mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-08 08:31:13 +00:00
Merge branch 'bubbles'
This commit is contained in:
commit
91be786a22
@ -5291,3 +5291,8 @@ Any member of this group will be able to see messages in the channel.";
|
||||
"Forward.ErrorPublicQuizDisabledInChannels" = "Sorry, public polls can’t be forwarded to channels.";
|
||||
|
||||
"Map.PlacesInThisArea" = "Places In This Area";
|
||||
|
||||
"Appearance.BubbleCornersSetting" = "Message Corners";
|
||||
"Appearance.BubbleCorners.Title" = "Message Corners";
|
||||
"Appearance.BubbleCorners.AdjustAdjacent" = "Adjust Adjacent Corners";
|
||||
"Appearance.BubbleCorners.Apply" = "Set";
|
||||
|
@ -446,8 +446,8 @@ public protocol SharedAccountContext: class {
|
||||
func makeComposeController(context: AccountContext) -> ViewController
|
||||
func makeChatListController(context: AccountContext, groupId: PeerGroupId, controlsHistoryPreload: Bool, hideNetworkActivityStatus: Bool, previewing: Bool, enableDebugActions: Bool) -> ChatListController
|
||||
func makeChatController(context: AccountContext, chatLocation: ChatLocation, subject: ChatControllerSubject?, botStart: ChatControllerInitialBotStart?, mode: ChatControllerPresentationMode) -> ChatController
|
||||
func makeChatMessagePreviewItem(context: AccountContext, message: Message, theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, dateTimeFormat: PresentationDateTimeFormat, nameOrder: PresentationPersonNameOrder, forcedResourceStatus: FileMediaResourceStatus?, tapMessage: ((Message) -> Void)?, clickThroughMessage: (() -> Void)?) -> ListViewItem
|
||||
func makeChatMessageDateHeaderItem(context: AccountContext, timestamp: Int32, theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, dateTimeFormat: PresentationDateTimeFormat, nameOrder: PresentationPersonNameOrder) -> ListViewItemHeader
|
||||
func makeChatMessagePreviewItem(context: AccountContext, message: Message, theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, dateTimeFormat: PresentationDateTimeFormat, nameOrder: PresentationPersonNameOrder, forcedResourceStatus: FileMediaResourceStatus?, tapMessage: ((Message) -> Void)?, clickThroughMessage: (() -> Void)?) -> ListViewItem
|
||||
func makeChatMessageDateHeaderItem(context: AccountContext, timestamp: Int32, theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, dateTimeFormat: PresentationDateTimeFormat, nameOrder: PresentationPersonNameOrder) -> ListViewItemHeader
|
||||
func makePeerSharedMediaController(context: AccountContext, peerId: PeerId) -> ViewController?
|
||||
func makeContactSelectionController(_ params: ContactSelectionControllerParams) -> ContactSelectionController
|
||||
func makeContactMultiselectionController(_ params: ContactMultiselectionControllerParams) -> ContactMultiselectionController
|
||||
|
@ -109,7 +109,6 @@ private func ==(lhs: Tail, rhs: Tail) -> Bool {
|
||||
}
|
||||
|
||||
private var cachedCorners = Atomic<[Corner: DrawingContext]>(value: [:])
|
||||
private var cachedTails = Atomic<[Tail: DrawingContext]>(value: [:])
|
||||
|
||||
private func cornerContext(_ corner: Corner) -> DrawingContext {
|
||||
let cached: DrawingContext? = cachedCorners.with {
|
||||
@ -148,62 +147,6 @@ private func cornerContext(_ corner: Corner) -> DrawingContext {
|
||||
}
|
||||
}
|
||||
|
||||
private func tailContext(_ tail: Tail) -> DrawingContext {
|
||||
let cached: DrawingContext? = cachedTails.with {
|
||||
return $0[tail]
|
||||
}
|
||||
|
||||
if let cached = cached {
|
||||
return cached
|
||||
} else {
|
||||
let context = DrawingContext(size: CGSize(width: CGFloat(tail.radius) + 3.0, height: CGFloat(tail.radius)), clear: true)
|
||||
|
||||
context.withContext { c in
|
||||
c.setBlendMode(.copy)
|
||||
c.setFillColor(UIColor.black.cgColor)
|
||||
let rect: CGRect
|
||||
switch tail {
|
||||
case let .BottomLeft(radius):
|
||||
rect = CGRect(origin: CGPoint(x: 3.0, y: -CGFloat(radius)), size: CGSize(width: CGFloat(radius << 1), height: CGFloat(radius << 1)))
|
||||
|
||||
c.move(to: CGPoint(x: 3.0, y: 1.0))
|
||||
c.addLine(to: CGPoint(x: 3.0, y: 11.0))
|
||||
c.addLine(to: CGPoint(x: 2.3, y: 13.0))
|
||||
c.addLine(to: CGPoint(x: 0.0, y: 16.6))
|
||||
c.addLine(to: CGPoint(x: 4.5, y: 15.5))
|
||||
c.addLine(to: CGPoint(x: 6.5, y: 14.3))
|
||||
c.addLine(to: CGPoint(x: 9.0, y: 12.5))
|
||||
c.closePath()
|
||||
c.fillPath()
|
||||
case let .BottomRight(radius):
|
||||
rect = CGRect(origin: CGPoint(x: 3.0, y: -CGFloat(radius)), size: CGSize(width: CGFloat(radius << 1), height: CGFloat(radius << 1)))
|
||||
|
||||
c.translateBy(x: context.size.width / 2.0, y: context.size.height / 2.0)
|
||||
c.scaleBy(x: -1.0, y: 1.0)
|
||||
c.translateBy(x: -context.size.width / 2.0, y: -context.size.height / 2.0)
|
||||
|
||||
c.move(to: CGPoint(x: 3.0, y: 1.0))
|
||||
c.addLine(to: CGPoint(x: 3.0, y: 11.0))
|
||||
c.addLine(to: CGPoint(x: 2.3, y: 13.0))
|
||||
c.addLine(to: CGPoint(x: 0.0, y: 16.6))
|
||||
c.addLine(to: CGPoint(x: 4.5, y: 15.5))
|
||||
c.addLine(to: CGPoint(x: 6.5, y: 14.3))
|
||||
c.addLine(to: CGPoint(x: 9.0, y: 12.5))
|
||||
c.closePath()
|
||||
c.fillPath()
|
||||
}
|
||||
c.fillEllipse(in: rect)
|
||||
}
|
||||
|
||||
let _ = cachedTails.modify { current in
|
||||
var current = current
|
||||
current[tail] = context
|
||||
return current
|
||||
}
|
||||
return context
|
||||
}
|
||||
}
|
||||
|
||||
public func addCorners(_ context: DrawingContext, arguments: TransformImageArguments) {
|
||||
let corners = arguments.corners
|
||||
let drawingRect = arguments.drawingRect
|
||||
@ -223,23 +166,24 @@ public func addCorners(_ context: DrawingContext, arguments: TransformImageArgum
|
||||
let corner = cornerContext(.BottomLeft(Int(radius)))
|
||||
context.blt(corner, at: CGPoint(x: drawingRect.minX, y: drawingRect.maxY - radius))
|
||||
}
|
||||
case let .Tail(radius, enabled):
|
||||
case let .Tail(radius, image):
|
||||
if radius > CGFloat.ulpOfOne {
|
||||
if enabled {
|
||||
let tail = tailContext(.BottomLeft(Int(radius)))
|
||||
let color = context.colorAt(CGPoint(x: drawingRect.minX, y: drawingRect.maxY - 1.0))
|
||||
context.withContext { c in
|
||||
c.clear(CGRect(x: drawingRect.minX - 3.0, y: 0.0, width: 3.0, height: drawingRect.maxY - 6.0))
|
||||
c.setFillColor(color.cgColor)
|
||||
c.fill(CGRect(x: 0.0, y: drawingRect.maxY - 6.0, width: 3.0, height: 6.0))
|
||||
}
|
||||
context.blt(tail, at: CGPoint(x: drawingRect.minX - 3.0, y: drawingRect.maxY - radius))
|
||||
} else {
|
||||
let corner = cornerContext(.BottomLeft(Int(radius)))
|
||||
context.blt(corner, at: CGPoint(x: drawingRect.minX, y: drawingRect.maxY - radius))
|
||||
let color = context.colorAt(CGPoint(x: drawingRect.minX, y: drawingRect.maxY - 1.0))
|
||||
context.withContext { c in
|
||||
c.clear(CGRect(x: drawingRect.minX - 4.0, y: 0.0, width: 4.0, height: drawingRect.maxY - 6.0))
|
||||
c.setFillColor(color.cgColor)
|
||||
c.fill(CGRect(x: 0.0, y: drawingRect.maxY - 6.0, width: 4.0, height: 6.0))
|
||||
c.setBlendMode(.destinationIn)
|
||||
let cornerRect = CGRect(origin: CGPoint(x: drawingRect.minX - 6.0, y: drawingRect.maxY - image.size.height), size: image.size)
|
||||
c.translateBy(x: cornerRect.midX, y: cornerRect.midY)
|
||||
c.scaleBy(x: 1.0, y: -1.0)
|
||||
c.translateBy(x: -cornerRect.midX, y: -cornerRect.midY)
|
||||
c.draw(image.cgImage!, in: cornerRect)
|
||||
c.translateBy(x: cornerRect.midX, y: cornerRect.midY)
|
||||
c.scaleBy(x: 1.0, y: -1.0)
|
||||
c.translateBy(x: -cornerRect.midX, y: -cornerRect.midY)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
switch corners.bottomRight {
|
||||
@ -248,20 +192,22 @@ public func addCorners(_ context: DrawingContext, arguments: TransformImageArgum
|
||||
let corner = cornerContext(.BottomRight(Int(radius)))
|
||||
context.blt(corner, at: CGPoint(x: drawingRect.maxX - radius, y: drawingRect.maxY - radius))
|
||||
}
|
||||
case let .Tail(radius, enabled):
|
||||
case let .Tail(radius, image):
|
||||
if radius > CGFloat.ulpOfOne {
|
||||
if enabled {
|
||||
let tail = tailContext(.BottomRight(Int(radius)))
|
||||
let color = context.colorAt(CGPoint(x: drawingRect.maxX - 1.0, y: drawingRect.maxY - 1.0))
|
||||
context.withContext { c in
|
||||
c.clear(CGRect(x: drawingRect.maxX, y: 0.0, width: 3.0, height: drawingRect.maxY - 6.0))
|
||||
c.setFillColor(color.cgColor)
|
||||
c.fill(CGRect(x: drawingRect.maxX, y: drawingRect.maxY - 6.0, width: 3.0, height: 6.0))
|
||||
}
|
||||
context.blt(tail, at: CGPoint(x: drawingRect.maxX - radius, y: drawingRect.maxY - radius))
|
||||
} else {
|
||||
let corner = cornerContext(.BottomRight(Int(radius)))
|
||||
context.blt(corner, at: CGPoint(x: drawingRect.maxX - radius, y: drawingRect.maxY - radius))
|
||||
let color = context.colorAt(CGPoint(x: drawingRect.maxX - 1.0, y: drawingRect.maxY - 1.0))
|
||||
context.withContext { c in
|
||||
c.clear(CGRect(x: drawingRect.maxX, y: 0.0, width: 4.0, height: drawingRect.maxY - image.size.height))
|
||||
c.setFillColor(color.cgColor)
|
||||
c.fill(CGRect(x: drawingRect.maxX, y: drawingRect.maxY - 6.0, width: 4.0, height: 6.0))
|
||||
c.setBlendMode(.destinationIn)
|
||||
let cornerRect = CGRect(origin: CGPoint(x: drawingRect.maxX - image.size.width + 6.0, y: drawingRect.maxY - image.size.height), size: image.size)
|
||||
c.translateBy(x: cornerRect.midX, y: cornerRect.midY)
|
||||
c.scaleBy(x: 1.0, y: -1.0)
|
||||
c.translateBy(x: -cornerRect.midX, y: -cornerRect.midY)
|
||||
c.draw(image.cgImage!, in: cornerRect)
|
||||
c.translateBy(x: cornerRect.midX, y: cornerRect.midY)
|
||||
c.scaleBy(x: 1.0, y: -1.0)
|
||||
c.translateBy(x: -cornerRect.midX, y: -cornerRect.midY)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,12 +8,12 @@ private let dispatcher = displayLinkDispatcher
|
||||
|
||||
public enum ImageCorner: Equatable {
|
||||
case Corner(CGFloat)
|
||||
case Tail(CGFloat, Bool)
|
||||
case Tail(CGFloat, UIImage)
|
||||
|
||||
public var extendedInsets: CGSize {
|
||||
switch self {
|
||||
case .Tail:
|
||||
return CGSize(width: 3.0, height: 0.0)
|
||||
return CGSize(width: 4.0, height: 0.0)
|
||||
default:
|
||||
return CGSize()
|
||||
}
|
||||
@ -36,15 +36,6 @@ public enum ImageCorner: Equatable {
|
||||
return radius
|
||||
}
|
||||
}
|
||||
|
||||
public func scaledBy(_ scale: CGFloat) -> ImageCorner {
|
||||
switch self {
|
||||
case let .Corner(radius):
|
||||
return .Corner(radius * scale)
|
||||
case let .Tail(radius, enabled):
|
||||
return .Tail(radius * scale, enabled)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func ==(lhs: ImageCorner, rhs: ImageCorner) -> Bool {
|
||||
@ -56,8 +47,8 @@ public func ==(lhs: ImageCorner, rhs: ImageCorner) -> Bool {
|
||||
default:
|
||||
return false
|
||||
}
|
||||
case let .Tail(lhsRadius, lhsEnabled):
|
||||
if case let .Tail(rhsRadius, rhsEnabled) = rhs, lhsRadius.isEqual(to: rhsRadius), lhsEnabled == rhsEnabled {
|
||||
case let .Tail(lhsRadius, lhsImage):
|
||||
if case let .Tail(rhsRadius, rhsImage) = rhs, lhsRadius.isEqual(to: rhsRadius), lhsImage === rhsImage {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
@ -124,10 +115,6 @@ public struct ImageCorners: Equatable {
|
||||
public func withRemovedTails() -> ImageCorners {
|
||||
return ImageCorners(topLeft: self.topLeft.withoutTail, topRight: self.topRight.withoutTail, bottomLeft: self.bottomLeft.withoutTail, bottomRight: self.bottomRight.withoutTail)
|
||||
}
|
||||
|
||||
public func scaledBy(_ scale: CGFloat) -> ImageCorners {
|
||||
return ImageCorners(topLeft: self.topLeft.scaledBy(scale), topRight: self.topRight.scaledBy(scale), bottomLeft: self.bottomLeft.scaledBy(scale), bottomRight: self.bottomRight.scaledBy(scale))
|
||||
}
|
||||
}
|
||||
|
||||
public func ==(lhs: ImageCorners, rhs: ImageCorners) -> Bool {
|
||||
|
@ -0,0 +1,578 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
import Postbox
|
||||
import SwiftSignalKit
|
||||
import AsyncDisplayKit
|
||||
import TelegramCore
|
||||
import SyncCore
|
||||
import TelegramPresentationData
|
||||
import TelegramUIPreferences
|
||||
import AccountContext
|
||||
import ChatListUI
|
||||
import WallpaperResources
|
||||
import LegacyComponents
|
||||
import ItemListUI
|
||||
|
||||
private func generateMaskImage(color: UIColor) -> UIImage? {
|
||||
return generateImage(CGSize(width: 1.0, height: 80.0), opaque: false, rotatedContext: { size, context in
|
||||
let bounds = CGRect(origin: CGPoint(), size: size)
|
||||
context.clear(bounds)
|
||||
|
||||
let gradientColors = [color.withAlphaComponent(0.0).cgColor, color.cgColor, color.cgColor] as CFArray
|
||||
|
||||
var locations: [CGFloat] = [0.0, 0.75, 1.0]
|
||||
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
||||
let gradient = CGGradient(colorsSpace: colorSpace, colors: gradientColors, locations: &locations)!
|
||||
|
||||
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: 0.0, y: 80.0), options: CGGradientDrawingOptions())
|
||||
})
|
||||
}
|
||||
|
||||
private final class BubbleSettingsControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
private let context: AccountContext
|
||||
private var presentationThemeSettings: PresentationThemeSettings
|
||||
private var presentationData: PresentationData
|
||||
|
||||
private let referenceTimestamp: Int32
|
||||
|
||||
private let scrollNode: ASScrollNode
|
||||
|
||||
private let maskNode: ASImageNode
|
||||
private let chatBackgroundNode: WallpaperBackgroundNode
|
||||
private let messagesContainerNode: ASDisplayNode
|
||||
private var dateHeaderNode: ListViewItemHeaderNode?
|
||||
private var messageNodes: [ListViewItemNode]?
|
||||
private let toolbarNode: BubbleSettingsToolbarNode
|
||||
|
||||
private var validLayout: (ContainerViewLayout, CGFloat)?
|
||||
|
||||
init(context: AccountContext, presentationThemeSettings: PresentationThemeSettings, dismiss: @escaping () -> Void, apply: @escaping (PresentationChatBubbleSettings) -> Void) {
|
||||
self.context = context
|
||||
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
self.presentationThemeSettings = presentationThemeSettings
|
||||
|
||||
let calendar = Calendar(identifier: .gregorian)
|
||||
var components = calendar.dateComponents(Set([.era, .year, .month, .day, .hour, .minute, .second]), from: Date())
|
||||
components.hour = 13
|
||||
components.minute = 0
|
||||
components.second = 0
|
||||
self.referenceTimestamp = Int32(calendar.date(from: components)?.timeIntervalSince1970 ?? 0.0)
|
||||
|
||||
self.scrollNode = ASScrollNode()
|
||||
|
||||
self.chatBackgroundNode = WallpaperBackgroundNode()
|
||||
self.chatBackgroundNode.displaysAsynchronously = false
|
||||
|
||||
self.messagesContainerNode = ASDisplayNode()
|
||||
self.messagesContainerNode.clipsToBounds = true
|
||||
self.messagesContainerNode.transform = CATransform3DMakeScale(1.0, -1.0, 1.0)
|
||||
|
||||
self.chatBackgroundNode.image = chatControllerBackgroundImage(theme: self.presentationData.theme, wallpaper: self.presentationData.chatWallpaper, mediaBox: context.sharedContext.accountManager.mediaBox, knockoutMode: false)
|
||||
self.chatBackgroundNode.motionEnabled = self.presentationData.chatWallpaper.settings?.motion ?? false
|
||||
if case .gradient = self.presentationData.chatWallpaper {
|
||||
self.chatBackgroundNode.imageContentMode = .scaleToFill
|
||||
}
|
||||
|
||||
self.toolbarNode = BubbleSettingsToolbarNode(presentationThemeSettings: self.presentationThemeSettings, presentationData: self.presentationData)
|
||||
|
||||
self.maskNode = ASImageNode()
|
||||
self.maskNode.displaysAsynchronously = false
|
||||
self.maskNode.displayWithoutProcessing = true
|
||||
self.maskNode.contentMode = .scaleToFill
|
||||
|
||||
|
||||
super.init()
|
||||
|
||||
self.setViewBlock({
|
||||
return UITracingLayerView()
|
||||
})
|
||||
|
||||
self.backgroundColor = self.presentationData.theme.list.plainBackgroundColor
|
||||
|
||||
self.maskNode.image = generateMaskImage(color: self.presentationData.theme.chatList.backgroundColor)
|
||||
|
||||
self.addSubnode(self.scrollNode)
|
||||
self.addSubnode(self.toolbarNode)
|
||||
|
||||
self.scrollNode.addSubnode(self.chatBackgroundNode)
|
||||
self.scrollNode.addSubnode(self.messagesContainerNode)
|
||||
|
||||
self.toolbarNode.cancel = {
|
||||
dismiss()
|
||||
}
|
||||
var dismissed = false
|
||||
self.toolbarNode.done = { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if !dismissed {
|
||||
dismissed = true
|
||||
apply(strongSelf.presentationThemeSettings.chatBubbleSettings)
|
||||
}
|
||||
}
|
||||
self.toolbarNode.updateMergeBubbleCorners = { [weak self] value in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.presentationThemeSettings.chatBubbleSettings.mergeBubbleCorners = value
|
||||
strongSelf.updatePresentationThemeSettings(strongSelf.presentationThemeSettings)
|
||||
}
|
||||
self.toolbarNode.updateCornerRadius = { [weak self] value in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.presentationThemeSettings.chatBubbleSettings.mainRadius = Int32(value)
|
||||
strongSelf.presentationThemeSettings.chatBubbleSettings.auxiliaryRadius = Int32(value / 2)
|
||||
strongSelf.updatePresentationThemeSettings(strongSelf.presentationThemeSettings)
|
||||
}
|
||||
}
|
||||
|
||||
override func didLoad() {
|
||||
super.didLoad()
|
||||
|
||||
self.scrollNode.view.disablesInteractiveTransitionGestureRecognizer = true
|
||||
self.scrollNode.view.showsHorizontalScrollIndicator = false
|
||||
self.scrollNode.view.isPagingEnabled = true
|
||||
self.scrollNode.view.delegate = self
|
||||
self.scrollNode.view.alwaysBounceHorizontal = false
|
||||
}
|
||||
|
||||
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||
}
|
||||
|
||||
func animateIn(completion: (() -> Void)? = nil) {
|
||||
if let (layout, _) = self.validLayout, case .compact = layout.metrics.widthClass {
|
||||
self.layer.animatePosition(from: CGPoint(x: self.layer.position.x, y: self.layer.position.y + self.layer.bounds.size.height), to: self.layer.position, duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring)
|
||||
}
|
||||
}
|
||||
|
||||
func animateOut(completion: (() -> Void)? = nil) {
|
||||
if let (layout, _) = self.validLayout, case .compact = layout.metrics.widthClass {
|
||||
self.layer.animatePosition(from: self.layer.position, to: CGPoint(x: self.layer.position.x, y: self.layer.position.y + self.layer.bounds.size.height), duration: 0.2, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, removeOnCompletion: false, completion: { _ in
|
||||
completion?()
|
||||
})
|
||||
} else {
|
||||
completion?()
|
||||
}
|
||||
}
|
||||
|
||||
private func updateMessagesLayout(layout: ContainerViewLayout, bottomInset: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
let headerItem = self.context.sharedContext.makeChatMessageDateHeaderItem(context: self.context, timestamp: self.referenceTimestamp, theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder)
|
||||
|
||||
var items: [ListViewItem] = []
|
||||
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: 1)
|
||||
let otherPeerId = self.context.account.peerId
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var messages = SimpleDictionary<MessageId, Message>()
|
||||
peers[peerId] = TelegramUser(id: peerId, accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_Chat_2_ReplyName, lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])
|
||||
peers[otherPeerId] = TelegramUser(id: otherPeerId, accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_Chat_2_ReplyName, lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])
|
||||
|
||||
let replyMessageId = MessageId(peerId: peerId, namespace: 0, id: 3)
|
||||
messages[replyMessageId] = Message(stableId: 3, stableVersion: 0, id: replyMessageId, globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66000, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_1_Text, attributes: [], media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
|
||||
let message1 = Message(stableId: 4, stableVersion: 0, id: MessageId(peerId: otherPeerId, namespace: 0, id: 4), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66003, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_3_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])
|
||||
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, message: message1, theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil))
|
||||
|
||||
let message2 = Message(stableId: 3, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 3), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66002, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_2_Text, attributes: [ReplyMessageAttribute(messageId: replyMessageId)], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])
|
||||
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, message: message2, theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil))
|
||||
|
||||
let waveformBase64 = "DAAOAAkACQAGAAwADwAMABAADQAPABsAGAALAA0AGAAfABoAHgATABgAGQAYABQADAAVABEAHwANAA0ACQAWABkACQAOAAwACQAfAAAAGQAVAAAAEwATAAAACAAfAAAAHAAAABwAHwAAABcAGQAAABQADgAAABQAHwAAAB8AHwAAAAwADwAAAB8AEwAAABoAFwAAAB8AFAAAAAAAHwAAAAAAHgAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAAAA="
|
||||
let voiceAttributes: [TelegramMediaFileAttribute] = [.Audio(isVoice: true, duration: 23, title: nil, performer: nil, waveform: MemoryBuffer(data: Data(base64Encoded: waveformBase64)!))]
|
||||
let voiceMedia = TelegramMediaFile(fileId: MediaId(namespace: 0, id: 0), partialReference: nil, resource: LocalFileMediaResource(fileId: 0), previewRepresentations: [], immediateThumbnailData: nil, mimeType: "audio/ogg", size: 0, attributes: voiceAttributes)
|
||||
|
||||
let message3 = Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66001, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: "", attributes: [], media: [voiceMedia], peers: peers, associatedMessages: messages, associatedMessageIds: [])
|
||||
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, message: message3, theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: FileMediaResourceStatus(mediaStatus: .playbackStatus(.paused), fetchStatus: .Local), tapMessage: nil, clickThroughMessage: nil))
|
||||
|
||||
let message4 = Message(stableId: 2, stableVersion: 0, id: MessageId(peerId: otherPeerId, namespace: 0, id: 2), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66001, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_1_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])
|
||||
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, message: message4, theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil))
|
||||
|
||||
let width: CGFloat
|
||||
if case .regular = layout.metrics.widthClass {
|
||||
width = layout.size.width / 2.0
|
||||
} else {
|
||||
width = layout.size.width
|
||||
}
|
||||
|
||||
let params = ListViewItemLayoutParams(width: width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, availableHeight: layout.size.height)
|
||||
if let messageNodes = self.messageNodes {
|
||||
for i in 0 ..< items.count {
|
||||
let itemNode = messageNodes[i]
|
||||
items[i].updateNode(async: { $0() }, node: {
|
||||
return itemNode
|
||||
}, params: params, previousItem: i == 0 ? nil : items[i - 1], nextItem: i == (items.count - 1) ? nil : items[i + 1], animation: .None, completion: { (layout, apply) in
|
||||
let nodeFrame = CGRect(origin: itemNode.frame.origin, size: CGSize(width: width, height: layout.size.height))
|
||||
|
||||
itemNode.contentSize = layout.contentSize
|
||||
itemNode.insets = layout.insets
|
||||
itemNode.frame = nodeFrame
|
||||
itemNode.isUserInteractionEnabled = false
|
||||
|
||||
apply(ListViewItemApply(isOnScreen: true))
|
||||
})
|
||||
}
|
||||
} else {
|
||||
var messageNodes: [ListViewItemNode] = []
|
||||
for i in 0 ..< items.count {
|
||||
var itemNode: ListViewItemNode?
|
||||
items[i].nodeConfiguredForParams(async: { $0() }, params: params, synchronousLoads: false, previousItem: i == 0 ? nil : items[i - 1], nextItem: i == (items.count - 1) ? nil : items[i + 1], completion: { node, apply in
|
||||
itemNode = node
|
||||
apply().1(ListViewItemApply(isOnScreen: true))
|
||||
})
|
||||
itemNode!.subnodeTransform = CATransform3DMakeScale(-1.0, 1.0, 1.0)
|
||||
itemNode!.isUserInteractionEnabled = false
|
||||
messageNodes.append(itemNode!)
|
||||
self.messagesContainerNode.addSubnode(itemNode!)
|
||||
}
|
||||
self.messageNodes = messageNodes
|
||||
}
|
||||
|
||||
var bottomOffset: CGFloat = 9.0 + bottomInset
|
||||
if let messageNodes = self.messageNodes {
|
||||
for itemNode in messageNodes {
|
||||
transition.updateFrame(node: itemNode, frame: CGRect(origin: CGPoint(x: 0.0, y: bottomOffset), size: itemNode.frame.size))
|
||||
bottomOffset += itemNode.frame.height
|
||||
itemNode.updateFrame(itemNode.frame, within: layout.size)
|
||||
}
|
||||
}
|
||||
|
||||
let dateHeaderNode: ListViewItemHeaderNode
|
||||
if let currentDateHeaderNode = self.dateHeaderNode {
|
||||
dateHeaderNode = currentDateHeaderNode
|
||||
headerItem.updateNode(dateHeaderNode, previous: nil, next: headerItem)
|
||||
} else {
|
||||
dateHeaderNode = headerItem.node()
|
||||
dateHeaderNode.subnodeTransform = CATransform3DMakeScale(-1.0, 1.0, 1.0)
|
||||
self.messagesContainerNode.addSubnode(dateHeaderNode)
|
||||
self.dateHeaderNode = dateHeaderNode
|
||||
}
|
||||
|
||||
transition.updateFrame(node: dateHeaderNode, frame: CGRect(origin: CGPoint(x: 0.0, y: bottomOffset), size: CGSize(width: layout.size.width, height: headerItem.height)))
|
||||
dateHeaderNode.updateLayout(size: self.messagesContainerNode.frame.size, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right)
|
||||
}
|
||||
|
||||
func updatePresentationThemeSettings(_ presentationThemeSettings: PresentationThemeSettings) {
|
||||
let chatBubbleCorners = PresentationChatBubbleCorners(mainRadius: CGFloat(presentationThemeSettings.chatBubbleSettings.mainRadius), auxiliaryRadius: CGFloat(presentationThemeSettings.chatBubbleSettings.auxiliaryRadius), mergeBubbleCorners: presentationThemeSettings.chatBubbleSettings.mergeBubbleCorners)
|
||||
|
||||
self.presentationData = self.presentationData.withChatBubbleCorners(chatBubbleCorners)
|
||||
self.toolbarNode.updatePresentationData(presentationData: self.presentationData)
|
||||
self.toolbarNode.updatePresentationThemeSettings(presentationThemeSettings: self.presentationThemeSettings)
|
||||
if let (layout, navigationBarHeight) = self.validLayout {
|
||||
self.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate)
|
||||
self.recursivelyEnsureDisplaySynchronously(true)
|
||||
}
|
||||
}
|
||||
|
||||
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayout = (layout, navigationBarHeight)
|
||||
|
||||
let bounds = CGRect(origin: CGPoint(), size: layout.size)
|
||||
self.scrollNode.frame = bounds
|
||||
|
||||
let toolbarHeight = self.toolbarNode.updateLayout(width: layout.size.width, bottomInset: layout.intrinsicInsets.bottom, layout: layout, transition: transition)
|
||||
|
||||
var chatFrame = CGRect(x: 0.0, y: 0.0, width: bounds.width, height: bounds.height)
|
||||
|
||||
let bottomInset: CGFloat
|
||||
chatFrame = CGRect(x: 0.0, y: 0.0, width: bounds.width, height: bounds.height)
|
||||
self.scrollNode.view.contentSize = CGSize(width: bounds.width, height: bounds.height)
|
||||
|
||||
bottomInset = 37.0
|
||||
|
||||
self.chatBackgroundNode.frame = chatFrame
|
||||
self.chatBackgroundNode.updateLayout(size: chatFrame.size, transition: transition)
|
||||
self.messagesContainerNode.frame = chatFrame
|
||||
|
||||
transition.updateFrame(node: self.toolbarNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - toolbarHeight), size: CGSize(width: layout.size.width, height: toolbarHeight + layout.intrinsicInsets.bottom)))
|
||||
|
||||
self.updateMessagesLayout(layout: layout, bottomInset: toolbarHeight + bottomInset, transition: transition)
|
||||
|
||||
transition.updateFrame(node: self.maskNode, frame: CGRect(x: 0.0, y: layout.size.height - toolbarHeight - 80.0, width: bounds.width, height: 80.0))
|
||||
}
|
||||
}
|
||||
|
||||
final class BubbleSettingsController: ViewController {
|
||||
private let context: AccountContext
|
||||
|
||||
private var controllerNode: BubbleSettingsControllerNode {
|
||||
return self.displayNode as! BubbleSettingsControllerNode
|
||||
}
|
||||
|
||||
private var didPlayPresentationAnimation = false
|
||||
|
||||
private var presentationData: PresentationData
|
||||
private var presentationDataDisposable: Disposable?
|
||||
|
||||
private var presentationThemeSettings: PresentationThemeSettings
|
||||
private var presentationThemeSettingsDisposable: Disposable?
|
||||
|
||||
private var disposable: Disposable?
|
||||
private var applyDisposable = MetaDisposable()
|
||||
|
||||
public init(context: AccountContext, presentationThemeSettings: PresentationThemeSettings) {
|
||||
self.context = context
|
||||
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
self.presentationThemeSettings = presentationThemeSettings
|
||||
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationTheme: self.presentationData.theme, presentationStrings: self.presentationData.strings))
|
||||
|
||||
self.blocksBackgroundWhenInOverlay = true
|
||||
self.navigationPresentation = .modal
|
||||
|
||||
self.navigationItem.title = self.presentationData.strings.Appearance_BubbleCorners_Title
|
||||
self.navigationItem.leftBarButtonItem = UIBarButtonItem(customView: UIView())
|
||||
|
||||
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
||||
self.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait)
|
||||
|
||||
self.presentationDataDisposable = (context.sharedContext.presentationData
|
||||
|> deliverOnMainQueue).start(next: { [weak self] presentationData in
|
||||
if let strongSelf = self {
|
||||
strongSelf.presentationData = presentationData
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
required public init(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.presentationDataDisposable?.dispose()
|
||||
self.presentationThemeSettingsDisposable?.dispose()
|
||||
self.disposable?.dispose()
|
||||
self.applyDisposable.dispose()
|
||||
}
|
||||
|
||||
override public func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
|
||||
if let presentationArguments = self.presentationArguments as? ViewControllerPresentationArguments, !self.didPlayPresentationAnimation {
|
||||
self.didPlayPresentationAnimation = true
|
||||
if case .modalSheet = presentationArguments.presentationAnimation {
|
||||
self.controllerNode.animateIn()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override public func loadDisplayNode() {
|
||||
super.loadDisplayNode()
|
||||
|
||||
self.displayNode = BubbleSettingsControllerNode(context: self.context, presentationThemeSettings: self.presentationThemeSettings, dismiss: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.dismiss()
|
||||
}
|
||||
}, apply: { [weak self] chatBubbleSettings in
|
||||
if let strongSelf = self {
|
||||
strongSelf.apply(chatBubbleSettings: chatBubbleSettings)
|
||||
}
|
||||
})
|
||||
self.displayNodeDidLoad()
|
||||
}
|
||||
|
||||
private func apply(chatBubbleSettings: PresentationChatBubbleSettings) {
|
||||
let _ = (updatePresentationThemeSettingsInteractively(accountManager: self.context.sharedContext.accountManager, { current in
|
||||
var current = current
|
||||
current.chatBubbleSettings = chatBubbleSettings
|
||||
return current
|
||||
})
|
||||
|> deliverOnMainQueue).start(completed: { [weak self] in
|
||||
self?.dismiss()
|
||||
})
|
||||
}
|
||||
|
||||
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||
super.containerLayoutUpdated(layout, transition: transition)
|
||||
|
||||
self.controllerNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationHeight, transition: transition)
|
||||
}
|
||||
}
|
||||
|
||||
private enum TextSelectionCustomMode {
|
||||
case list
|
||||
case chat
|
||||
}
|
||||
|
||||
private final class BubbleSettingsToolbarNode: ASDisplayNode {
|
||||
private var presentationThemeSettings: PresentationThemeSettings
|
||||
private var presentationData: PresentationData
|
||||
|
||||
private let cancelButton = HighlightableButtonNode()
|
||||
private let doneButton = HighlightableButtonNode()
|
||||
private let separatorNode = ASDisplayNode()
|
||||
private let topSeparatorNode = ASDisplayNode()
|
||||
|
||||
private var switchItemNode: ItemListSwitchItemNode
|
||||
private var cornerRadiusItemNode: ThemeSettingsFontSizeItemNode
|
||||
|
||||
private(set) var customMode: TextSelectionCustomMode = .chat
|
||||
|
||||
var cancel: (() -> Void)?
|
||||
var done: (() -> Void)?
|
||||
|
||||
var updateMergeBubbleCorners: ((Bool) -> Void)?
|
||||
var updateCornerRadius: ((Int32) -> Void)?
|
||||
|
||||
init(presentationThemeSettings: PresentationThemeSettings, presentationData: PresentationData) {
|
||||
self.presentationThemeSettings = presentationThemeSettings
|
||||
self.presentationData = presentationData
|
||||
|
||||
self.switchItemNode = ItemListSwitchItemNode(type: .regular)
|
||||
self.cornerRadiusItemNode = ThemeSettingsFontSizeItemNode()
|
||||
|
||||
super.init()
|
||||
|
||||
self.addSubnode(self.switchItemNode)
|
||||
self.addSubnode(self.cornerRadiusItemNode)
|
||||
self.addSubnode(self.cancelButton)
|
||||
self.addSubnode(self.doneButton)
|
||||
self.addSubnode(self.separatorNode)
|
||||
self.addSubnode(self.topSeparatorNode)
|
||||
|
||||
self.updatePresentationData(presentationData: self.presentationData)
|
||||
|
||||
self.cancelButton.highligthedChanged = { [weak self] highlighted in
|
||||
if let strongSelf = self {
|
||||
if highlighted {
|
||||
strongSelf.cancelButton.backgroundColor = strongSelf.presentationData.theme.list.itemHighlightedBackgroundColor
|
||||
} else {
|
||||
UIView.animate(withDuration: 0.3, animations: {
|
||||
strongSelf.cancelButton.backgroundColor = .clear
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.doneButton.highligthedChanged = { [weak self] highlighted in
|
||||
if let strongSelf = self {
|
||||
if highlighted {
|
||||
strongSelf.doneButton.backgroundColor = strongSelf.presentationData.theme.list.itemHighlightedBackgroundColor
|
||||
} else {
|
||||
UIView.animate(withDuration: 0.3, animations: {
|
||||
strongSelf.doneButton.backgroundColor = .clear
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.cancelButton.addTarget(self, action: #selector(self.cancelPressed), forControlEvents: .touchUpInside)
|
||||
self.doneButton.addTarget(self, action: #selector(self.donePressed), forControlEvents: .touchUpInside)
|
||||
}
|
||||
|
||||
func setDoneEnabled(_ enabled: Bool) {
|
||||
self.doneButton.alpha = enabled ? 1.0 : 0.4
|
||||
self.doneButton.isUserInteractionEnabled = enabled
|
||||
}
|
||||
|
||||
func setCustomMode(_ customMode: TextSelectionCustomMode) {
|
||||
self.customMode = customMode
|
||||
}
|
||||
|
||||
func updatePresentationData(presentationData: PresentationData) {
|
||||
self.backgroundColor = presentationData.theme.rootController.tabBar.backgroundColor
|
||||
self.separatorNode.backgroundColor = presentationData.theme.rootController.tabBar.separatorColor
|
||||
self.topSeparatorNode.backgroundColor = presentationData.theme.rootController.tabBar.separatorColor
|
||||
|
||||
self.cancelButton.setTitle(presentationData.strings.Common_Cancel, with: Font.regular(17.0), with: presentationData.theme.list.itemPrimaryTextColor, for: [])
|
||||
self.doneButton.setTitle(presentationData.strings.Wallpaper_Set, with: Font.regular(17.0), with: presentationData.theme.list.itemPrimaryTextColor, for: [])
|
||||
}
|
||||
|
||||
func updatePresentationThemeSettings(presentationThemeSettings: PresentationThemeSettings) {
|
||||
self.presentationThemeSettings = presentationThemeSettings
|
||||
}
|
||||
|
||||
func updateLayout(width: CGFloat, bottomInset: CGFloat, layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) -> CGFloat {
|
||||
var contentHeight: CGFloat = 0.0
|
||||
|
||||
let switchItem = ItemListSwitchItem(presentationData: ItemListPresentationData(self.presentationData), title: self.presentationData.strings.Appearance_BubbleCorners_AdjustAdjacent, value: self.presentationThemeSettings.chatBubbleSettings.mergeBubbleCorners, disableLeadingInset: true, sectionId: 0, style: .blocks, updated: { [weak self] value in
|
||||
self?.updateMergeBubbleCorners?(value)
|
||||
})
|
||||
let fontSize: PresentationFontSize
|
||||
switch Int(self.presentationData.chatBubbleCorners.mainRadius) {
|
||||
case 4:
|
||||
fontSize = .extraSmall
|
||||
case 6:
|
||||
fontSize = .small
|
||||
case 8:
|
||||
fontSize = .medium
|
||||
case 10:
|
||||
fontSize = .regular
|
||||
case 12:
|
||||
fontSize = .large
|
||||
case 14:
|
||||
fontSize = .extraLarge
|
||||
case 16:
|
||||
fontSize = .extraLargeX2
|
||||
default:
|
||||
fontSize = .extraLargeX2
|
||||
}
|
||||
let cornerRadiusItem = ThemeSettingsFontSizeItem(theme: self.presentationData.theme, fontSize: fontSize, enabled: true, disableLeadingInset: false, displayIcons: false, force: false, sectionId: 0, updated: { [weak self] value in
|
||||
let numericValue: Int32
|
||||
switch value {
|
||||
case .extraSmall:
|
||||
numericValue = 4
|
||||
case .small:
|
||||
numericValue = 6
|
||||
case .medium:
|
||||
numericValue = 8
|
||||
case .regular:
|
||||
numericValue = 10
|
||||
case .large:
|
||||
numericValue = 12
|
||||
case .extraLarge:
|
||||
numericValue = 14
|
||||
case .extraLargeX2:
|
||||
numericValue = 16
|
||||
}
|
||||
self?.updateCornerRadius?(numericValue)
|
||||
})
|
||||
|
||||
/*switchItem.updateNode(async: { f in
|
||||
f()
|
||||
}, node: {
|
||||
return self.switchItemNode
|
||||
}, params: ListViewItemLayoutParams(width: width, leftInset: layout.intrinsicInsets.left, rightInset: layout.intrinsicInsets.right, availableHeight: 1000.0), previousItem: nil, nextItem: cornerRadiusItem, animation: .None, completion: { layout, apply in
|
||||
self.switchItemNode.contentSize = layout.contentSize
|
||||
self.switchItemNode.insets = layout.insets
|
||||
transition.updateFrame(node: self.switchItemNode, frame: CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: layout.contentSize))
|
||||
contentHeight += layout.contentSize.height
|
||||
apply(ListViewItemApply(isOnScreen: true))
|
||||
})*/
|
||||
|
||||
cornerRadiusItem.updateNode(async: { f in
|
||||
f()
|
||||
}, node: {
|
||||
return self.cornerRadiusItemNode
|
||||
}, params: ListViewItemLayoutParams(width: width, leftInset: layout.intrinsicInsets.left, rightInset: layout.intrinsicInsets.right, availableHeight: 1000.0), previousItem: switchItem, nextItem: nil, animation: .None, completion: { layout, apply in
|
||||
self.cornerRadiusItemNode.contentSize = layout.contentSize
|
||||
self.cornerRadiusItemNode.insets = layout.insets
|
||||
transition.updateFrame(node: self.cornerRadiusItemNode, frame: CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: layout.contentSize))
|
||||
contentHeight += layout.contentSize.height
|
||||
apply(ListViewItemApply(isOnScreen: true))
|
||||
})
|
||||
|
||||
self.cancelButton.frame = CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: floor(width / 2.0), height: 49.0))
|
||||
self.doneButton.frame = CGRect(origin: CGPoint(x: floor(width / 2.0), y: contentHeight), size: CGSize(width: width - floor(width / 2.0), height: 49.0))
|
||||
|
||||
contentHeight += 49.0
|
||||
|
||||
self.topSeparatorNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: width, height: UIScreenPixel))
|
||||
|
||||
let resultHeight = contentHeight + bottomInset
|
||||
|
||||
self.separatorNode.frame = CGRect(origin: CGPoint(x: floor(width / 2.0), y: self.cancelButton.frame.minY), size: CGSize(width: UIScreenPixel, height: resultHeight - self.cancelButton.frame.minY))
|
||||
|
||||
return resultHeight
|
||||
}
|
||||
|
||||
@objc func cancelPressed() {
|
||||
self.cancel?()
|
||||
}
|
||||
|
||||
@objc func donePressed() {
|
||||
self.doneButton.isUserInteractionEnabled = false
|
||||
self.done?()
|
||||
}
|
||||
}
|
@ -18,6 +18,7 @@ class ForwardPrivacyChatPreviewItem: ListViewItem, ItemListItem {
|
||||
let strings: PresentationStrings
|
||||
let sectionId: ItemListSectionId
|
||||
let fontSize: PresentationFontSize
|
||||
let chatBubbleCorners: PresentationChatBubbleCorners
|
||||
let wallpaper: TelegramWallpaper
|
||||
let dateTimeFormat: PresentationDateTimeFormat
|
||||
let nameDisplayOrder: PresentationPersonNameOrder
|
||||
@ -25,12 +26,13 @@ class ForwardPrivacyChatPreviewItem: ListViewItem, ItemListItem {
|
||||
let linkEnabled: Bool
|
||||
let tooltipText: String
|
||||
|
||||
init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, sectionId: ItemListSectionId, fontSize: PresentationFontSize, wallpaper: TelegramWallpaper, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, peerName: String, linkEnabled: Bool, tooltipText: String) {
|
||||
init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, sectionId: ItemListSectionId, fontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, wallpaper: TelegramWallpaper, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, peerName: String, linkEnabled: Bool, tooltipText: String) {
|
||||
self.context = context
|
||||
self.theme = theme
|
||||
self.strings = strings
|
||||
self.sectionId = sectionId
|
||||
self.fontSize = fontSize
|
||||
self.chatBubbleCorners = chatBubbleCorners
|
||||
self.wallpaper = wallpaper
|
||||
self.dateTimeFormat = dateTimeFormat
|
||||
self.nameDisplayOrder = nameDisplayOrder
|
||||
@ -157,7 +159,7 @@ class ForwardPrivacyChatPreviewItemNode: ListViewItemNode {
|
||||
|
||||
let forwardInfo = MessageForwardInfo(author: item.linkEnabled ? peers[peerId] : nil, source: nil, sourceMessageId: nil, date: 0, authorSignature: item.linkEnabled ? nil : item.peerName)
|
||||
|
||||
let messageItem = item.context.sharedContext.makeChatMessagePreviewItem(context: item.context, message: Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: forwardInfo, author: nil, text: item.strings.Privacy_Forwards_PreviewMessageText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), theme: item.theme, strings: item.strings, wallpaper: item.wallpaper, fontSize: item.fontSize, dateTimeFormat: item.dateTimeFormat, nameOrder: item.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil)
|
||||
let messageItem = item.context.sharedContext.makeChatMessagePreviewItem(context: item.context, message: Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: forwardInfo, author: nil, text: item.strings.Privacy_Forwards_PreviewMessageText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), theme: item.theme, strings: item.strings, wallpaper: item.wallpaper, fontSize: item.fontSize, chatBubbleCorners: item.chatBubbleCorners, dateTimeFormat: item.dateTimeFormat, nameOrder: item.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil)
|
||||
|
||||
var node: ListViewItemNode?
|
||||
if let current = currentNode {
|
||||
|
@ -87,7 +87,7 @@ private func stringForUserCount(_ peers: [PeerId: SelectivePrivacyPeer], strings
|
||||
|
||||
private enum SelectivePrivacySettingsEntry: ItemListNodeEntry {
|
||||
case forwardsPreviewHeader(PresentationTheme, String)
|
||||
case forwardsPreview(PresentationTheme, TelegramWallpaper, PresentationFontSize, PresentationStrings, PresentationDateTimeFormat, PresentationPersonNameOrder, String, Bool, String)
|
||||
case forwardsPreview(PresentationTheme, TelegramWallpaper, PresentationFontSize, PresentationChatBubbleCorners, PresentationStrings, PresentationDateTimeFormat, PresentationPersonNameOrder, String, Bool, String)
|
||||
case settingHeader(PresentationTheme, String)
|
||||
case everybody(PresentationTheme, String, Bool)
|
||||
case contacts(PresentationTheme, String, Bool)
|
||||
@ -194,8 +194,8 @@ private enum SelectivePrivacySettingsEntry: ItemListNodeEntry {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .forwardsPreview(lhsTheme, lhsWallpaper, lhsFontSize, lhsStrings, lhsTimeFormat, lhsNameOrder, lhsPeerName, lhsLinkEnabled, lhsTooltipText):
|
||||
if case let .forwardsPreview(rhsTheme, rhsWallpaper, rhsFontSize, rhsStrings, rhsTimeFormat, rhsNameOrder, rhsPeerName, rhsLinkEnabled, rhsTooltipText) = rhs, lhsTheme === rhsTheme, lhsWallpaper == rhsWallpaper, lhsFontSize == rhsFontSize, lhsStrings === rhsStrings, lhsTimeFormat == rhsTimeFormat, lhsNameOrder == rhsNameOrder, lhsPeerName == rhsPeerName, lhsLinkEnabled == rhsLinkEnabled, lhsTooltipText == rhsTooltipText {
|
||||
case let .forwardsPreview(lhsTheme, lhsWallpaper, lhsFontSize, lhsChatBubbleCorners, lhsStrings, lhsTimeFormat, lhsNameOrder, lhsPeerName, lhsLinkEnabled, lhsTooltipText):
|
||||
if case let .forwardsPreview(rhsTheme, rhsWallpaper, rhsFontSize, rhsChatBubbleCorners, rhsStrings, rhsTimeFormat, rhsNameOrder, rhsPeerName, rhsLinkEnabled, rhsTooltipText) = rhs, lhsTheme === rhsTheme, lhsWallpaper == rhsWallpaper, lhsFontSize == rhsFontSize, lhsChatBubbleCorners == rhsChatBubbleCorners, lhsStrings === rhsStrings, lhsTimeFormat == rhsTimeFormat, lhsNameOrder == rhsNameOrder, lhsPeerName == rhsPeerName, lhsLinkEnabled == rhsLinkEnabled, lhsTooltipText == rhsTooltipText {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
@ -350,8 +350,8 @@ private enum SelectivePrivacySettingsEntry: ItemListNodeEntry {
|
||||
switch self {
|
||||
case let .forwardsPreviewHeader(theme, text):
|
||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, multiline: true, sectionId: self.section)
|
||||
case let .forwardsPreview(theme, wallpaper, fontSize, strings, dateTimeFormat, nameDisplayOrder, peerName, linkEnabled, tooltipText):
|
||||
return ForwardPrivacyChatPreviewItem(context: arguments.context, theme: theme, strings: strings, sectionId: self.section, fontSize: fontSize, wallpaper: wallpaper, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, peerName: peerName, linkEnabled: linkEnabled, tooltipText: tooltipText)
|
||||
case let .forwardsPreview(theme, wallpaper, fontSize, chatBubbleCorners, strings, dateTimeFormat, nameDisplayOrder, peerName, linkEnabled, tooltipText):
|
||||
return ForwardPrivacyChatPreviewItem(context: arguments.context, theme: theme, strings: strings, sectionId: self.section, fontSize: fontSize, chatBubbleCorners: chatBubbleCorners, wallpaper: wallpaper, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, peerName: peerName, linkEnabled: linkEnabled, tooltipText: tooltipText)
|
||||
case let .settingHeader(theme, text):
|
||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, multiline: true, sectionId: self.section)
|
||||
case let .everybody(theme, text, value):
|
||||
@ -591,7 +591,7 @@ private func selectivePrivacySettingsControllerEntries(presentationData: Present
|
||||
linkEnabled = false
|
||||
}
|
||||
entries.append(.forwardsPreviewHeader(presentationData.theme, presentationData.strings.Privacy_Forwards_Preview))
|
||||
entries.append(.forwardsPreview(presentationData.theme, presentationData.chatWallpaper, presentationData.chatFontSize, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, peerName, linkEnabled, tootipText))
|
||||
entries.append(.forwardsPreview(presentationData.theme, presentationData.chatWallpaper, presentationData.chatFontSize, presentationData.chatBubbleCorners, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, peerName, linkEnabled, tootipText))
|
||||
}
|
||||
|
||||
entries.append(.settingHeader(presentationData.theme, settingTitle))
|
||||
|
@ -303,7 +303,7 @@ private final class TextSizeSelectionControllerNode: ASDisplayNode, UIScrollView
|
||||
}
|
||||
|
||||
private func updateMessagesLayout(layout: ContainerViewLayout, bottomInset: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
let headerItem = self.context.sharedContext.makeChatMessageDateHeaderItem(context: self.context, timestamp: self.referenceTimestamp, theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder)
|
||||
let headerItem = self.context.sharedContext.makeChatMessageDateHeaderItem(context: self.context, timestamp: self.referenceTimestamp, theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder)
|
||||
|
||||
var items: [ListViewItem] = []
|
||||
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: 1)
|
||||
@ -317,20 +317,20 @@ private final class TextSizeSelectionControllerNode: ASDisplayNode, UIScrollView
|
||||
messages[replyMessageId] = Message(stableId: 3, stableVersion: 0, id: replyMessageId, globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66000, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_1_Text, attributes: [], media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
|
||||
let message1 = Message(stableId: 4, stableVersion: 0, id: MessageId(peerId: otherPeerId, namespace: 0, id: 4), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66003, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_3_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])
|
||||
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, message: message1, theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil))
|
||||
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, message: message1, theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil))
|
||||
|
||||
let message2 = Message(stableId: 3, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 3), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66002, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_2_Text, attributes: [ReplyMessageAttribute(messageId: replyMessageId)], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])
|
||||
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, message: message2, theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil))
|
||||
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, message: message2, theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil))
|
||||
|
||||
let waveformBase64 = "DAAOAAkACQAGAAwADwAMABAADQAPABsAGAALAA0AGAAfABoAHgATABgAGQAYABQADAAVABEAHwANAA0ACQAWABkACQAOAAwACQAfAAAAGQAVAAAAEwATAAAACAAfAAAAHAAAABwAHwAAABcAGQAAABQADgAAABQAHwAAAB8AHwAAAAwADwAAAB8AEwAAABoAFwAAAB8AFAAAAAAAHwAAAAAAHgAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAAAA="
|
||||
let voiceAttributes: [TelegramMediaFileAttribute] = [.Audio(isVoice: true, duration: 23, title: nil, performer: nil, waveform: MemoryBuffer(data: Data(base64Encoded: waveformBase64)!))]
|
||||
let voiceMedia = TelegramMediaFile(fileId: MediaId(namespace: 0, id: 0), partialReference: nil, resource: LocalFileMediaResource(fileId: 0), previewRepresentations: [], immediateThumbnailData: nil, mimeType: "audio/ogg", size: 0, attributes: voiceAttributes)
|
||||
|
||||
let message3 = Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66001, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: "", attributes: [], media: [voiceMedia], peers: peers, associatedMessages: messages, associatedMessageIds: [])
|
||||
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, message: message3, theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: FileMediaResourceStatus(mediaStatus: .playbackStatus(.paused), fetchStatus: .Local), tapMessage: nil, clickThroughMessage: nil))
|
||||
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, message: message3, theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: FileMediaResourceStatus(mediaStatus: .playbackStatus(.paused), fetchStatus: .Local), tapMessage: nil, clickThroughMessage: nil))
|
||||
|
||||
let message4 = Message(stableId: 2, stableVersion: 0, id: MessageId(peerId: otherPeerId, namespace: 0, id: 2), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66001, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_1_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])
|
||||
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, message: message4, theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil))
|
||||
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, message: message4, theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil))
|
||||
|
||||
let width: CGFloat
|
||||
if case .regular = layout.metrics.widthClass {
|
||||
|
@ -53,7 +53,7 @@ private enum EditThemeControllerEntry: ItemListNodeEntry {
|
||||
case slug(PresentationTheme, PresentationStrings, String, String, Bool)
|
||||
case slugInfo(PresentationTheme, String)
|
||||
case chatPreviewHeader(PresentationTheme, String)
|
||||
case chatPreview(PresentationTheme, PresentationTheme, TelegramWallpaper, PresentationFontSize, PresentationStrings, PresentationDateTimeFormat, PresentationPersonNameOrder, [ChatPreviewMessageItem])
|
||||
case chatPreview(PresentationTheme, PresentationTheme, TelegramWallpaper, PresentationFontSize, PresentationChatBubbleCorners, PresentationStrings, PresentationDateTimeFormat, PresentationPersonNameOrder, [ChatPreviewMessageItem])
|
||||
case changeColors(PresentationTheme, String)
|
||||
case uploadTheme(PresentationTheme, String)
|
||||
case uploadInfo(PresentationTheme, String)
|
||||
@ -114,8 +114,8 @@ private enum EditThemeControllerEntry: ItemListNodeEntry {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .chatPreview(lhsTheme, lhsComponentTheme, lhsWallpaper, lhsFontSize, lhsStrings, lhsTimeFormat, lhsNameOrder, lhsItems):
|
||||
if case let .chatPreview(rhsTheme, rhsComponentTheme, rhsWallpaper, rhsFontSize, rhsStrings, rhsTimeFormat, rhsNameOrder, rhsItems) = rhs, lhsComponentTheme === rhsComponentTheme, lhsTheme === rhsTheme, lhsWallpaper == rhsWallpaper, lhsFontSize == rhsFontSize, lhsStrings === rhsStrings, lhsTimeFormat == rhsTimeFormat, lhsNameOrder == rhsNameOrder, lhsItems == rhsItems {
|
||||
case let .chatPreview(lhsTheme, lhsComponentTheme, lhsWallpaper, lhsFontSize, lhsChatBubbleCorners, lhsStrings, lhsTimeFormat, lhsNameOrder, lhsItems):
|
||||
if case let .chatPreview(rhsTheme, rhsComponentTheme, rhsWallpaper, rhsFontSize, rhsChatBubbleCorners, rhsStrings, rhsTimeFormat, rhsNameOrder, rhsItems) = rhs, lhsComponentTheme === rhsComponentTheme, lhsTheme === rhsTheme, lhsWallpaper == rhsWallpaper, lhsFontSize == rhsFontSize, lhsChatBubbleCorners == rhsChatBubbleCorners, lhsStrings === rhsStrings, lhsTimeFormat == rhsTimeFormat, lhsNameOrder == rhsNameOrder, lhsItems == rhsItems {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
@ -172,8 +172,8 @@ private enum EditThemeControllerEntry: ItemListNodeEntry {
|
||||
return ItemListTextItem(presentationData: presentationData, text: .markdown(text), sectionId: self.section)
|
||||
case let .chatPreviewHeader(theme, text):
|
||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
|
||||
case let .chatPreview(theme, componentTheme, wallpaper, fontSize, strings, dateTimeFormat, nameDisplayOrder, items):
|
||||
return ThemeSettingsChatPreviewItem(context: arguments.context, theme: theme, componentTheme: componentTheme, strings: strings, sectionId: self.section, fontSize: fontSize, wallpaper: wallpaper, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, messageItems: items)
|
||||
case let .chatPreview(theme, componentTheme, wallpaper, fontSize, chatBubbleCorners, strings, dateTimeFormat, nameDisplayOrder, items):
|
||||
return ThemeSettingsChatPreviewItem(context: arguments.context, theme: theme, componentTheme: componentTheme, strings: strings, sectionId: self.section, fontSize: fontSize, chatBubbleCorners: chatBubbleCorners, wallpaper: wallpaper, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, messageItems: items)
|
||||
case let .changeColors(theme, text):
|
||||
return ItemListActionItem(presentationData: presentationData, title: text, kind: .generic, alignment: .natural, sectionId: self.section, style: .blocks, action: {
|
||||
arguments.openColors()
|
||||
@ -253,7 +253,7 @@ private func editThemeControllerEntries(presentationData: PresentationData, stat
|
||||
entries.append(.slugInfo(presentationData.theme, infoText))
|
||||
|
||||
entries.append(.chatPreviewHeader(presentationData.theme, presentationData.strings.EditTheme_Preview.uppercased()))
|
||||
entries.append(.chatPreview(presentationData.theme, previewTheme, previewTheme.chat.defaultWallpaper, presentationData.chatFontSize, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, [ChatPreviewMessageItem(outgoing: false, reply: (previewIncomingReplyName, previewIncomingReplyText), text: previewIncomingText), ChatPreviewMessageItem(outgoing: true, reply: nil, text: previewOutgoingText)]))
|
||||
entries.append(.chatPreview(presentationData.theme, previewTheme, previewTheme.chat.defaultWallpaper, presentationData.chatFontSize, presentationData.chatBubbleCorners, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, [ChatPreviewMessageItem(outgoing: false, reply: (previewIncomingReplyName, previewIncomingReplyText), text: previewIncomingText), ChatPreviewMessageItem(outgoing: true, reply: nil, text: previewOutgoingText)]))
|
||||
|
||||
entries.append(.changeColors(presentationData.theme, presentationData.strings.EditTheme_ChangeColors))
|
||||
if !hasSettings {
|
||||
@ -556,7 +556,7 @@ public func editThemeController(context: AccountContext, mode: EditThemeControll
|
||||
var themeSpecificChatWallpapers = current.themeSpecificChatWallpapers
|
||||
themeSpecificChatWallpapers[themeReference.index] = nil
|
||||
|
||||
return PresentationThemeSettings(theme: themeReference, themeSpecificAccentColors: current.themeSpecificAccentColors, themeSpecificChatWallpapers: themeSpecificChatWallpapers, useSystemFont: current.useSystemFont, fontSize: current.fontSize, listsFontSize: current.listsFontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, largeEmoji: current.largeEmoji, disableAnimations: current.disableAnimations)
|
||||
return PresentationThemeSettings(theme: themeReference, themeSpecificAccentColors: current.themeSpecificAccentColors, themeSpecificChatWallpapers: themeSpecificChatWallpapers, useSystemFont: current.useSystemFont, fontSize: current.fontSize, listsFontSize: current.listsFontSize, chatBubbleSettings: current.chatBubbleSettings, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, largeEmoji: current.largeEmoji, disableAnimations: current.disableAnimations)
|
||||
}) |> deliverOnMainQueue).start(completed: {
|
||||
if !hasCustomFile {
|
||||
saveThemeTemplateFile(state.title, themeResource, {
|
||||
@ -590,7 +590,7 @@ public func editThemeController(context: AccountContext, mode: EditThemeControll
|
||||
var themeSpecificChatWallpapers = current.themeSpecificChatWallpapers
|
||||
themeSpecificChatWallpapers[themeReference.index] = nil
|
||||
|
||||
return PresentationThemeSettings(theme: themeReference, themeSpecificAccentColors: current.themeSpecificAccentColors, themeSpecificChatWallpapers: themeSpecificChatWallpapers, useSystemFont: current.useSystemFont, fontSize: current.fontSize, listsFontSize: current.listsFontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, largeEmoji: current.largeEmoji, disableAnimations: current.disableAnimations)
|
||||
return PresentationThemeSettings(theme: themeReference, themeSpecificAccentColors: current.themeSpecificAccentColors, themeSpecificChatWallpapers: themeSpecificChatWallpapers, useSystemFont: current.useSystemFont, fontSize: current.fontSize, listsFontSize: current.listsFontSize, chatBubbleSettings: current.chatBubbleSettings, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, largeEmoji: current.largeEmoji, disableAnimations: current.disableAnimations)
|
||||
}) |> deliverOnMainQueue).start(completed: {
|
||||
if let themeResource = themeResource, !hasCustomFile {
|
||||
saveThemeTemplateFile(state.title, themeResource, {
|
||||
|
@ -276,7 +276,7 @@ final class ThemeAccentColorController: ViewController {
|
||||
var themeSpecificAccentColors = current.themeSpecificAccentColors
|
||||
themeSpecificAccentColors[baseThemeReference.index] = PresentationThemeAccentColor(themeIndex: themeReference.index)
|
||||
|
||||
return PresentationThemeSettings(theme: updatedTheme, themeSpecificAccentColors: themeSpecificAccentColors, themeSpecificChatWallpapers: themeSpecificChatWallpapers, useSystemFont: current.useSystemFont, fontSize: current.fontSize, listsFontSize: current.listsFontSize, automaticThemeSwitchSetting: updatedAutomaticThemeSwitchSetting, largeEmoji: current.largeEmoji, disableAnimations: current.disableAnimations)
|
||||
return PresentationThemeSettings(theme: updatedTheme, themeSpecificAccentColors: themeSpecificAccentColors, themeSpecificChatWallpapers: themeSpecificChatWallpapers, useSystemFont: current.useSystemFont, fontSize: current.fontSize, listsFontSize: current.listsFontSize, chatBubbleSettings: current.chatBubbleSettings, automaticThemeSwitchSetting: updatedAutomaticThemeSwitchSetting, largeEmoji: current.largeEmoji, disableAnimations: current.disableAnimations)
|
||||
})
|
||||
|> castError(CreateThemeError.self)
|
||||
} else {
|
||||
@ -305,7 +305,7 @@ final class ThemeAccentColorController: ViewController {
|
||||
var themeSpecificAccentColors = current.themeSpecificAccentColors
|
||||
themeSpecificAccentColors[baseThemeReference.index] = PresentationThemeAccentColor(themeIndex: themeReference.index)
|
||||
|
||||
return PresentationThemeSettings(theme: updatedTheme, themeSpecificAccentColors: themeSpecificAccentColors, themeSpecificChatWallpapers: themeSpecificChatWallpapers, useSystemFont: current.useSystemFont, fontSize: current.fontSize, listsFontSize: current.listsFontSize, automaticThemeSwitchSetting: updatedAutomaticThemeSwitchSetting, largeEmoji: current.largeEmoji, disableAnimations: current.disableAnimations)
|
||||
return PresentationThemeSettings(theme: updatedTheme, themeSpecificAccentColors: themeSpecificAccentColors, themeSpecificChatWallpapers: themeSpecificChatWallpapers, useSystemFont: current.useSystemFont, fontSize: current.fontSize, listsFontSize: current.listsFontSize, chatBubbleSettings: current.chatBubbleSettings, automaticThemeSwitchSetting: updatedAutomaticThemeSwitchSetting, largeEmoji: current.largeEmoji, disableAnimations: current.disableAnimations)
|
||||
})
|
||||
|> castError(CreateThemeError.self)
|
||||
} else {
|
||||
|
@ -226,6 +226,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
self.theme = theme
|
||||
self.wallpaper = self.presentationData.chatWallpaper
|
||||
let bubbleCorners = self.presentationData.chatBubbleCorners
|
||||
|
||||
self.ready = ready
|
||||
|
||||
@ -498,7 +499,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
|
||||
updatedTheme = theme
|
||||
}
|
||||
|
||||
let _ = PresentationResourcesChat.principalGraphics(mediaBox: context.account.postbox.mediaBox, knockoutWallpaper: context.sharedContext.immediateExperimentalUISettings.knockoutWallpaper, theme: updatedTheme!, wallpaper: wallpaper)
|
||||
let _ = PresentationResourcesChat.principalGraphics(mediaBox: context.account.postbox.mediaBox, knockoutWallpaper: context.sharedContext.immediateExperimentalUISettings.knockoutWallpaper, theme: updatedTheme!, wallpaper: wallpaper, bubbleCorners: bubbleCorners)
|
||||
} else {
|
||||
updatedTheme = nil
|
||||
}
|
||||
@ -836,7 +837,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
|
||||
}
|
||||
|
||||
private func updateMessagesLayout(layout: ContainerViewLayout, bottomInset: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
let headerItem = self.context.sharedContext.makeChatMessageDateHeaderItem(context: self.context, timestamp: self.referenceTimestamp, theme: self.theme, strings: self.presentationData.strings, wallpaper: self.wallpaper, fontSize: self.presentationData.chatFontSize, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder)
|
||||
let headerItem = self.context.sharedContext.makeChatMessageDateHeaderItem(context: self.context, timestamp: self.referenceTimestamp, theme: self.theme, strings: self.presentationData.strings, wallpaper: self.wallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder)
|
||||
|
||||
var items: [ListViewItem] = []
|
||||
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: 1)
|
||||
@ -878,7 +879,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
|
||||
sampleMessages.append(message8)
|
||||
|
||||
items = sampleMessages.reversed().map { message in
|
||||
let item = self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, message: message, theme: self.theme, strings: self.presentationData.strings, wallpaper: self.wallpaper, fontSize: self.presentationData.chatFontSize, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: !message.media.isEmpty ? FileMediaResourceStatus(mediaStatus: .playbackStatus(.paused), fetchStatus: .Local) : nil, tapMessage: { [weak self] message in
|
||||
let item = self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, message: message, theme: self.theme, strings: self.presentationData.strings, wallpaper: self.wallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: !message.media.isEmpty ? FileMediaResourceStatus(mediaStatus: .playbackStatus(.paused), fetchStatus: .Local) : nil, tapMessage: { [weak self] message in
|
||||
if message.flags.contains(.Incoming) {
|
||||
self?.updateSection(.accent)
|
||||
self?.requestSectionUpdate?(.accent)
|
||||
|
@ -442,7 +442,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
}
|
||||
|
||||
private func updateMessagesLayout(layout: ContainerViewLayout, bottomInset: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
let headerItem = self.context.sharedContext.makeChatMessageDateHeaderItem(context: self.context, timestamp: self.referenceTimestamp, theme: self.previewTheme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder)
|
||||
let headerItem = self.context.sharedContext.makeChatMessageDateHeaderItem(context: self.context, timestamp: self.referenceTimestamp, theme: self.previewTheme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder)
|
||||
|
||||
var items: [ListViewItem] = []
|
||||
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: 1)
|
||||
@ -484,7 +484,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
sampleMessages.append(message8)
|
||||
|
||||
items = sampleMessages.reversed().map { message in
|
||||
self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, message: message, theme: self.previewTheme, strings: self.presentationData.strings, wallpaper: self.previewTheme.chat.defaultWallpaper, fontSize: self.presentationData.chatFontSize, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: !message.media.isEmpty ? FileMediaResourceStatus(mediaStatus: .playbackStatus(.paused), fetchStatus: .Local) : nil, tapMessage: nil, clickThroughMessage: nil)
|
||||
self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, message: message, theme: self.previewTheme, strings: self.presentationData.strings, wallpaper: self.previewTheme.chat.defaultWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: !message.media.isEmpty ? FileMediaResourceStatus(mediaStatus: .playbackStatus(.paused), fetchStatus: .Local) : nil, tapMessage: nil, clickThroughMessage: nil)
|
||||
}
|
||||
|
||||
let width: CGFloat
|
||||
|
@ -40,18 +40,20 @@ class ThemeSettingsChatPreviewItem: ListViewItem, ItemListItem {
|
||||
let strings: PresentationStrings
|
||||
let sectionId: ItemListSectionId
|
||||
let fontSize: PresentationFontSize
|
||||
let chatBubbleCorners: PresentationChatBubbleCorners
|
||||
let wallpaper: TelegramWallpaper
|
||||
let dateTimeFormat: PresentationDateTimeFormat
|
||||
let nameDisplayOrder: PresentationPersonNameOrder
|
||||
let messageItems: [ChatPreviewMessageItem]
|
||||
|
||||
init(context: AccountContext, theme: PresentationTheme, componentTheme: PresentationTheme, strings: PresentationStrings, sectionId: ItemListSectionId, fontSize: PresentationFontSize, wallpaper: TelegramWallpaper, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, messageItems: [ChatPreviewMessageItem]) {
|
||||
init(context: AccountContext, theme: PresentationTheme, componentTheme: PresentationTheme, strings: PresentationStrings, sectionId: ItemListSectionId, fontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, wallpaper: TelegramWallpaper, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, messageItems: [ChatPreviewMessageItem]) {
|
||||
self.context = context
|
||||
self.theme = theme
|
||||
self.componentTheme = componentTheme
|
||||
self.strings = strings
|
||||
self.sectionId = sectionId
|
||||
self.fontSize = fontSize
|
||||
self.chatBubbleCorners = chatBubbleCorners
|
||||
self.wallpaper = wallpaper
|
||||
self.dateTimeFormat = dateTimeFormat
|
||||
self.nameDisplayOrder = nameDisplayOrder
|
||||
@ -163,7 +165,7 @@ class ThemeSettingsChatPreviewItemNode: ListViewItemNode {
|
||||
}
|
||||
|
||||
let message = Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: messageItem.outgoing ? otherPeerId : peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66000, flags: messageItem.outgoing ? [] : [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: messageItem.outgoing ? TelegramUser(id: otherPeerId, accessHash: nil, firstName: "", lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: []) : nil, text: messageItem.text, attributes: messageItem.reply != nil ? [ReplyMessageAttribute(messageId: replyMessageId)] : [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])
|
||||
items.append(item.context.sharedContext.makeChatMessagePreviewItem(context: item.context, message: message, theme: item.componentTheme, strings: item.strings, wallpaper: item.wallpaper, fontSize: item.fontSize, dateTimeFormat: item.dateTimeFormat, nameOrder: item.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil))
|
||||
items.append(item.context.sharedContext.makeChatMessagePreviewItem(context: item.context, message: message, theme: item.componentTheme, strings: item.strings, wallpaper: item.wallpaper, fontSize: item.fontSize, chatBubbleCorners: item.chatBubbleCorners, dateTimeFormat: item.dateTimeFormat, nameOrder: item.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil))
|
||||
}
|
||||
|
||||
var nodes: [ListViewItemNode] = []
|
||||
|
@ -76,6 +76,7 @@ private final class ThemeSettingsControllerArguments {
|
||||
let openAccentColorPicker: (PresentationThemeReference, Bool) -> Void
|
||||
let openAutoNightTheme: () -> Void
|
||||
let openTextSize: () -> Void
|
||||
let openBubbleSettings: () -> Void
|
||||
let toggleLargeEmoji: (Bool) -> Void
|
||||
let disableAnimations: (Bool) -> Void
|
||||
let selectAppIcon: (String) -> Void
|
||||
@ -83,7 +84,7 @@ private final class ThemeSettingsControllerArguments {
|
||||
let themeContextAction: (Bool, PresentationThemeReference, ASDisplayNode, ContextGesture?) -> Void
|
||||
let colorContextAction: (Bool, PresentationThemeReference, ThemeSettingsColorOption?, ASDisplayNode, ContextGesture?) -> Void
|
||||
|
||||
init(context: AccountContext, selectTheme: @escaping (PresentationThemeReference) -> Void, selectFontSize: @escaping (PresentationFontSize) -> Void, openWallpaperSettings: @escaping () -> Void, selectAccentColor: @escaping (PresentationThemeAccentColor?) -> Void, openAccentColorPicker: @escaping (PresentationThemeReference, Bool) -> Void, openAutoNightTheme: @escaping () -> Void, openTextSize: @escaping () -> Void, toggleLargeEmoji: @escaping (Bool) -> Void, disableAnimations: @escaping (Bool) -> Void, selectAppIcon: @escaping (String) -> Void, editTheme: @escaping (PresentationCloudTheme) -> Void, themeContextAction: @escaping (Bool, PresentationThemeReference, ASDisplayNode, ContextGesture?) -> Void, colorContextAction: @escaping (Bool, PresentationThemeReference, ThemeSettingsColorOption?, ASDisplayNode, ContextGesture?) -> Void) {
|
||||
init(context: AccountContext, selectTheme: @escaping (PresentationThemeReference) -> Void, selectFontSize: @escaping (PresentationFontSize) -> Void, openWallpaperSettings: @escaping () -> Void, selectAccentColor: @escaping (PresentationThemeAccentColor?) -> Void, openAccentColorPicker: @escaping (PresentationThemeReference, Bool) -> Void, openAutoNightTheme: @escaping () -> Void, openTextSize: @escaping () -> Void, openBubbleSettings: @escaping () -> Void, toggleLargeEmoji: @escaping (Bool) -> Void, disableAnimations: @escaping (Bool) -> Void, selectAppIcon: @escaping (String) -> Void, editTheme: @escaping (PresentationCloudTheme) -> Void, themeContextAction: @escaping (Bool, PresentationThemeReference, ASDisplayNode, ContextGesture?) -> Void, colorContextAction: @escaping (Bool, PresentationThemeReference, ThemeSettingsColorOption?, ASDisplayNode, ContextGesture?) -> Void) {
|
||||
self.context = context
|
||||
self.selectTheme = selectTheme
|
||||
self.selectFontSize = selectFontSize
|
||||
@ -92,6 +93,7 @@ private final class ThemeSettingsControllerArguments {
|
||||
self.openAccentColorPicker = openAccentColorPicker
|
||||
self.openAutoNightTheme = openAutoNightTheme
|
||||
self.openTextSize = openTextSize
|
||||
self.openBubbleSettings = openBubbleSettings
|
||||
self.toggleLargeEmoji = toggleLargeEmoji
|
||||
self.disableAnimations = disableAnimations
|
||||
self.selectAppIcon = selectAppIcon
|
||||
@ -131,11 +133,12 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
|
||||
case themeListHeader(PresentationTheme, String)
|
||||
case fontSizeHeader(PresentationTheme, String)
|
||||
case fontSize(PresentationTheme, PresentationFontSize)
|
||||
case chatPreview(PresentationTheme, TelegramWallpaper, PresentationFontSize, PresentationStrings, PresentationDateTimeFormat, PresentationPersonNameOrder, [ChatPreviewMessageItem])
|
||||
case chatPreview(PresentationTheme, TelegramWallpaper, PresentationFontSize, PresentationChatBubbleCorners, PresentationStrings, PresentationDateTimeFormat, PresentationPersonNameOrder, [ChatPreviewMessageItem])
|
||||
case wallpaper(PresentationTheme, String)
|
||||
case accentColor(PresentationTheme, PresentationThemeReference, PresentationThemeReference, [PresentationThemeReference], ThemeSettingsColorOption?)
|
||||
case autoNightTheme(PresentationTheme, String, String)
|
||||
case textSize(PresentationTheme, String, String)
|
||||
case bubbleSettings(PresentationTheme, String, String)
|
||||
case themeItem(PresentationTheme, PresentationStrings, [PresentationThemeReference], [PresentationThemeReference], PresentationThemeReference, [Int64: PresentationThemeAccentColor], [Int64: TelegramWallpaper], PresentationThemeAccentColor?)
|
||||
case iconHeader(PresentationTheme, String)
|
||||
case iconItem(PresentationTheme, PresentationStrings, [PresentationAppIcon], String?)
|
||||
@ -150,7 +153,7 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
|
||||
return ThemeSettingsControllerSection.chatPreview.rawValue
|
||||
case .fontSizeHeader, .fontSize:
|
||||
return ThemeSettingsControllerSection.fontSize.rawValue
|
||||
case .wallpaper, .autoNightTheme, .textSize:
|
||||
case .wallpaper, .autoNightTheme, .textSize, .bubbleSettings:
|
||||
return ThemeSettingsControllerSection.background.rawValue
|
||||
case .iconHeader, .iconItem:
|
||||
return ThemeSettingsControllerSection.icon.rawValue
|
||||
@ -175,29 +178,31 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
|
||||
return 6
|
||||
case .textSize:
|
||||
return 7
|
||||
case .fontSizeHeader:
|
||||
case .bubbleSettings:
|
||||
return 8
|
||||
case .fontSize:
|
||||
case .fontSizeHeader:
|
||||
return 9
|
||||
case .iconHeader:
|
||||
case .fontSize:
|
||||
return 10
|
||||
case .iconItem:
|
||||
case .iconHeader:
|
||||
return 11
|
||||
case .otherHeader:
|
||||
case .iconItem:
|
||||
return 12
|
||||
case .largeEmoji:
|
||||
case .otherHeader:
|
||||
return 13
|
||||
case .animations:
|
||||
case .largeEmoji:
|
||||
return 14
|
||||
case .animationsInfo:
|
||||
case .animations:
|
||||
return 15
|
||||
case .animationsInfo:
|
||||
return 16
|
||||
}
|
||||
}
|
||||
|
||||
static func ==(lhs: ThemeSettingsControllerEntry, rhs: ThemeSettingsControllerEntry) -> Bool {
|
||||
switch lhs {
|
||||
case let .chatPreview(lhsTheme, lhsWallpaper, lhsFontSize, lhsStrings, lhsTimeFormat, lhsNameOrder, lhsItems):
|
||||
if case let .chatPreview(rhsTheme, rhsWallpaper, rhsFontSize, rhsStrings, rhsTimeFormat, rhsNameOrder, rhsItems) = rhs, lhsTheme === rhsTheme, lhsWallpaper == rhsWallpaper, lhsFontSize == rhsFontSize, lhsStrings === rhsStrings, lhsTimeFormat == rhsTimeFormat, lhsNameOrder == rhsNameOrder, lhsItems == rhsItems {
|
||||
case let .chatPreview(lhsTheme, lhsWallpaper, lhsFontSize, lhsChatBubbleCorners, lhsStrings, lhsTimeFormat, lhsNameOrder, lhsItems):
|
||||
if case let .chatPreview(rhsTheme, rhsWallpaper, rhsFontSize, rhsChatBubbleCorners, rhsStrings, rhsTimeFormat, rhsNameOrder, rhsItems) = rhs, lhsTheme === rhsTheme, lhsWallpaper == rhsWallpaper, lhsFontSize == rhsFontSize, lhsChatBubbleCorners == rhsChatBubbleCorners, lhsStrings === rhsStrings, lhsTimeFormat == rhsTimeFormat, lhsNameOrder == rhsNameOrder, lhsItems == rhsItems {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
@ -226,6 +231,12 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .bubbleSettings(lhsTheme, lhsText, lhsValue):
|
||||
if case let .bubbleSettings(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .themeListHeader(lhsTheme, lhsText):
|
||||
if case let .themeListHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||
return true
|
||||
@ -302,8 +313,8 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
|
||||
return ThemeSettingsFontSizeItem(theme: theme, fontSize: fontSize, sectionId: self.section, updated: { value in
|
||||
arguments.selectFontSize(value)
|
||||
}, tag: ThemeSettingsEntryTag.fontSize)
|
||||
case let .chatPreview(theme, wallpaper, fontSize, strings, dateTimeFormat, nameDisplayOrder, items):
|
||||
return ThemeSettingsChatPreviewItem(context: arguments.context, theme: theme, componentTheme: theme, strings: strings, sectionId: self.section, fontSize: fontSize, wallpaper: wallpaper, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, messageItems: items)
|
||||
case let .chatPreview(theme, wallpaper, fontSize, chatBubbleCorners, strings, dateTimeFormat, nameDisplayOrder, items):
|
||||
return ThemeSettingsChatPreviewItem(context: arguments.context, theme: theme, componentTheme: theme, strings: strings, sectionId: self.section, fontSize: fontSize, chatBubbleCorners: chatBubbleCorners, wallpaper: wallpaper, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, messageItems: items)
|
||||
case let .wallpaper(theme, text):
|
||||
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: "", sectionId: self.section, style: .blocks, action: {
|
||||
arguments.openWallpaperSettings()
|
||||
@ -387,6 +398,10 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
|
||||
return ItemListDisclosureItem(presentationData: presentationData, icon: nil, title: text, label: value, labelStyle: .text, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: {
|
||||
arguments.openTextSize()
|
||||
})
|
||||
case let .bubbleSettings(theme, text, value):
|
||||
return ItemListDisclosureItem(presentationData: presentationData, icon: nil, title: text, label: value, labelStyle: .text, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: {
|
||||
arguments.openBubbleSettings()
|
||||
})
|
||||
case let .themeListHeader(theme, text):
|
||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
|
||||
case let .themeItem(theme, strings, themes, allThemes, currentTheme, themeSpecificAccentColors, themeSpecificChatWallpapers, _):
|
||||
@ -429,7 +444,7 @@ private func themeSettingsControllerEntries(presentationData: PresentationData,
|
||||
let strings = presentationData.strings
|
||||
let title = presentationData.autoNightModeTriggered ? strings.Appearance_ColorThemeNight.uppercased() : strings.Appearance_ColorTheme.uppercased()
|
||||
entries.append(.themeListHeader(presentationData.theme, title))
|
||||
entries.append(.chatPreview(presentationData.theme, presentationData.chatWallpaper, presentationData.chatFontSize, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, [ChatPreviewMessageItem(outgoing: false, reply: (presentationData.strings.Appearance_PreviewReplyAuthor, presentationData.strings.Appearance_PreviewReplyText), text: presentationData.strings.Appearance_PreviewIncomingText), ChatPreviewMessageItem(outgoing: true, reply: nil, text: presentationData.strings.Appearance_PreviewOutgoingText)]))
|
||||
entries.append(.chatPreview(presentationData.theme, presentationData.chatWallpaper, presentationData.chatFontSize, presentationData.chatBubbleCorners, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, [ChatPreviewMessageItem(outgoing: false, reply: (presentationData.strings.Appearance_PreviewReplyAuthor, presentationData.strings.Appearance_PreviewReplyText), text: presentationData.strings.Appearance_PreviewIncomingText), ChatPreviewMessageItem(outgoing: true, reply: nil, text: presentationData.strings.Appearance_PreviewOutgoingText)]))
|
||||
|
||||
let generalThemes: [PresentationThemeReference] = availableThemes.filter { reference in
|
||||
if case let .cloud(theme) = reference {
|
||||
@ -497,6 +512,7 @@ private func themeSettingsControllerEntries(presentationData: PresentationData,
|
||||
}
|
||||
}
|
||||
entries.append(.textSize(presentationData.theme, strings.Appearance_TextSizeSetting, textSizeValue))
|
||||
entries.append(.bubbleSettings(presentationData.theme, strings.Appearance_BubbleCornersSetting, ""))
|
||||
|
||||
if !availableAppIcons.isEmpty {
|
||||
entries.append(.iconHeader(presentationData.theme, strings.Appearance_AppIcon.uppercased()))
|
||||
@ -570,6 +586,13 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
|
||||
let settings = (view.entries[ApplicationSpecificSharedDataKeys.presentationThemeSettings] as? PresentationThemeSettings) ?? PresentationThemeSettings.defaultSettings
|
||||
pushControllerImpl?(TextSizeSelectionController(context: context, presentationThemeSettings: settings))
|
||||
})
|
||||
}, openBubbleSettings: {
|
||||
let _ = (context.sharedContext.accountManager.sharedData(keys: Set([ApplicationSpecificSharedDataKeys.presentationThemeSettings]))
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { view in
|
||||
let settings = (view.entries[ApplicationSpecificSharedDataKeys.presentationThemeSettings] as? PresentationThemeSettings) ?? PresentationThemeSettings.defaultSettings
|
||||
pushControllerImpl?(BubbleSettingsController(context: context, presentationThemeSettings: settings))
|
||||
})
|
||||
}, toggleLargeEmoji: { largeEmoji in
|
||||
let _ = updatePresentationThemeSettingsInteractively(accountManager: context.sharedContext.accountManager, { current in
|
||||
return current.withUpdatedLargeEmoji(largeEmoji)
|
||||
@ -1272,7 +1295,7 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
|
||||
}
|
||||
}
|
||||
|
||||
return PresentationThemeSettings(theme: updatedTheme, themeSpecificAccentColors: themeSpecificAccentColors, themeSpecificChatWallpapers: themeSpecificChatWallpapers, useSystemFont: current.useSystemFont, fontSize: current.fontSize, listsFontSize: current.listsFontSize, automaticThemeSwitchSetting: updatedAutomaticThemeSwitchSetting, largeEmoji: current.largeEmoji, disableAnimations: current.disableAnimations)
|
||||
return PresentationThemeSettings(theme: updatedTheme, themeSpecificAccentColors: themeSpecificAccentColors, themeSpecificChatWallpapers: themeSpecificChatWallpapers, useSystemFont: current.useSystemFont, fontSize: current.fontSize, listsFontSize: current.listsFontSize, chatBubbleSettings: current.chatBubbleSettings, automaticThemeSwitchSetting: updatedAutomaticThemeSwitchSetting, largeEmoji: current.largeEmoji, disableAnimations: current.disableAnimations)
|
||||
}).start()
|
||||
|
||||
presentCrossfadeControllerImpl?(true)
|
||||
|
@ -16,17 +16,19 @@ class ThemeSettingsFontSizeItem: ListViewItem, ItemListItem {
|
||||
let theme: PresentationTheme
|
||||
let fontSize: PresentationFontSize
|
||||
let disableLeadingInset: Bool
|
||||
let displayIcons: Bool
|
||||
let force: Bool
|
||||
let enabled: Bool
|
||||
let sectionId: ItemListSectionId
|
||||
let updated: (PresentationFontSize) -> Void
|
||||
let tag: ItemListItemTag?
|
||||
|
||||
init(theme: PresentationTheme, fontSize: PresentationFontSize, enabled: Bool = true, disableLeadingInset: Bool = false, force: Bool = false, sectionId: ItemListSectionId, updated: @escaping (PresentationFontSize) -> Void, tag: ItemListItemTag? = nil) {
|
||||
init(theme: PresentationTheme, fontSize: PresentationFontSize, enabled: Bool = true, disableLeadingInset: Bool = false, displayIcons: Bool = true, force: Bool = false, sectionId: ItemListSectionId, updated: @escaping (PresentationFontSize) -> Void, tag: ItemListItemTag? = nil) {
|
||||
self.theme = theme
|
||||
self.fontSize = fontSize
|
||||
self.enabled = enabled
|
||||
self.disableLeadingInset = disableLeadingInset
|
||||
self.displayIcons = displayIcons
|
||||
self.force = force
|
||||
self.sectionId = sectionId
|
||||
self.updated = updated
|
||||
@ -164,7 +166,9 @@ class ThemeSettingsFontSizeItemNode: ListViewItemNode, ItemListItemNode {
|
||||
sliderView.trackColor = item.enabled ? item.theme.list.itemAccentColor : item.theme.list.itemDisabledTextColor
|
||||
sliderView.knobImage = generateKnobImage()
|
||||
|
||||
sliderView.frame = CGRect(origin: CGPoint(x: params.leftInset + 38.0, y: 8.0), size: CGSize(width: params.width - params.leftInset - params.rightInset - 38.0 * 2.0, height: 44.0))
|
||||
let sliderInset: CGFloat = item.displayIcons ? 38.0 : 16.0
|
||||
|
||||
sliderView.frame = CGRect(origin: CGPoint(x: params.leftInset + sliderInset, y: 8.0), size: CGSize(width: params.width - params.leftInset - params.rightInset - sliderInset * 2.0, height: 44.0))
|
||||
}
|
||||
self.view.insertSubview(sliderView, belowSubview: self.disabledOverlayNode.view)
|
||||
sliderView.addTarget(self, action: #selector(self.sliderValueChanged), for: .valueChanged)
|
||||
@ -271,6 +275,9 @@ class ThemeSettingsFontSizeItemNode: ListViewItemNode, ItemListItemNode {
|
||||
strongSelf.rightIconNode.frame = CGRect(origin: CGPoint(x: params.width - params.rightInset - 14.0 - image.size.width, y: 21.0), size: CGSize(width: image.size.width, height: image.size.height))
|
||||
}
|
||||
|
||||
strongSelf.leftIconNode.isHidden = !item.displayIcons
|
||||
strongSelf.rightIconNode.isHidden = !item.displayIcons
|
||||
|
||||
if let sliderView = strongSelf.sliderView {
|
||||
sliderView.isUserInteractionEnabled = item.enabled
|
||||
sliderView.trackColor = item.enabled ? item.theme.list.itemAccentColor : item.theme.list.itemDisabledTextColor
|
||||
@ -302,7 +309,8 @@ class ThemeSettingsFontSizeItemNode: ListViewItemNode, ItemListItemNode {
|
||||
sliderView.value = value
|
||||
}
|
||||
|
||||
sliderView.frame = CGRect(origin: CGPoint(x: params.leftInset + 38.0, y: 8.0), size: CGSize(width: params.width - params.leftInset - params.rightInset - 38.0 * 2.0, height: 44.0))
|
||||
let sliderInset: CGFloat = item.displayIcons ? 38.0 : 16.0
|
||||
sliderView.frame = CGRect(origin: CGPoint(x: params.leftInset + sliderInset, y: 8.0), size: CGSize(width: params.width - params.leftInset - params.rightInset - sliderInset * 2.0, height: 44.0))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -832,10 +832,10 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
let theme = self.presentationData.theme.withUpdated(preview: true)
|
||||
|
||||
let message1 = Message(stableId: 2, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 2), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66001, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: bottomMessageText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])
|
||||
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, message: message1, theme: theme, strings: self.presentationData.strings, wallpaper: currentWallpaper, fontSize: self.presentationData.chatFontSize, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil))
|
||||
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, message: message1, theme: theme, strings: self.presentationData.strings, wallpaper: currentWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil))
|
||||
|
||||
let message2 = Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: topMessageText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])
|
||||
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, message: message2, theme: theme, strings: self.presentationData.strings, wallpaper: currentWallpaper, fontSize: self.presentationData.chatFontSize, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil))
|
||||
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, message: message2, theme: theme, strings: self.presentationData.strings, wallpaper: currentWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil))
|
||||
|
||||
let params = ListViewItemLayoutParams(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, availableHeight: layout.size.height)
|
||||
if let messageNodes = self.messageNodes {
|
||||
|
@ -26,14 +26,253 @@ public func messageSingleBubbleLikeImage(fillColor: UIColor, strokeColor: UIColo
|
||||
})!.stretchableImage(withLeftCapWidth: Int(diameter / 2.0), topCapHeight: Int(diameter / 2.0))
|
||||
}
|
||||
|
||||
public func messageBubbleImage(incoming: Bool, fillColor: UIColor, strokeColor: UIColor, neighbors: MessageBubbleImageNeighbors, theme: PresentationThemeChat, wallpaper: TelegramWallpaper, knockout knockoutValue: Bool, mask: Bool = false, extendedEdges: Bool = false, onlyOutline: Bool = false) -> UIImage {
|
||||
let diameter: CGFloat = 36.0
|
||||
let corner: CGFloat = 7.0
|
||||
private let minRadiusForFullTailCorner: CGFloat = 14.0
|
||||
|
||||
func mediaBubbleCornerImage(incoming: Bool, radius: CGFloat, inset: CGFloat) -> UIImage {
|
||||
let imageSize = CGSize(width: radius + 7.0, height: 8.0)
|
||||
let fixedMainDiameter: CGFloat = 33.0
|
||||
|
||||
let formContext = DrawingContext(size: imageSize)
|
||||
formContext.withFlippedContext { context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: imageSize))
|
||||
context.translateBy(x: imageSize.width / 2.0, y: imageSize.height / 2.0)
|
||||
context.scaleBy(x: incoming ? -1.0 : 1.0, y: -1.0)
|
||||
context.translateBy(x: -imageSize.width / 2.0, y: -imageSize.height / 2.0)
|
||||
|
||||
context.setFillColor(UIColor.black.cgColor)
|
||||
|
||||
let bottomEllipse = CGRect(origin: CGPoint(x: 24.0, y: 16.0), size: CGSize(width: 27.0, height: 17.0)).insetBy(dx: inset, dy: inset).offsetBy(dx: inset, dy: inset)
|
||||
let topEllipse = CGRect(origin: CGPoint(x: 33.0, y: 14.0), size: CGSize(width: 23.0, height: 21.0)).insetBy(dx: -inset, dy: -inset).offsetBy(dx: inset, dy: inset)
|
||||
|
||||
context.translateBy(x: -fixedMainDiameter + imageSize.width - 6.0, y: -fixedMainDiameter + imageSize.height)
|
||||
|
||||
let topLeftRadius: CGFloat = 2.0
|
||||
let topRightRadius: CGFloat = 2.0
|
||||
let bottomLeftRadius: CGFloat = 2.0
|
||||
let bottomRightRadius: CGFloat = radius
|
||||
|
||||
context.move(to: CGPoint(x: 0.0, y: topLeftRadius))
|
||||
context.addArc(tangent1End: CGPoint(x: 0.0, y: 0.0), tangent2End: CGPoint(x: topLeftRadius, y: 0.0), radius: topLeftRadius)
|
||||
context.addLine(to: CGPoint(x: fixedMainDiameter - topRightRadius, y: 0.0))
|
||||
context.addArc(tangent1End: CGPoint(x: fixedMainDiameter, y: 0.0), tangent2End: CGPoint(x: fixedMainDiameter, y: topRightRadius), radius: topRightRadius)
|
||||
context.addLine(to: CGPoint(x: fixedMainDiameter, y: fixedMainDiameter - bottomRightRadius))
|
||||
context.addArc(tangent1End: CGPoint(x: fixedMainDiameter, y: fixedMainDiameter), tangent2End: CGPoint(x: fixedMainDiameter - bottomRightRadius, y: fixedMainDiameter), radius: bottomRightRadius)
|
||||
context.addLine(to: CGPoint(x: bottomLeftRadius, y: fixedMainDiameter))
|
||||
context.addArc(tangent1End: CGPoint(x: 0.0, y: fixedMainDiameter), tangent2End: CGPoint(x: 0.0, y: fixedMainDiameter - bottomLeftRadius), radius: bottomLeftRadius)
|
||||
context.addLine(to: CGPoint(x: 0.0, y: topLeftRadius))
|
||||
context.fillPath()
|
||||
|
||||
if radius >= minRadiusForFullTailCorner {
|
||||
context.move(to: CGPoint(x: bottomEllipse.minX, y: bottomEllipse.midY))
|
||||
context.addQuadCurve(to: CGPoint(x: bottomEllipse.midX, y: bottomEllipse.maxY), control: CGPoint(x: bottomEllipse.minX, y: bottomEllipse.maxY))
|
||||
context.addQuadCurve(to: CGPoint(x: bottomEllipse.maxX, y: bottomEllipse.midY), control: CGPoint(x: bottomEllipse.maxX, y: bottomEllipse.maxY))
|
||||
context.fillPath()
|
||||
} else {
|
||||
context.fill(CGRect(origin: CGPoint(x: bottomEllipse.minX - 5.0, y: bottomEllipse.midY), size: CGSize(width: bottomEllipse.width + 5.0, height: bottomEllipse.height / 2.0)))
|
||||
}
|
||||
context.fill(CGRect(origin: CGPoint(x: fixedMainDiameter / 2.0, y: fixedMainDiameter / 2.0), size: CGSize(width: fixedMainDiameter / 2.0, height: bottomEllipse.midY - fixedMainDiameter / 2.0)))
|
||||
context.setFillColor(UIColor.clear.cgColor)
|
||||
context.setBlendMode(.copy)
|
||||
context.fillEllipse(in: topEllipse)
|
||||
}
|
||||
|
||||
return formContext.generateImage()!
|
||||
}
|
||||
|
||||
public func messageBubbleImage(maxCornerRadius: CGFloat, minCornerRadius: CGFloat, incoming: Bool, fillColor: UIColor, strokeColor: UIColor, neighbors: MessageBubbleImageNeighbors, theme: PresentationThemeChat, wallpaper: TelegramWallpaper, knockout knockoutValue: Bool, mask: Bool = false, extendedEdges: Bool = false, onlyOutline: Bool = false) -> UIImage {
|
||||
let topLeftRadius: CGFloat
|
||||
let topRightRadius: CGFloat
|
||||
let bottomLeftRadius: CGFloat
|
||||
let bottomRightRadius: CGFloat
|
||||
let drawTail: Bool
|
||||
|
||||
switch neighbors {
|
||||
case .none:
|
||||
topLeftRadius = maxCornerRadius
|
||||
topRightRadius = maxCornerRadius
|
||||
bottomLeftRadius = maxCornerRadius
|
||||
bottomRightRadius = maxCornerRadius
|
||||
drawTail = true
|
||||
case .both:
|
||||
topLeftRadius = maxCornerRadius
|
||||
topRightRadius = minCornerRadius
|
||||
bottomLeftRadius = maxCornerRadius
|
||||
bottomRightRadius = minCornerRadius
|
||||
drawTail = false
|
||||
case .bottom:
|
||||
topLeftRadius = maxCornerRadius
|
||||
topRightRadius = minCornerRadius
|
||||
bottomLeftRadius = maxCornerRadius
|
||||
bottomRightRadius = maxCornerRadius
|
||||
drawTail = true
|
||||
case .side:
|
||||
topLeftRadius = maxCornerRadius
|
||||
topRightRadius = maxCornerRadius
|
||||
bottomLeftRadius = maxCornerRadius
|
||||
bottomRightRadius = maxCornerRadius
|
||||
drawTail = false
|
||||
case let .top(side):
|
||||
topLeftRadius = maxCornerRadius
|
||||
topRightRadius = side ? minCornerRadius : maxCornerRadius
|
||||
bottomLeftRadius = maxCornerRadius
|
||||
bottomRightRadius = minCornerRadius
|
||||
drawTail = false
|
||||
}
|
||||
|
||||
let fixedMainDiameter: CGFloat = 33.0
|
||||
let innerSize = CGSize(width: fixedMainDiameter + 6.0, height: fixedMainDiameter)
|
||||
let strokeInset: CGFloat = 1.0
|
||||
let sourceRawSize = CGSize(width: innerSize.width + strokeInset * 2.0, height: innerSize.height + strokeInset * 2.0)
|
||||
let additionalInset: CGFloat = 1.0
|
||||
let imageSize = CGSize(width: sourceRawSize.width + additionalInset * 2.0, height: sourceRawSize.height + additionalInset * 2.0)
|
||||
let outgoingStretchPoint: (x: Int, y: Int) = (Int(additionalInset + strokeInset + round(fixedMainDiameter / 2.0)) - 1, Int(additionalInset + strokeInset + round(fixedMainDiameter / 2.0)))
|
||||
let incomingStretchPoint: (x: Int, y: Int) = (Int(sourceRawSize.width) - outgoingStretchPoint.x + 1, outgoingStretchPoint.y)
|
||||
|
||||
let knockout = knockoutValue && !mask
|
||||
|
||||
let inset: CGFloat = 1.0
|
||||
let rawSize = imageSize
|
||||
|
||||
return generateImage(CGSize(width: 42.0 + inset * 2.0, height: diameter + inset * 2.0), contextGenerator: { rawSize, context in
|
||||
let bottomEllipse = CGRect(origin: CGPoint(x: 24.0, y: 16.0), size: CGSize(width: 27.0, height: 17.0))
|
||||
let topEllipse = CGRect(origin: CGPoint(x: 33.0, y: 14.0), size: CGSize(width: 23.0, height: 21.0))
|
||||
|
||||
let formContext = DrawingContext(size: imageSize)
|
||||
formContext.withFlippedContext { context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: rawSize))
|
||||
context.translateBy(x: additionalInset + strokeInset, y: additionalInset + strokeInset)
|
||||
|
||||
context.setFillColor(UIColor.black.cgColor)
|
||||
|
||||
context.move(to: CGPoint(x: 0.0, y: topLeftRadius))
|
||||
context.addArc(tangent1End: CGPoint(x: 0.0, y: 0.0), tangent2End: CGPoint(x: topLeftRadius, y: 0.0), radius: topLeftRadius)
|
||||
context.addLine(to: CGPoint(x: fixedMainDiameter - topRightRadius, y: 0.0))
|
||||
context.addArc(tangent1End: CGPoint(x: fixedMainDiameter, y: 0.0), tangent2End: CGPoint(x: fixedMainDiameter, y: topRightRadius), radius: topRightRadius)
|
||||
context.addLine(to: CGPoint(x: fixedMainDiameter, y: fixedMainDiameter - bottomRightRadius))
|
||||
context.addArc(tangent1End: CGPoint(x: fixedMainDiameter, y: fixedMainDiameter), tangent2End: CGPoint(x: fixedMainDiameter - bottomRightRadius, y: fixedMainDiameter), radius: bottomRightRadius)
|
||||
context.addLine(to: CGPoint(x: bottomLeftRadius, y: fixedMainDiameter))
|
||||
context.addArc(tangent1End: CGPoint(x: 0.0, y: fixedMainDiameter), tangent2End: CGPoint(x: 0.0, y: fixedMainDiameter - bottomLeftRadius), radius: bottomLeftRadius)
|
||||
context.addLine(to: CGPoint(x: 0.0, y: topLeftRadius))
|
||||
context.fillPath()
|
||||
|
||||
if drawTail {
|
||||
if maxCornerRadius >= minRadiusForFullTailCorner {
|
||||
context.move(to: CGPoint(x: bottomEllipse.minX, y: bottomEllipse.midY))
|
||||
context.addQuadCurve(to: CGPoint(x: bottomEllipse.midX, y: bottomEllipse.maxY), control: CGPoint(x: bottomEllipse.minX, y: bottomEllipse.maxY))
|
||||
context.addQuadCurve(to: CGPoint(x: bottomEllipse.maxX, y: bottomEllipse.midY), control: CGPoint(x: bottomEllipse.maxX, y: bottomEllipse.maxY))
|
||||
context.fillPath()
|
||||
} else {
|
||||
context.fill(CGRect(origin: CGPoint(x: bottomEllipse.minX - 2.0, y: bottomEllipse.midY), size: CGSize(width: bottomEllipse.width + 2.0, height: bottomEllipse.height / 2.0)))
|
||||
}
|
||||
context.fill(CGRect(origin: CGPoint(x: fixedMainDiameter / 2.0, y: fixedMainDiameter / 2.0), size: CGSize(width: fixedMainDiameter / 2.0, height: bottomEllipse.midY - fixedMainDiameter / 2.0)))
|
||||
context.setFillColor(UIColor.clear.cgColor)
|
||||
context.setBlendMode(.copy)
|
||||
context.fillEllipse(in: topEllipse)
|
||||
}
|
||||
}
|
||||
let formImage = formContext.generateImage()!
|
||||
|
||||
let outlineContext = DrawingContext(size: imageSize)
|
||||
outlineContext.withFlippedContext { context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: rawSize))
|
||||
context.translateBy(x: additionalInset + strokeInset, y: additionalInset + strokeInset)
|
||||
|
||||
context.setStrokeColor(UIColor.black.cgColor)
|
||||
let borderWidth: CGFloat = UIScreenPixel * 2.0
|
||||
context.setLineWidth(borderWidth)
|
||||
|
||||
let borderOffset: CGFloat = borderWidth / 2.0
|
||||
|
||||
context.move(to: CGPoint(x: -borderOffset, y: topLeftRadius + borderOffset))
|
||||
context.addArc(tangent1End: CGPoint(x: -borderOffset, y: -borderOffset), tangent2End: CGPoint(x: topLeftRadius + borderOffset, y: -borderOffset), radius: topLeftRadius + borderOffset * 2.0)
|
||||
context.addLine(to: CGPoint(x: fixedMainDiameter - topRightRadius - borderOffset, y: -borderOffset))
|
||||
context.addArc(tangent1End: CGPoint(x: fixedMainDiameter + borderOffset, y: -borderOffset), tangent2End: CGPoint(x: fixedMainDiameter + borderOffset, y: topRightRadius + borderOffset), radius: topRightRadius + borderOffset * 2.0)
|
||||
context.addLine(to: CGPoint(x: fixedMainDiameter + borderOffset, y: fixedMainDiameter - bottomRightRadius - borderOffset))
|
||||
context.addArc(tangent1End: CGPoint(x: fixedMainDiameter + borderOffset, y: fixedMainDiameter + borderOffset), tangent2End: CGPoint(x: fixedMainDiameter - bottomRightRadius - borderOffset, y: fixedMainDiameter + borderOffset), radius: bottomRightRadius + borderOffset * 2.0)
|
||||
context.addLine(to: CGPoint(x: bottomLeftRadius + borderOffset, y: fixedMainDiameter + borderOffset))
|
||||
context.addArc(tangent1End: CGPoint(x: -borderOffset, y: fixedMainDiameter + borderOffset), tangent2End: CGPoint(x: -borderOffset, y: fixedMainDiameter - bottomLeftRadius - borderOffset), radius: bottomLeftRadius + borderOffset * 2.0)
|
||||
context.closePath()
|
||||
context.strokePath()
|
||||
|
||||
if drawTail {
|
||||
let outlineBottomEllipse = bottomEllipse.insetBy(dx: -borderOffset, dy: -borderOffset)
|
||||
let outlineInnerTopEllipse = topEllipse.insetBy(dx: borderOffset, dy: borderOffset)
|
||||
let outlineTopEllipse = topEllipse.insetBy(dx: -borderOffset, dy: -borderOffset)
|
||||
|
||||
context.setBlendMode(.copy)
|
||||
context.setFillColor(UIColor.clear.cgColor)
|
||||
|
||||
if maxCornerRadius >= minRadiusForFullTailCorner {
|
||||
context.move(to: CGPoint(x: bottomEllipse.minX, y: bottomEllipse.midY))
|
||||
context.addQuadCurve(to: CGPoint(x: bottomEllipse.midX, y: bottomEllipse.maxY), control: CGPoint(x: bottomEllipse.minX, y: bottomEllipse.maxY))
|
||||
context.addQuadCurve(to: CGPoint(x: bottomEllipse.maxX, y: bottomEllipse.midY), control: CGPoint(x: bottomEllipse.maxX, y: bottomEllipse.maxY))
|
||||
context.fillPath()
|
||||
} else {
|
||||
context.fill(CGRect(origin: CGPoint(x: bottomEllipse.minX - 2.0, y: bottomEllipse.midY), size: CGSize(width: bottomEllipse.width + 2.0, height: bottomEllipse.height / 2.0)))
|
||||
}
|
||||
context.fill(CGRect(origin: CGPoint(x: fixedMainDiameter / 2.0, y: fixedMainDiameter / 2.0), size: CGSize(width: fixedMainDiameter / 2.0 + borderWidth, height: bottomEllipse.midY - fixedMainDiameter / 2.0)))
|
||||
|
||||
context.setBlendMode(.normal)
|
||||
context.move(to: CGPoint(x: fixedMainDiameter + borderOffset, y: fixedMainDiameter / 2.0))
|
||||
context.addLine(to: CGPoint(x: fixedMainDiameter + borderOffset, y: outlineBottomEllipse.midY))
|
||||
context.strokePath()
|
||||
|
||||
let bubbleTailContext = DrawingContext(size: imageSize)
|
||||
bubbleTailContext.withFlippedContext { context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: rawSize))
|
||||
context.translateBy(x: additionalInset + strokeInset, y: additionalInset + strokeInset)
|
||||
|
||||
context.setStrokeColor(UIColor.black.cgColor)
|
||||
context.setLineWidth(borderWidth)
|
||||
|
||||
if maxCornerRadius >= minRadiusForFullTailCorner {
|
||||
context.move(to: CGPoint(x: outlineBottomEllipse.minX, y: outlineBottomEllipse.midY))
|
||||
context.addQuadCurve(to: CGPoint(x: outlineBottomEllipse.midX, y: outlineBottomEllipse.maxY), control: CGPoint(x: outlineBottomEllipse.minX, y: outlineBottomEllipse.maxY))
|
||||
context.addQuadCurve(to: CGPoint(x: outlineBottomEllipse.maxX, y: outlineBottomEllipse.midY), control: CGPoint(x: outlineBottomEllipse.maxX, y: outlineBottomEllipse.maxY))
|
||||
} else {
|
||||
context.move(to: CGPoint(x: outlineBottomEllipse.minX - 2.0, y: outlineBottomEllipse.maxY))
|
||||
context.addLine(to: CGPoint(x: outlineBottomEllipse.minX, y: outlineBottomEllipse.maxY))
|
||||
context.addLine(to: CGPoint(x: outlineBottomEllipse.maxX, y: outlineBottomEllipse.maxY))
|
||||
}
|
||||
context.strokePath()
|
||||
context.setFillColor(UIColor.clear.cgColor)
|
||||
context.setBlendMode(.copy)
|
||||
context.fillEllipse(in: outlineInnerTopEllipse)
|
||||
|
||||
context.move(to: CGPoint(x: 0.0, y: topLeftRadius))
|
||||
context.addArc(tangent1End: CGPoint(x: 0.0, y: 0.0), tangent2End: CGPoint(x: topLeftRadius, y: 0.0), radius: topLeftRadius)
|
||||
context.addLine(to: CGPoint(x: fixedMainDiameter - topRightRadius, y: 0.0))
|
||||
context.addArc(tangent1End: CGPoint(x: fixedMainDiameter, y: 0.0), tangent2End: CGPoint(x: fixedMainDiameter, y: topRightRadius), radius: topRightRadius)
|
||||
context.addLine(to: CGPoint(x: fixedMainDiameter, y: fixedMainDiameter - bottomRightRadius))
|
||||
context.addArc(tangent1End: CGPoint(x: fixedMainDiameter, y: fixedMainDiameter), tangent2End: CGPoint(x: fixedMainDiameter - bottomRightRadius, y: fixedMainDiameter), radius: bottomRightRadius)
|
||||
context.addLine(to: CGPoint(x: bottomLeftRadius, y: fixedMainDiameter))
|
||||
context.addArc(tangent1End: CGPoint(x: 0.0, y: fixedMainDiameter), tangent2End: CGPoint(x: 0.0, y: fixedMainDiameter - bottomLeftRadius), radius: bottomLeftRadius)
|
||||
context.addLine(to: CGPoint(x: 0.0, y: topLeftRadius))
|
||||
context.fillPath()
|
||||
|
||||
let bottomEllipseMask = generateImage(bottomEllipse.insetBy(dx: -1.0, dy: -1.0).size, contextGenerator: { size, context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
context.setFillColor(UIColor.black.cgColor)
|
||||
if maxCornerRadius >= minRadiusForFullTailCorner {
|
||||
context.fillEllipse(in: CGRect(origin: CGPoint(x: 1.0 - borderOffset, y: 1.0 - borderOffset), size: CGSize(width: outlineBottomEllipse.width, height: outlineBottomEllipse.height)))
|
||||
} else {
|
||||
context.fill(CGRect(origin: CGPoint(x: 1.0 - borderOffset, y: 1.0 - borderOffset), size: CGSize(width: outlineBottomEllipse.width, height: outlineBottomEllipse.height)))
|
||||
}
|
||||
context.clear(CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: size.height / 2.0)))
|
||||
})!
|
||||
|
||||
context.clip(to: bottomEllipse.insetBy(dx: -1.0, dy: -1.0), mask: bottomEllipseMask.cgImage!)
|
||||
context.strokeEllipse(in: outlineInnerTopEllipse)
|
||||
context.resetClip()
|
||||
}
|
||||
|
||||
context.translateBy(x: -(additionalInset + strokeInset), y: -(additionalInset + strokeInset))
|
||||
context.draw(bubbleTailContext.generateImage()!.cgImage!, in: CGRect(origin: CGPoint(), size: rawSize))
|
||||
context.translateBy(x: additionalInset + strokeInset, y: additionalInset + strokeInset)
|
||||
}
|
||||
}
|
||||
let outlineImage = outlineContext.generateImage()!
|
||||
|
||||
let drawingContext = DrawingContext(size: imageSize)
|
||||
drawingContext.withFlippedContext { context in
|
||||
var drawWithClearColor = false
|
||||
|
||||
if knockout {
|
||||
@ -48,94 +287,33 @@ public func messageBubbleImage(incoming: Bool, fillColor: UIColor, strokeColor:
|
||||
context.clear(CGRect(origin: CGPoint(), size: rawSize))
|
||||
}
|
||||
|
||||
let additionalOffset: CGFloat
|
||||
switch neighbors {
|
||||
case .none, .bottom:
|
||||
additionalOffset = 0.0
|
||||
case .both, .side, .top:
|
||||
additionalOffset = 6.0
|
||||
}
|
||||
|
||||
context.translateBy(x: rawSize.width / 2.0, y: rawSize.height / 2.0)
|
||||
context.scaleBy(x: incoming ? 1.0 : -1.0, y: -1.0)
|
||||
context.translateBy(x: -rawSize.width / 2.0, y: -rawSize.height / 2.0)
|
||||
|
||||
context.translateBy(x: additionalOffset + 0.5, y: 0.5)
|
||||
|
||||
let size = CGSize(width: rawSize.width - inset * 2.0, height: rawSize.height - inset * 2.0)
|
||||
context.translateBy(x: inset, y: inset)
|
||||
|
||||
var lineWidth: CGFloat = 1.0
|
||||
|
||||
if drawWithClearColor {
|
||||
context.setBlendMode(.copy)
|
||||
context.setFillColor(UIColor.clear.cgColor)
|
||||
context.setStrokeColor(UIColor.clear.cgColor)
|
||||
} else {
|
||||
context.setBlendMode(.normal)
|
||||
context.setFillColor(fillColor.cgColor)
|
||||
context.setLineWidth(lineWidth)
|
||||
context.setStrokeColor(strokeColor.cgColor)
|
||||
}
|
||||
|
||||
if onlyOutline {
|
||||
if knockout {
|
||||
lineWidth = max(UIScreenPixel, 1.0 - 0.5)
|
||||
}
|
||||
context.setLineWidth(lineWidth)
|
||||
context.setStrokeColor(strokeColor.cgColor)
|
||||
context.saveGState()
|
||||
|
||||
context.translateBy(x: rawSize.width / 2.0, y: rawSize.height / 2.0)
|
||||
context.scaleBy(x: incoming ? -1.0 : 1.0, y: -1.0)
|
||||
context.translateBy(x: -rawSize.width / 2.0, y: -rawSize.height / 2.0)
|
||||
|
||||
if !onlyOutline {
|
||||
context.clip(to: CGRect(origin: CGPoint(), size: rawSize), mask: formImage.cgImage!)
|
||||
context.fill(CGRect(origin: CGPoint(), size: rawSize))
|
||||
} else {
|
||||
context.setFillColor(strokeColor.cgColor)
|
||||
context.clip(to: CGRect(origin: CGPoint(), size: rawSize), mask: outlineImage.cgImage!)
|
||||
context.fill(CGRect(origin: CGPoint(), size: rawSize))
|
||||
}
|
||||
|
||||
switch neighbors {
|
||||
case .none:
|
||||
if onlyOutline {
|
||||
let _ = try? drawSvgPath(context, path: "M6,17.5 C6,7.83289181 13.8350169,0 23.5,0 C33.1671082,0 41,7.83501688 41,17.5 C41,27.1671082 33.1649831,35 23.5,35 C19.2941198,35 15.4354328,33.5169337 12.4179496,31.0453367 C9.05531719,34.9894816 -2.41102995e-08,35 0,35 C5.972003,31.5499861 6,26.8616169 6,26.8616169 L6,17.5 L6,17.5 ")
|
||||
context.strokePath()
|
||||
} else {
|
||||
let _ = try? drawSvgPath(context, path: "M6,17.5 C6,7.83289181 13.8350169,0 23.5,0 C33.1671082,0 41,7.83501688 41,17.5 C41,27.1671082 33.1649831,35 23.5,35 C19.2941198,35 15.4354328,33.5169337 12.4179496,31.0453367 C9.05531719,34.9894816 -2.41102995e-08,35 0,35 C5.972003,31.5499861 6,26.8616169 6,26.8616169 L6,17.5 L6,17.5 ")
|
||||
context.fillPath()
|
||||
}
|
||||
case .side:
|
||||
if onlyOutline {
|
||||
context.strokeEllipse(in: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: 35.0, height: 35.0)))
|
||||
} else {
|
||||
context.fillEllipse(in: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: 35.0, height: 35.0)))
|
||||
}
|
||||
case let .top(side):
|
||||
if side {
|
||||
if onlyOutline {
|
||||
let _ = try? drawSvgPath(context, path: "M17.5,0 L17.5,0 C27.1649831,-1.7754286e-15 35,7.83501688 35,17.5 L35,29 C35,32.3137085 32.3137085,35 29,35 L6,35 C2.6862915,35 4.05812251e-16,32.3137085 0,29 L0,17.5 C-1.18361906e-15,7.83501688 7.83501688,1.7754286e-15 17.5,0 ")
|
||||
context.strokePath()
|
||||
} else {
|
||||
let _ = try? drawSvgPath(context, path: "M17.5,0 L17.5,0 C27.1649831,-1.7754286e-15 35,7.83501688 35,17.5 L35,29 C35,32.3137085 32.3137085,35 29,35 L6,35 C2.6862915,35 4.05812251e-16,32.3137085 0,29 L0,17.5 C-1.18361906e-15,7.83501688 7.83501688,1.7754286e-15 17.5,0 ")
|
||||
context.fillPath()
|
||||
}
|
||||
} else {
|
||||
if onlyOutline {
|
||||
let _ = try? drawSvgPath(context, path: "M35,17.5 C35,7.83501688 27.1671082,0 17.5,0 L17.5,0 C7.83501688,0 0,7.83289181 0,17.5 L0,29.0031815 C0,32.3151329 2.6882755,35 5.99681848,35 L17.5,35 C27.1649831,35 35,27.1671082 35,17.5 L35,17.5 L35,17.5 ")
|
||||
context.strokePath()
|
||||
} else {
|
||||
let _ = try? drawSvgPath(context, path: "M35,17.5 C35,7.83501688 27.1671082,0 17.5,0 L17.5,0 C7.83501688,0 0,7.83289181 0,17.5 L0,29.0031815 C0,32.3151329 2.6882755,35 5.99681848,35 L17.5,35 C27.1649831,35 35,27.1671082 35,17.5 L35,17.5 L35,17.5 ")
|
||||
context.fillPath()
|
||||
}
|
||||
}
|
||||
case .bottom:
|
||||
if onlyOutline {
|
||||
let _ = try? drawSvgPath(context, path: "M6,17.5 L6,5.99681848 C6,2.6882755 8.68486709,0 11.9968185,0 L23.5,0 C33.1671082,0 41,7.83501688 41,17.5 C41,27.1671082 33.1649831,35 23.5,35 C19.2941198,35 15.4354328,33.5169337 12.4179496,31.0453367 C9.05531719,34.9894816 -2.41103066e-08,35 0,35 C5.972003,31.5499861 6,26.8616169 6,26.8616169 L6,17.5 L6,17.5 ")
|
||||
context.strokePath()
|
||||
} else {
|
||||
let _ = try? drawSvgPath(context, path: "M6,17.5 L6,5.99681848 C6,2.6882755 8.68486709,0 11.9968185,0 L23.5,0 C33.1671082,0 41,7.83501688 41,17.5 C41,27.1671082 33.1649831,35 23.5,35 C19.2941198,35 15.4354328,33.5169337 12.4179496,31.0453367 C9.05531719,34.9894816 -2.41103066e-08,35 0,35 C5.972003,31.5499861 6,26.8616169 6,26.8616169 L6,17.5 L6,17.5 ")
|
||||
context.fillPath()
|
||||
}
|
||||
case .both:
|
||||
if onlyOutline {
|
||||
let _ = try? drawSvgPath(context, path: "M35,17.5 C35,7.83501688 27.1671082,0 17.5,0 L5.99681848,0 C2.68486709,0 0,2.6882755 0,5.99681848 L0,29.0031815 C0,32.3151329 2.6882755,35 5.99681848,35 L17.5,35 C27.1649831,35 35,27.1671082 35,17.5 L35,17.5 L35,17.5 ")
|
||||
context.strokePath()
|
||||
} else {
|
||||
let _ = try? drawSvgPath(context, path: "M35,17.5 C35,7.83501688 27.1671082,0 17.5,0 L5.99681848,0 C2.68486709,0 0,2.6882755 0,5.99681848 L0,29.0031815 C0,32.3151329 2.6882755,35 5.99681848,35 L17.5,35 C27.1649831,35 35,27.1671082 35,17.5 L35,17.5 L35,17.5 ")
|
||||
context.fillPath()
|
||||
}
|
||||
}
|
||||
})!.stretchableImage(withLeftCapWidth: incoming ? Int(inset + corner + diameter / 2.0 - 1.0) : Int(inset + diameter / 2.0), topCapHeight: Int(inset + diameter / 2.0))
|
||||
context.restoreGState()
|
||||
}
|
||||
|
||||
return drawingContext.generateImage()!.stretchableImage(withLeftCapWidth: incoming ? incomingStretchPoint.x : outgoingStretchPoint.x, topCapHeight: incoming ? incomingStretchPoint.y : outgoingStretchPoint.y)
|
||||
}
|
||||
|
||||
public enum MessageBubbleActionButtonPosition {
|
||||
|
@ -48,12 +48,25 @@ public enum PresentationDateFormat {
|
||||
case dayFirst
|
||||
}
|
||||
|
||||
public struct PresentationChatBubbleCorners: Equatable, Hashable {
|
||||
public var mainRadius: CGFloat
|
||||
public var auxiliaryRadius: CGFloat
|
||||
public var mergeBubbleCorners: Bool
|
||||
|
||||
public init(mainRadius: CGFloat, auxiliaryRadius: CGFloat, mergeBubbleCorners: Bool) {
|
||||
self.mainRadius = mainRadius
|
||||
self.auxiliaryRadius = auxiliaryRadius
|
||||
self.mergeBubbleCorners = mergeBubbleCorners
|
||||
}
|
||||
}
|
||||
|
||||
public final class PresentationData: Equatable {
|
||||
public let strings: PresentationStrings
|
||||
public let theme: PresentationTheme
|
||||
public let autoNightModeTriggered: Bool
|
||||
public let chatWallpaper: TelegramWallpaper
|
||||
public let chatFontSize: PresentationFontSize
|
||||
public let chatBubbleCorners: PresentationChatBubbleCorners
|
||||
public let listsFontSize: PresentationFontSize
|
||||
public let dateTimeFormat: PresentationDateTimeFormat
|
||||
public let nameDisplayOrder: PresentationPersonNameOrder
|
||||
@ -61,12 +74,13 @@ public final class PresentationData: Equatable {
|
||||
public let disableAnimations: Bool
|
||||
public let largeEmoji: Bool
|
||||
|
||||
public init(strings: PresentationStrings, theme: PresentationTheme, autoNightModeTriggered: Bool, chatWallpaper: TelegramWallpaper, chatFontSize: PresentationFontSize, listsFontSize: PresentationFontSize, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, nameSortOrder: PresentationPersonNameOrder, disableAnimations: Bool, largeEmoji: Bool) {
|
||||
public init(strings: PresentationStrings, theme: PresentationTheme, autoNightModeTriggered: Bool, chatWallpaper: TelegramWallpaper, chatFontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, listsFontSize: PresentationFontSize, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, nameSortOrder: PresentationPersonNameOrder, disableAnimations: Bool, largeEmoji: Bool) {
|
||||
self.strings = strings
|
||||
self.theme = theme
|
||||
self.autoNightModeTriggered = autoNightModeTriggered
|
||||
self.chatWallpaper = chatWallpaper
|
||||
self.chatFontSize = chatFontSize
|
||||
self.chatBubbleCorners = chatBubbleCorners
|
||||
self.listsFontSize = listsFontSize
|
||||
self.dateTimeFormat = dateTimeFormat
|
||||
self.nameDisplayOrder = nameDisplayOrder
|
||||
@ -76,7 +90,7 @@ public final class PresentationData: Equatable {
|
||||
}
|
||||
|
||||
public static func ==(lhs: PresentationData, rhs: PresentationData) -> Bool {
|
||||
return lhs.strings === rhs.strings && lhs.theme === rhs.theme && lhs.autoNightModeTriggered == rhs.autoNightModeTriggered && lhs.chatWallpaper == rhs.chatWallpaper && lhs.chatFontSize == rhs.chatFontSize && lhs.listsFontSize == rhs.listsFontSize && lhs.dateTimeFormat == rhs.dateTimeFormat && lhs.disableAnimations == rhs.disableAnimations && lhs.largeEmoji == rhs.largeEmoji
|
||||
return lhs.strings === rhs.strings && lhs.theme === rhs.theme && lhs.autoNightModeTriggered == rhs.autoNightModeTriggered && lhs.chatWallpaper == rhs.chatWallpaper && lhs.chatFontSize == rhs.chatFontSize && lhs.chatBubbleCorners == rhs.chatBubbleCorners && lhs.listsFontSize == rhs.listsFontSize && lhs.dateTimeFormat == rhs.dateTimeFormat && lhs.disableAnimations == rhs.disableAnimations && lhs.largeEmoji == rhs.largeEmoji
|
||||
}
|
||||
}
|
||||
|
||||
@ -268,7 +282,9 @@ public func currentPresentationDataAndSettings(accountManager: AccountManager, s
|
||||
|
||||
let (chatFontSize, listsFontSize) = resolveFontSize(settings: themeSettings)
|
||||
|
||||
return InitialPresentationDataAndSettings(presentationData: PresentationData(strings: stringsValue, theme: theme, autoNightModeTriggered: autoNightModeTriggered, chatWallpaper: effectiveChatWallpaper, chatFontSize: chatFontSize, listsFontSize: listsFontSize, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, nameSortOrder: nameSortOrder, disableAnimations: themeSettings.disableAnimations, largeEmoji: themeSettings.largeEmoji), automaticMediaDownloadSettings: automaticMediaDownloadSettings, autodownloadSettings: autodownloadSettings, callListSettings: callListSettings, inAppNotificationSettings: inAppNotificationSettings, mediaInputSettings: mediaInputSettings, experimentalUISettings: experimentalUISettings)
|
||||
let chatBubbleCorners = PresentationChatBubbleCorners(mainRadius: CGFloat(themeSettings.chatBubbleSettings.mainRadius), auxiliaryRadius: CGFloat(themeSettings.chatBubbleSettings.auxiliaryRadius), mergeBubbleCorners: themeSettings.chatBubbleSettings.mergeBubbleCorners)
|
||||
|
||||
return InitialPresentationDataAndSettings(presentationData: PresentationData(strings: stringsValue, theme: theme, autoNightModeTriggered: autoNightModeTriggered, chatWallpaper: effectiveChatWallpaper, chatFontSize: chatFontSize, chatBubbleCorners: chatBubbleCorners, listsFontSize: listsFontSize, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, nameSortOrder: nameSortOrder, disableAnimations: themeSettings.disableAnimations, largeEmoji: themeSettings.largeEmoji), automaticMediaDownloadSettings: automaticMediaDownloadSettings, autodownloadSettings: autodownloadSettings, callListSettings: callListSettings, inAppNotificationSettings: inAppNotificationSettings, mediaInputSettings: mediaInputSettings, experimentalUISettings: experimentalUISettings)
|
||||
}
|
||||
}
|
||||
|
||||
@ -601,7 +617,9 @@ public func updatedPresentationData(accountManager: AccountManager, applicationI
|
||||
|
||||
let (chatFontSize, listsFontSize) = resolveFontSize(settings: themeSettings)
|
||||
|
||||
return PresentationData(strings: stringsValue, theme: themeValue, autoNightModeTriggered: autoNightModeTriggered, chatWallpaper: effectiveChatWallpaper, chatFontSize: chatFontSize, listsFontSize: listsFontSize, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, nameSortOrder: nameSortOrder, disableAnimations: themeSettings.disableAnimations, largeEmoji: themeSettings.largeEmoji)
|
||||
let chatBubbleCorners = PresentationChatBubbleCorners(mainRadius: CGFloat(themeSettings.chatBubbleSettings.mainRadius), auxiliaryRadius: CGFloat(themeSettings.chatBubbleSettings.auxiliaryRadius), mergeBubbleCorners: themeSettings.chatBubbleSettings.mergeBubbleCorners)
|
||||
|
||||
return PresentationData(strings: stringsValue, theme: themeValue, autoNightModeTriggered: autoNightModeTriggered, chatWallpaper: effectiveChatWallpaper, chatFontSize: chatFontSize, chatBubbleCorners: chatBubbleCorners, listsFontSize: listsFontSize, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, nameSortOrder: nameSortOrder, disableAnimations: themeSettings.disableAnimations, largeEmoji: themeSettings.largeEmoji)
|
||||
}
|
||||
} else {
|
||||
return .complete()
|
||||
@ -634,15 +652,21 @@ public func defaultPresentationData() -> PresentationData {
|
||||
|
||||
let (chatFontSize, listsFontSize) = resolveFontSize(settings: themeSettings)
|
||||
|
||||
return PresentationData(strings: defaultPresentationStrings, theme: defaultPresentationTheme, autoNightModeTriggered: false, chatWallpaper: .builtin(WallpaperSettings()), chatFontSize: chatFontSize, listsFontSize: listsFontSize, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, nameSortOrder: nameSortOrder, disableAnimations: themeSettings.disableAnimations, largeEmoji: themeSettings.largeEmoji)
|
||||
let chatBubbleCorners = PresentationChatBubbleCorners(mainRadius: CGFloat(themeSettings.chatBubbleSettings.mainRadius), auxiliaryRadius: CGFloat(themeSettings.chatBubbleSettings.auxiliaryRadius), mergeBubbleCorners: themeSettings.chatBubbleSettings.mergeBubbleCorners)
|
||||
|
||||
return PresentationData(strings: defaultPresentationStrings, theme: defaultPresentationTheme, autoNightModeTriggered: false, chatWallpaper: .builtin(WallpaperSettings()), chatFontSize: chatFontSize, chatBubbleCorners: chatBubbleCorners, listsFontSize: listsFontSize, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, nameSortOrder: nameSortOrder, disableAnimations: themeSettings.disableAnimations, largeEmoji: themeSettings.largeEmoji)
|
||||
}
|
||||
|
||||
public extension PresentationData {
|
||||
func withFontSizes(chatFontSize: PresentationFontSize, listsFontSize: PresentationFontSize) -> PresentationData {
|
||||
return PresentationData(strings: self.strings, theme: self.theme, autoNightModeTriggered: self.autoNightModeTriggered, chatWallpaper: self.chatWallpaper, chatFontSize: chatFontSize, listsFontSize: listsFontSize, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, nameSortOrder: self.nameSortOrder, disableAnimations: self.disableAnimations, largeEmoji: self.largeEmoji)
|
||||
return PresentationData(strings: self.strings, theme: self.theme, autoNightModeTriggered: self.autoNightModeTriggered, chatWallpaper: self.chatWallpaper, chatFontSize: chatFontSize, chatBubbleCorners: self.chatBubbleCorners, listsFontSize: listsFontSize, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, nameSortOrder: self.nameSortOrder, disableAnimations: self.disableAnimations, largeEmoji: self.largeEmoji)
|
||||
}
|
||||
|
||||
func withChatBubbleCorners(_ chatBubbleCorners: PresentationChatBubbleCorners) -> PresentationData {
|
||||
return PresentationData(strings: self.strings, theme: self.theme, autoNightModeTriggered: self.autoNightModeTriggered, chatWallpaper: self.chatWallpaper, chatFontSize: self.chatFontSize, chatBubbleCorners: chatBubbleCorners, listsFontSize: self.listsFontSize, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, nameSortOrder: self.nameSortOrder, disableAnimations: self.disableAnimations, largeEmoji: self.largeEmoji)
|
||||
}
|
||||
|
||||
func withStrings(_ strings: PresentationStrings) -> PresentationData {
|
||||
return PresentationData(strings: strings, theme: self.theme, autoNightModeTriggered: self.autoNightModeTriggered, chatWallpaper: self.chatWallpaper, chatFontSize: self.chatFontSize, listsFontSize: self.listsFontSize, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, nameSortOrder: self.nameSortOrder, disableAnimations: self.disableAnimations, largeEmoji: self.largeEmoji)
|
||||
return PresentationData(strings: strings, theme: self.theme, autoNightModeTriggered: self.autoNightModeTriggered, chatWallpaper: self.chatWallpaper, chatFontSize: self.chatFontSize, chatBubbleCorners: chatBubbleCorners, listsFontSize: self.listsFontSize, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, nameSortOrder: self.nameSortOrder, disableAnimations: self.disableAnimations, largeEmoji: self.largeEmoji)
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1182,6 +1182,10 @@ public final class PresentationTheme: Equatable {
|
||||
return self.resourceCache.object(key, self, generate)
|
||||
}
|
||||
|
||||
public func object(_ key: PresentationResourceParameterKey, _ generate: (PresentationTheme) -> AnyObject?) -> AnyObject? {
|
||||
return self.resourceCache.parameterObject(key, self, generate)
|
||||
}
|
||||
|
||||
public static func ==(lhs: PresentationTheme, rhs: PresentationTheme) -> Bool {
|
||||
return lhs === rhs
|
||||
}
|
||||
|
@ -160,7 +160,7 @@ public final class PrincipalThemeEssentialGraphics {
|
||||
public let incomingBubbleGradientImage: UIImage?
|
||||
public let outgoingBubbleGradientImage: UIImage?
|
||||
|
||||
init(mediaBox: MediaBox, presentationTheme: PresentationTheme, wallpaper initialWallpaper: TelegramWallpaper, preview: Bool = false, knockoutMode: Bool) {
|
||||
init(mediaBox: MediaBox, presentationTheme: PresentationTheme, wallpaper initialWallpaper: TelegramWallpaper, preview: Bool = false, knockoutMode: Bool, bubbleCorners: PresentationChatBubbleCorners) {
|
||||
let theme = presentationTheme.chat
|
||||
var wallpaper = initialWallpaper
|
||||
|
||||
@ -215,28 +215,31 @@ public final class PrincipalThemeEssentialGraphics {
|
||||
|
||||
let serviceColor = serviceMessageColorComponents(chatTheme: theme, wallpaper: wallpaper)
|
||||
|
||||
let maxCornerRadius = bubbleCorners.mainRadius
|
||||
let minCornerRadius = bubbleCorners.mergeBubbleCorners ? bubbleCorners.auxiliaryRadius : bubbleCorners.mainRadius
|
||||
|
||||
let emptyImage = UIImage()
|
||||
if preview {
|
||||
self.chatMessageBackgroundIncomingMaskImage = messageBubbleImage(incoming: true, fillColor: UIColor.black, strokeColor: UIColor.clear, neighbors: .none, theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true)
|
||||
self.chatMessageBackgroundIncomingImage = messageBubbleImage(incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .none, theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundIncomingOutlineImage = messageBubbleImage(incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .none, theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true, onlyOutline: true)
|
||||
self.chatMessageBackgroundOutgoingMaskImage = messageBubbleImage(incoming: false, fillColor: .black, strokeColor: .clear, neighbors: .none, theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingImage = messageBubbleImage(incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .none, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingOutlineImage = messageBubbleImage(incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .none, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true, onlyOutline: true)
|
||||
self.chatMessageBackgroundIncomingMaskImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: UIColor.black, strokeColor: UIColor.clear, neighbors: .none, theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true)
|
||||
self.chatMessageBackgroundIncomingImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .none, theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundIncomingOutlineImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .none, theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true, onlyOutline: true)
|
||||
self.chatMessageBackgroundOutgoingMaskImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: .black, strokeColor: .clear, neighbors: .none, theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .none, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingOutlineImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .none, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true, onlyOutline: true)
|
||||
self.checkBubbleFullImage = generateCheckImage(partial: false, color: theme.message.outgoingCheckColor, width: 11.0)!
|
||||
self.checkBubblePartialImage = generateCheckImage(partial: true, color: theme.message.outgoingCheckColor, width: 11.0)!
|
||||
self.chatMessageBackgroundIncomingHighlightedImage = emptyImage
|
||||
self.chatMessageBackgroundIncomingMergedTopMaskImage = emptyImage
|
||||
self.chatMessageBackgroundIncomingMergedTopImage = messageBubbleImage(incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .top(side: false), theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundIncomingMergedTopOutlineImage = messageBubbleImage(incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .top(side: false), theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true, onlyOutline: true)
|
||||
self.chatMessageBackgroundIncomingMergedTopImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .top(side: false), theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundIncomingMergedTopOutlineImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .top(side: false), theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true, onlyOutline: true)
|
||||
self.chatMessageBackgroundIncomingMergedTopHighlightedImage = emptyImage
|
||||
self.chatMessageBackgroundIncomingMergedTopSideMaskImage = emptyImage
|
||||
self.chatMessageBackgroundIncomingMergedTopSideImage = emptyImage
|
||||
self.chatMessageBackgroundIncomingMergedTopSideOutlineImage = emptyImage
|
||||
self.chatMessageBackgroundIncomingMergedTopSideHighlightedImage = emptyImage
|
||||
self.chatMessageBackgroundIncomingMergedBottomMaskImage = emptyImage
|
||||
self.chatMessageBackgroundIncomingMergedBottomImage = messageBubbleImage(incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .bottom, theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundIncomingMergedBottomOutlineImage = messageBubbleImage(incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .bottom, theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true, onlyOutline: true)
|
||||
self.chatMessageBackgroundIncomingMergedBottomImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .bottom, theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundIncomingMergedBottomOutlineImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .bottom, theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true, onlyOutline: true)
|
||||
self.chatMessageBackgroundIncomingMergedBottomHighlightedImage = emptyImage
|
||||
self.chatMessageBackgroundIncomingMergedBothMaskImage = emptyImage
|
||||
self.chatMessageBackgroundIncomingMergedBothImage = emptyImage
|
||||
@ -247,21 +250,21 @@ public final class PrincipalThemeEssentialGraphics {
|
||||
self.chatMessageBackgroundIncomingMergedSideOutlineImage = emptyImage
|
||||
self.chatMessageBackgroundIncomingMergedSideHighlightedImage = emptyImage
|
||||
self.chatMessageBackgroundOutgoingHighlightedImage = emptyImage
|
||||
self.chatMessageBackgroundOutgoingMergedTopMaskImage = messageBubbleImage(incoming: false, fillColor: .black, strokeColor: .clear, neighbors: .top(side: false), theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingMergedTopImage = messageBubbleImage(incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .top(side: false), theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingMergedTopOutlineImage = messageBubbleImage(incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .top(side: false), theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true, onlyOutline: true)
|
||||
self.chatMessageBackgroundOutgoingMergedTopMaskImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: .black, strokeColor: .clear, neighbors: .top(side: false), theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingMergedTopImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .top(side: false), theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingMergedTopOutlineImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .top(side: false), theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true, onlyOutline: true)
|
||||
self.chatMessageBackgroundOutgoingMergedTopHighlightedImage = emptyImage
|
||||
self.chatMessageBackgroundOutgoingMergedTopSideMaskImage = emptyImage
|
||||
self.chatMessageBackgroundOutgoingMergedTopSideImage = emptyImage
|
||||
self.chatMessageBackgroundOutgoingMergedTopSideOutlineImage = emptyImage
|
||||
self.chatMessageBackgroundOutgoingMergedTopSideHighlightedImage = emptyImage
|
||||
self.chatMessageBackgroundOutgoingMergedBottomMaskImage = messageBubbleImage(incoming: false, fillColor: .black, strokeColor: .clear, neighbors: .bottom, theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingMergedBottomImage = messageBubbleImage(incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .bottom, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingMergedBottomOutlineImage = messageBubbleImage(incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .bottom, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true, onlyOutline: true)
|
||||
self.chatMessageBackgroundOutgoingMergedBottomMaskImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: .black, strokeColor: .clear, neighbors: .bottom, theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingMergedBottomImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .bottom, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingMergedBottomOutlineImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .bottom, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true, onlyOutline: true)
|
||||
self.chatMessageBackgroundOutgoingMergedBottomHighlightedImage = emptyImage
|
||||
self.chatMessageBackgroundOutgoingMergedBothMaskImage = messageBubbleImage(incoming: false, fillColor: .black, strokeColor: .clear, neighbors: .both, theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingMergedBothImage = messageBubbleImage(incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .both, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingMergedBothOutlineImage = messageBubbleImage(incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .both, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true, onlyOutline: true)
|
||||
self.chatMessageBackgroundOutgoingMergedBothMaskImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: .black, strokeColor: .clear, neighbors: .both, theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingMergedBothImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .both, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingMergedBothOutlineImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .both, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true, onlyOutline: true)
|
||||
self.chatMessageBackgroundOutgoingMergedBothHighlightedImage = emptyImage
|
||||
self.chatMessageBackgroundOutgoingMergedSideMaskImage = emptyImage
|
||||
self.chatMessageBackgroundOutgoingMergedSideImage = emptyImage
|
||||
@ -288,56 +291,56 @@ public final class PrincipalThemeEssentialGraphics {
|
||||
self.radialIndicatorFileIconIncoming = emptyImage
|
||||
self.radialIndicatorFileIconOutgoing = emptyImage
|
||||
} else {
|
||||
self.chatMessageBackgroundIncomingMaskImage = messageBubbleImage(incoming: true, fillColor: .black, strokeColor: .clear, neighbors: .none, theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true)
|
||||
self.chatMessageBackgroundIncomingImage = messageBubbleImage(incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .none, theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundIncomingOutlineImage = messageBubbleImage(incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .none, theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true, onlyOutline: true)
|
||||
self.chatMessageBackgroundIncomingHighlightedImage = messageBubbleImage(incoming: true, fillColor: incoming.highlightedFill, strokeColor: incoming.stroke, neighbors: .none, theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundIncomingMergedTopMaskImage = messageBubbleImage(incoming: true, fillColor: .black, strokeColor: .clear, neighbors: .top(side: false), theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true)
|
||||
self.chatMessageBackgroundIncomingMergedTopImage = messageBubbleImage(incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .top(side: false), theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundIncomingMergedTopOutlineImage = messageBubbleImage(incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .top(side: false), theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true, onlyOutline: true)
|
||||
self.chatMessageBackgroundIncomingMergedTopHighlightedImage = messageBubbleImage(incoming: true, fillColor: incoming.highlightedFill, strokeColor: incoming.stroke, neighbors: .top(side: false), theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundIncomingMergedTopSideMaskImage = messageBubbleImage(incoming: true, fillColor: .black, strokeColor: .clear, neighbors: .top(side: true), theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true)
|
||||
self.chatMessageBackgroundIncomingMergedTopSideImage = messageBubbleImage(incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .top(side: true), theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundIncomingMergedTopSideOutlineImage = messageBubbleImage(incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .top(side: true), theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true, onlyOutline: true)
|
||||
self.chatMessageBackgroundIncomingMergedTopSideHighlightedImage = messageBubbleImage(incoming: true, fillColor: incoming.highlightedFill, strokeColor: incoming.stroke, neighbors: .top(side: true), theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundIncomingMergedBottomMaskImage = messageBubbleImage(incoming: true, fillColor: .black, strokeColor: .clear, neighbors: .bottom, theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true)
|
||||
self.chatMessageBackgroundIncomingMergedBottomImage = messageBubbleImage(incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .bottom, theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundIncomingMergedBottomOutlineImage = messageBubbleImage(incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .bottom, theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true, onlyOutline: true)
|
||||
self.chatMessageBackgroundIncomingMergedBottomHighlightedImage = messageBubbleImage(incoming: true, fillColor: incoming.highlightedFill, strokeColor: incoming.stroke, neighbors: .bottom, theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundIncomingMergedBothMaskImage = messageBubbleImage(incoming: true, fillColor: .black, strokeColor: .clear, neighbors: .both, theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true)
|
||||
self.chatMessageBackgroundIncomingMergedBothImage = messageBubbleImage(incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .both, theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundIncomingMergedBothOutlineImage = messageBubbleImage(incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .both, theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true, onlyOutline: true)
|
||||
self.chatMessageBackgroundIncomingMergedBothHighlightedImage = messageBubbleImage(incoming: true, fillColor: incoming.highlightedFill, strokeColor: incoming.stroke, neighbors: .both, theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundIncomingMaskImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: .black, strokeColor: .clear, neighbors: .none, theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true)
|
||||
self.chatMessageBackgroundIncomingImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .none, theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundIncomingOutlineImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .none, theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true, onlyOutline: true)
|
||||
self.chatMessageBackgroundIncomingHighlightedImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: incoming.highlightedFill, strokeColor: incoming.stroke, neighbors: .none, theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundIncomingMergedTopMaskImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: .black, strokeColor: .clear, neighbors: .top(side: false), theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true)
|
||||
self.chatMessageBackgroundIncomingMergedTopImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .top(side: false), theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundIncomingMergedTopOutlineImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .top(side: false), theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true, onlyOutline: true)
|
||||
self.chatMessageBackgroundIncomingMergedTopHighlightedImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: incoming.highlightedFill, strokeColor: incoming.stroke, neighbors: .top(side: false), theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundIncomingMergedTopSideMaskImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: .black, strokeColor: .clear, neighbors: .top(side: true), theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true)
|
||||
self.chatMessageBackgroundIncomingMergedTopSideImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .top(side: true), theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundIncomingMergedTopSideOutlineImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .top(side: true), theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true, onlyOutline: true)
|
||||
self.chatMessageBackgroundIncomingMergedTopSideHighlightedImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: incoming.highlightedFill, strokeColor: incoming.stroke, neighbors: .top(side: true), theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundIncomingMergedBottomMaskImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: .black, strokeColor: .clear, neighbors: .bottom, theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true)
|
||||
self.chatMessageBackgroundIncomingMergedBottomImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .bottom, theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundIncomingMergedBottomOutlineImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .bottom, theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true, onlyOutline: true)
|
||||
self.chatMessageBackgroundIncomingMergedBottomHighlightedImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: incoming.highlightedFill, strokeColor: incoming.stroke, neighbors: .bottom, theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundIncomingMergedBothMaskImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: .black, strokeColor: .clear, neighbors: .both, theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true)
|
||||
self.chatMessageBackgroundIncomingMergedBothImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .both, theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundIncomingMergedBothOutlineImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .both, theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true, onlyOutline: true)
|
||||
self.chatMessageBackgroundIncomingMergedBothHighlightedImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: incoming.highlightedFill, strokeColor: incoming.stroke, neighbors: .both, theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true)
|
||||
|
||||
self.chatMessageBackgroundOutgoingMaskImage = messageBubbleImage(incoming: false, fillColor: .black, strokeColor: .clear, neighbors: .none, theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingImage = messageBubbleImage(incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .none, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingOutlineImage = messageBubbleImage(incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .none, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true, onlyOutline: true)
|
||||
self.chatMessageBackgroundOutgoingHighlightedImage = messageBubbleImage(incoming: false, fillColor: outgoing.highlightedFill, strokeColor: outgoing.stroke, neighbors: .none, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingMergedTopMaskImage = messageBubbleImage(incoming: false, fillColor: .black, strokeColor: .clear, neighbors: .top(side: false), theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingMergedTopImage = messageBubbleImage(incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .top(side: false), theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingMergedTopOutlineImage = messageBubbleImage(incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .top(side: false), theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true, onlyOutline: true)
|
||||
self.chatMessageBackgroundOutgoingMergedTopHighlightedImage = messageBubbleImage(incoming: false, fillColor: outgoing.highlightedFill, strokeColor: outgoing.stroke, neighbors: .top(side: false), theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingMergedTopSideMaskImage = messageBubbleImage(incoming: false, fillColor: .black, strokeColor: .clear, neighbors: .top(side: true), theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingMergedTopSideImage = messageBubbleImage(incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .top(side: true), theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingMergedTopSideOutlineImage = messageBubbleImage(incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .top(side: true), theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true, onlyOutline: true)
|
||||
self.chatMessageBackgroundOutgoingMergedTopSideHighlightedImage = messageBubbleImage(incoming: false, fillColor: outgoing.highlightedFill, strokeColor: outgoing.stroke, neighbors: .top(side: true), theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingMergedBottomMaskImage = messageBubbleImage(incoming: false, fillColor: .black, strokeColor: .clear, neighbors: .bottom, theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingMergedBottomImage = messageBubbleImage(incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .bottom, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingMergedBottomOutlineImage = messageBubbleImage(incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .bottom, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true, onlyOutline: true)
|
||||
self.chatMessageBackgroundOutgoingMergedBottomHighlightedImage = messageBubbleImage(incoming: false, fillColor: outgoing.highlightedFill, strokeColor: outgoing.stroke, neighbors: .bottom, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingMergedBothMaskImage = messageBubbleImage(incoming: false, fillColor: .black, strokeColor: .clear, neighbors: .both, theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingMergedBothImage = messageBubbleImage(incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .both, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingMergedBothOutlineImage = messageBubbleImage(incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .both, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true, onlyOutline: true)
|
||||
self.chatMessageBackgroundOutgoingMergedBothHighlightedImage = messageBubbleImage(incoming: false, fillColor: outgoing.highlightedFill, strokeColor: outgoing.stroke, neighbors: .both, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingMaskImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: .black, strokeColor: .clear, neighbors: .none, theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .none, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingOutlineImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .none, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true, onlyOutline: true)
|
||||
self.chatMessageBackgroundOutgoingHighlightedImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: outgoing.highlightedFill, strokeColor: outgoing.stroke, neighbors: .none, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingMergedTopMaskImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: .black, strokeColor: .clear, neighbors: .top(side: false), theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingMergedTopImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .top(side: false), theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingMergedTopOutlineImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .top(side: false), theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true, onlyOutline: true)
|
||||
self.chatMessageBackgroundOutgoingMergedTopHighlightedImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: outgoing.highlightedFill, strokeColor: outgoing.stroke, neighbors: .top(side: false), theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingMergedTopSideMaskImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: .black, strokeColor: .clear, neighbors: .top(side: true), theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingMergedTopSideImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .top(side: true), theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingMergedTopSideOutlineImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .top(side: true), theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true, onlyOutline: true)
|
||||
self.chatMessageBackgroundOutgoingMergedTopSideHighlightedImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: outgoing.highlightedFill, strokeColor: outgoing.stroke, neighbors: .top(side: true), theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingMergedBottomMaskImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: .black, strokeColor: .clear, neighbors: .bottom, theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingMergedBottomImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .bottom, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingMergedBottomOutlineImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .bottom, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true, onlyOutline: true)
|
||||
self.chatMessageBackgroundOutgoingMergedBottomHighlightedImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: outgoing.highlightedFill, strokeColor: outgoing.stroke, neighbors: .bottom, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingMergedBothMaskImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: .black, strokeColor: .clear, neighbors: .both, theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingMergedBothImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .both, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingMergedBothOutlineImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .both, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true, onlyOutline: true)
|
||||
self.chatMessageBackgroundOutgoingMergedBothHighlightedImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: outgoing.highlightedFill, strokeColor: outgoing.stroke, neighbors: .both, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true)
|
||||
|
||||
self.chatMessageBackgroundIncomingMergedSideMaskImage = messageBubbleImage(incoming: true, fillColor: .black, strokeColor: .clear, neighbors: .side, theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true)
|
||||
self.chatMessageBackgroundIncomingMergedSideImage = messageBubbleImage(incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .side, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundIncomingMergedSideOutlineImage = messageBubbleImage(incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .side, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true, onlyOutline: true)
|
||||
self.chatMessageBackgroundOutgoingMergedSideMaskImage = messageBubbleImage(incoming: false, fillColor: .black, strokeColor: .clear, neighbors: .side, theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingMergedSideImage = messageBubbleImage(incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .side, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingMergedSideOutlineImage = messageBubbleImage(incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .side, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true, onlyOutline: true)
|
||||
self.chatMessageBackgroundIncomingMergedSideHighlightedImage = messageBubbleImage(incoming: true, fillColor: incoming.highlightedFill, strokeColor: incoming.stroke, neighbors: .side, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingMergedSideHighlightedImage = messageBubbleImage(incoming: false, fillColor: outgoing.highlightedFill, strokeColor: outgoing.stroke, neighbors: .side, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundIncomingMergedSideMaskImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: .black, strokeColor: .clear, neighbors: .side, theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true)
|
||||
self.chatMessageBackgroundIncomingMergedSideImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .side, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundIncomingMergedSideOutlineImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .side, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true, onlyOutline: true)
|
||||
self.chatMessageBackgroundOutgoingMergedSideMaskImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: .black, strokeColor: .clear, neighbors: .side, theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingMergedSideImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .side, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingMergedSideOutlineImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .side, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true, onlyOutline: true)
|
||||
self.chatMessageBackgroundIncomingMergedSideHighlightedImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: incoming.highlightedFill, strokeColor: incoming.stroke, neighbors: .side, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true)
|
||||
self.chatMessageBackgroundOutgoingMergedSideHighlightedImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: outgoing.highlightedFill, strokeColor: outgoing.stroke, neighbors: .side, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true)
|
||||
|
||||
self.checkBubbleFullImage = generateCheckImage(partial: false, color: theme.message.outgoingCheckColor, width: 11.0)!
|
||||
self.checkBubblePartialImage = generateCheckImage(partial: true, color: theme.message.outgoingCheckColor, width: 11.0)!
|
||||
|
@ -9,6 +9,7 @@ private final class PresentationsResourceCacheHolder {
|
||||
|
||||
private final class PresentationsResourceAnyCacheHolder {
|
||||
var objects: [Int32: AnyObject] = [:]
|
||||
var parameterObjects: [PresentationResourceParameterKey: AnyObject] = [:]
|
||||
}
|
||||
|
||||
public final class PresentationsResourceCache {
|
||||
@ -68,4 +69,22 @@ public final class PresentationsResourceCache {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func parameterObject(_ key: PresentationResourceParameterKey, _ theme: PresentationTheme, _ generate: (PresentationTheme) -> AnyObject?) -> AnyObject? {
|
||||
let result = self.objectCache.with { holder -> AnyObject? in
|
||||
return holder.parameterObjects[key]
|
||||
}
|
||||
if let result = result {
|
||||
return result
|
||||
} else {
|
||||
if let object = generate(theme) {
|
||||
self.objectCache.with { holder -> Void in
|
||||
holder.parameterObjects[key] = object
|
||||
}
|
||||
return object
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -78,9 +78,6 @@ public enum PresentationResourceKey: Int32 {
|
||||
case chatTitleLockIcon
|
||||
case chatTitleMuteIcon
|
||||
|
||||
case chatPrincipalThemeEssentialGraphicsWithWallpaper
|
||||
case chatPrincipalThemeEssentialGraphicsWithoutWallpaper
|
||||
|
||||
case chatPrincipalThemeAdditionalGraphicsWithCustomWallpaper
|
||||
case chatPrincipalThemeAdditionalGraphicsWithDefaultWallpaper
|
||||
|
||||
@ -234,4 +231,8 @@ public enum PresentationResourceParameterKey: Hashable {
|
||||
case chatListBadgeBackgroundMention(CGFloat)
|
||||
case chatListBadgeBackgroundInactiveMention(CGFloat)
|
||||
case chatListBadgeBackgroundPinned(CGFloat)
|
||||
|
||||
case chatBubbleMediaCorner(incoming: Bool, mainRadius: CGFloat, inset: CGFloat)
|
||||
|
||||
case chatPrincipalThemeEssentialGraphics(hasWallpaper: Bool, bubbleCorners: PresentationChatBubbleCorners)
|
||||
}
|
||||
|
@ -69,11 +69,10 @@ public struct PresentationResourcesChat {
|
||||
})
|
||||
}
|
||||
|
||||
public static func principalGraphics(mediaBox: MediaBox, knockoutWallpaper: Bool, theme: PresentationTheme, wallpaper: TelegramWallpaper) -> PrincipalThemeEssentialGraphics {
|
||||
public static func principalGraphics(mediaBox: MediaBox, knockoutWallpaper: Bool, theme: PresentationTheme, wallpaper: TelegramWallpaper, bubbleCorners: PresentationChatBubbleCorners) -> PrincipalThemeEssentialGraphics {
|
||||
let hasWallpaper = !wallpaper.isEmpty
|
||||
let key: PresentationResourceKey = !hasWallpaper ? PresentationResourceKey.chatPrincipalThemeEssentialGraphicsWithoutWallpaper : PresentationResourceKey.chatPrincipalThemeEssentialGraphicsWithWallpaper
|
||||
return theme.object(key.rawValue, { theme in
|
||||
return PrincipalThemeEssentialGraphics(mediaBox: mediaBox, presentationTheme: theme, wallpaper: wallpaper, preview: theme.preview, knockoutMode: knockoutWallpaper)
|
||||
return theme.object(PresentationResourceParameterKey.chatPrincipalThemeEssentialGraphics(hasWallpaper: hasWallpaper, bubbleCorners: bubbleCorners), { theme in
|
||||
return PrincipalThemeEssentialGraphics(mediaBox: mediaBox, presentationTheme: theme, wallpaper: wallpaper, preview: theme.preview, knockoutMode: knockoutWallpaper, bubbleCorners: bubbleCorners)
|
||||
}) as! PrincipalThemeEssentialGraphics
|
||||
}
|
||||
|
||||
@ -950,4 +949,10 @@ public struct PresentationResourcesChat {
|
||||
return generateCheckImage(partial: true, color: color, width: size)
|
||||
})
|
||||
}
|
||||
|
||||
public static func chatBubbleMediaCorner(_ theme: PresentationTheme, incoming: Bool, mainRadius: CGFloat, inset: CGFloat) -> UIImage? {
|
||||
return theme.image(PresentationResourceParameterKey.chatBubbleMediaCorner(incoming: incoming, mainRadius: mainRadius, inset: inset), { _ in
|
||||
return mediaBubbleCornerImage(incoming: incoming, radius: mainRadius, inset: inset)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -251,7 +251,7 @@ public final class ChatHistoryGridNode: GridNode, ChatHistoryNode {
|
||||
|
||||
self.chatPresentationDataPromise.set(context.sharedContext.presentationData
|
||||
|> map { presentationData in
|
||||
return ChatPresentationData(theme: ChatPresentationThemeData(theme: presentationData.theme, wallpaper: presentationData.chatWallpaper), fontSize: presentationData.chatFontSize, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, disableAnimations: presentationData.disableAnimations, largeEmoji: presentationData.largeEmoji)
|
||||
return ChatPresentationData(theme: ChatPresentationThemeData(theme: presentationData.theme, wallpaper: presentationData.chatWallpaper), fontSize: presentationData.chatFontSize, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, disableAnimations: presentationData.disableAnimations, largeEmoji: presentationData.largeEmoji, chatBubbleCorners: presentationData.chatBubbleCorners)
|
||||
})
|
||||
|
||||
self.floatingSections = true
|
||||
|
@ -505,7 +505,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
self.mode = mode
|
||||
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
self.currentPresentationData = ChatPresentationData(theme: ChatPresentationThemeData(theme: presentationData.theme, wallpaper: presentationData.chatWallpaper), fontSize: presentationData.chatFontSize, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, disableAnimations: presentationData.disableAnimations, largeEmoji: presentationData.largeEmoji, animatedEmojiScale: 1.0)
|
||||
self.currentPresentationData = ChatPresentationData(theme: ChatPresentationThemeData(theme: presentationData.theme, wallpaper: presentationData.chatWallpaper), fontSize: presentationData.chatFontSize, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, disableAnimations: presentationData.disableAnimations, largeEmoji: presentationData.largeEmoji, chatBubbleCorners: presentationData.chatBubbleCorners, animatedEmojiScale: 1.0)
|
||||
|
||||
self.chatPresentationDataPromise = Promise(self.currentPresentationData)
|
||||
|
||||
@ -880,7 +880,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
|
||||
if previousTheme !== presentationData.theme || previousStrings !== presentationData.strings || previousWallpaper != presentationData.chatWallpaper || previousDisableAnimations != presentationData.disableAnimations || previousAnimatedEmojiScale != animatedEmojiConfig.scale {
|
||||
let themeData = ChatPresentationThemeData(theme: presentationData.theme, wallpaper: presentationData.chatWallpaper)
|
||||
let chatPresentationData = ChatPresentationData(theme: themeData, fontSize: presentationData.chatFontSize, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, disableAnimations: presentationData.disableAnimations, largeEmoji: presentationData.largeEmoji, animatedEmojiScale: animatedEmojiConfig.scale)
|
||||
let chatPresentationData = ChatPresentationData(theme: themeData, fontSize: presentationData.chatFontSize, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, disableAnimations: presentationData.disableAnimations, largeEmoji: presentationData.largeEmoji, chatBubbleCorners: presentationData.chatBubbleCorners, animatedEmojiScale: animatedEmojiConfig.scale)
|
||||
|
||||
strongSelf.currentPresentationData = chatPresentationData
|
||||
strongSelf.dynamicBounceEnabled = !presentationData.disableAnimations
|
||||
|
@ -349,7 +349,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
||||
let currentItem = self.item
|
||||
|
||||
return { item, params, mergedTop, mergedBottom, dateHeaderAtBottom in
|
||||
let layoutConstants = chatMessageItemLayoutConstants(layoutConstants, params: params)
|
||||
let layoutConstants = chatMessageItemLayoutConstants(layoutConstants, params: params, presentationData: item.presentationData)
|
||||
let incoming = item.message.effectivelyIncoming(item.context.account.peerId)
|
||||
var imageSize: CGSize = CGSize(width: 200.0, height: 200.0)
|
||||
var isEmoji = false
|
||||
|
@ -82,8 +82,8 @@ class ChatMessageBackground: ASDisplayNode {
|
||||
super.init()
|
||||
|
||||
self.isUserInteractionEnabled = false
|
||||
self.addSubnode(self.outlineImageNode)
|
||||
self.addSubnode(self.imageNode)
|
||||
self.addSubnode(self.outlineImageNode)
|
||||
}
|
||||
|
||||
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
|
@ -91,7 +91,7 @@ final class ChatMessageBubbleBackdrop: ASDisplayNode {
|
||||
}
|
||||
|
||||
func setType(type: ChatMessageBackgroundType, theme: ChatPresentationThemeData, mediaBox: MediaBox, essentialGraphics: PrincipalThemeEssentialGraphics, maskMode: Bool) {
|
||||
if self.currentType != type || self.theme != theme || self.currentMaskMode != maskMode {
|
||||
if self.currentType != type || self.theme != theme || self.currentMaskMode != maskMode || self.essentialGraphics !== essentialGraphics {
|
||||
self.currentType = type
|
||||
self.theme = theme
|
||||
self.essentialGraphics = essentialGraphics
|
||||
|
@ -1,8 +1,9 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
import TelegramPresentationData
|
||||
|
||||
func chatMessageBubbleImageContentCorners(relativeContentPosition position: ChatMessageBubbleContentPosition, normalRadius: CGFloat, mergedRadius: CGFloat, mergedWithAnotherContentRadius: CGFloat) -> ImageCorners {
|
||||
func chatMessageBubbleImageContentCorners(relativeContentPosition position: ChatMessageBubbleContentPosition, normalRadius: CGFloat, mergedRadius: CGFloat, mergedWithAnotherContentRadius: CGFloat, layoutConstants: ChatMessageItemLayoutConstants, chatPresentationData: ChatPresentationData) -> ImageCorners {
|
||||
let topLeftCorner: ImageCorner
|
||||
let topRightCorner: ImageCorner
|
||||
|
||||
@ -55,13 +56,33 @@ func chatMessageBubbleImageContentCorners(relativeContentPosition position: Chat
|
||||
bottomLeftCorner = .Corner(mergedRadius)
|
||||
bottomRightCorner = .Corner(normalRadius)
|
||||
case let .None(status):
|
||||
let bubbleInsets: UIEdgeInsets
|
||||
if case .color = chatPresentationData.theme.wallpaper {
|
||||
let colors: PresentationThemeBubbleColorComponents
|
||||
switch status {
|
||||
case .Incoming:
|
||||
colors = chatPresentationData.theme.theme.chat.message.incoming.bubble.withoutWallpaper
|
||||
case .Outgoing:
|
||||
colors = chatPresentationData.theme.theme.chat.message.outgoing.bubble.withoutWallpaper
|
||||
case .None:
|
||||
colors = chatPresentationData.theme.theme.chat.message.incoming.bubble.withoutWallpaper
|
||||
}
|
||||
if colors.fill == colors.stroke || colors.stroke.alpha.isZero {
|
||||
bubbleInsets = UIEdgeInsets(top: 1.0, left: 1.0, bottom: 1.0, right: 1.0)
|
||||
} else {
|
||||
bubbleInsets = layoutConstants.bubble.strokeInsets
|
||||
}
|
||||
} else {
|
||||
bubbleInsets = layoutConstants.image.bubbleInsets
|
||||
}
|
||||
|
||||
switch status {
|
||||
case .Incoming:
|
||||
bottomLeftCorner = .Tail(normalRadius, true)
|
||||
bottomLeftCorner = .Tail(normalRadius, PresentationResourcesChat.chatBubbleMediaCorner(chatPresentationData.theme.theme, incoming: true, mainRadius: normalRadius, inset: max(0.0, bubbleInsets.left - 1.0))!)
|
||||
bottomRightCorner = .Corner(normalRadius)
|
||||
case .Outgoing:
|
||||
bottomLeftCorner = .Corner(normalRadius)
|
||||
bottomRightCorner = .Tail(normalRadius, true)
|
||||
bottomRightCorner = .Tail(normalRadius, PresentationResourcesChat.chatBubbleMediaCorner(chatPresentationData.theme.theme, incoming: false, mainRadius: normalRadius, inset: max(0.0, bubbleInsets.right - 1.0))!)
|
||||
case .None:
|
||||
bottomLeftCorner = .Corner(normalRadius)
|
||||
bottomRightCorner = .Corner(normalRadius)
|
||||
@ -75,7 +96,20 @@ func chatMessageBubbleImageContentCorners(relativeContentPosition position: Chat
|
||||
switch position.bottomLeft {
|
||||
case let .none(tail):
|
||||
if tail {
|
||||
bottomLeftCorner = .Tail(normalRadius, true)
|
||||
let bubbleInsets: UIEdgeInsets
|
||||
if case .color = chatPresentationData.theme.wallpaper {
|
||||
let colors: PresentationThemeBubbleColorComponents
|
||||
colors = chatPresentationData.theme.theme.chat.message.incoming.bubble.withoutWallpaper
|
||||
if colors.fill == colors.stroke || colors.stroke.alpha.isZero {
|
||||
bubbleInsets = UIEdgeInsets(top: 1.0, left: 1.0, bottom: 1.0, right: 1.0)
|
||||
} else {
|
||||
bubbleInsets = layoutConstants.bubble.strokeInsets
|
||||
}
|
||||
} else {
|
||||
bubbleInsets = layoutConstants.image.bubbleInsets
|
||||
}
|
||||
|
||||
bottomLeftCorner = .Tail(normalRadius, PresentationResourcesChat.chatBubbleMediaCorner(chatPresentationData.theme.theme, incoming: true, mainRadius: normalRadius, inset: max(0.0, bubbleInsets.left - 1.0))!)
|
||||
} else {
|
||||
bottomLeftCorner = .Corner(normalRadius)
|
||||
}
|
||||
@ -85,7 +119,19 @@ func chatMessageBubbleImageContentCorners(relativeContentPosition position: Chat
|
||||
switch position.bottomRight {
|
||||
case let .none(tail):
|
||||
if tail {
|
||||
bottomRightCorner = .Tail(normalRadius, true)
|
||||
let bubbleInsets: UIEdgeInsets
|
||||
if case .color = chatPresentationData.theme.wallpaper {
|
||||
let colors: PresentationThemeBubbleColorComponents
|
||||
colors = chatPresentationData.theme.theme.chat.message.outgoing.bubble.withoutWallpaper
|
||||
if colors.fill == colors.stroke || colors.stroke.alpha.isZero {
|
||||
bubbleInsets = UIEdgeInsets(top: 1.0, left: 1.0, bottom: 1.0, right: 1.0)
|
||||
} else {
|
||||
bubbleInsets = layoutConstants.bubble.strokeInsets
|
||||
}
|
||||
} else {
|
||||
bubbleInsets = layoutConstants.image.bubbleInsets
|
||||
}
|
||||
bottomRightCorner = .Tail(normalRadius, PresentationResourcesChat.chatBubbleMediaCorner(chatPresentationData.theme.theme, incoming: false, mainRadius: normalRadius, inset: max(0.0, bubbleInsets.right - 1.0))!)
|
||||
} else {
|
||||
bottomRightCorner = .Corner(normalRadius)
|
||||
}
|
||||
|
@ -615,7 +615,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
|
||||
let weakSelf = Weak(self)
|
||||
|
||||
return { item, params, mergedTop, mergedBottom, dateHeaderAtBottom in
|
||||
let layoutConstants = chatMessageItemLayoutConstants(layoutConstants, params: params)
|
||||
let layoutConstants = chatMessageItemLayoutConstants(layoutConstants, params: params, presentationData: item.presentationData)
|
||||
return ChatMessageBubbleItemNode.beginLayout(selfReference: weakSelf, item, params, mergedTop, mergedBottom, dateHeaderAtBottom,
|
||||
currentContentClassesPropertiesAndLayouts: currentContentClassesPropertiesAndLayouts,
|
||||
authorNameLayout: authorNameLayout,
|
||||
@ -1546,7 +1546,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
|
||||
|
||||
let layout = ListViewItemNodeLayout(contentSize: layoutSize, insets: layoutInsets)
|
||||
|
||||
let graphics = PresentationResourcesChat.principalGraphics(mediaBox: item.context.account.postbox.mediaBox, knockoutWallpaper: item.context.sharedContext.immediateExperimentalUISettings.knockoutWallpaper, theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper)
|
||||
let graphics = PresentationResourcesChat.principalGraphics(mediaBox: item.context.account.postbox.mediaBox, knockoutWallpaper: item.context.sharedContext.immediateExperimentalUISettings.knockoutWallpaper, theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper, bubbleCorners: item.presentationData.chatBubbleCorners)
|
||||
|
||||
var updatedMergedTop = mergedBottom
|
||||
var updatedMergedBottom = mergedTop
|
||||
@ -2769,7 +2769,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
|
||||
if self.highlightedState != highlighted {
|
||||
self.highlightedState = highlighted
|
||||
if let backgroundType = self.backgroundType {
|
||||
let graphics = PresentationResourcesChat.principalGraphics(mediaBox: item.context.account.postbox.mediaBox, knockoutWallpaper: item.context.sharedContext.immediateExperimentalUISettings.knockoutWallpaper, theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper)
|
||||
let graphics = PresentationResourcesChat.principalGraphics(mediaBox: item.context.account.postbox.mediaBox, knockoutWallpaper: item.context.sharedContext.immediateExperimentalUISettings.knockoutWallpaper, theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper, bubbleCorners: item.presentationData.chatBubbleCorners)
|
||||
|
||||
let hasWallpaper = item.presentationData.theme.wallpaper.hasWallpaper
|
||||
self.backgroundNode.setType(type: backgroundType, highlighted: highlighted, graphics: graphics, maskMode: self.contextSourceNode.isExtractedToContextPreview, hasWallpaper: hasWallpaper, transition: animated ? .animated(duration: 0.3, curve: .easeInOut) : .immediate)
|
||||
|
@ -187,7 +187,7 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
|
||||
let themeUpdated = presentationData.theme != currentTheme || type != currentType
|
||||
|
||||
let graphics = PresentationResourcesChat.principalGraphics(mediaBox: context.account.postbox.mediaBox, knockoutWallpaper: context.sharedContext.immediateExperimentalUISettings.knockoutWallpaper, theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper)
|
||||
let graphics = PresentationResourcesChat.principalGraphics(mediaBox: context.account.postbox.mediaBox, knockoutWallpaper: context.sharedContext.immediateExperimentalUISettings.knockoutWallpaper, theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper, bubbleCorners: presentationData.chatBubbleCorners)
|
||||
let isDefaultWallpaper = serviceMessageColorHasDefaultWallpaper(presentationData.theme.wallpaper)
|
||||
let offset: CGFloat = -UIScreenPixel
|
||||
|
||||
|
@ -161,7 +161,7 @@ final class ChatMessageDateHeaderNode: ListViewItemHeaderNode {
|
||||
|
||||
self.transform = CATransform3DMakeRotation(CGFloat.pi, 0.0, 0.0, 1.0)
|
||||
|
||||
let graphics = PresentationResourcesChat.principalGraphics(mediaBox: context.account.postbox.mediaBox, knockoutWallpaper: context.sharedContext.immediateExperimentalUISettings.knockoutWallpaper, theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper)
|
||||
let graphics = PresentationResourcesChat.principalGraphics(mediaBox: context.account.postbox.mediaBox, knockoutWallpaper: context.sharedContext.immediateExperimentalUISettings.knockoutWallpaper, theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper, bubbleCorners: presentationData.chatBubbleCorners)
|
||||
|
||||
self.backgroundNode.image = graphics.dateStaticBackground
|
||||
self.stickBackgroundNode.image = graphics.dateFloatingBackground
|
||||
@ -190,7 +190,7 @@ final class ChatMessageDateHeaderNode: ListViewItemHeaderNode {
|
||||
let previousPresentationData = self.presentationData
|
||||
self.presentationData = presentationData
|
||||
|
||||
let graphics = PresentationResourcesChat.principalGraphics(mediaBox: context.account.postbox.mediaBox, knockoutWallpaper: context.sharedContext.immediateExperimentalUISettings.knockoutWallpaper, theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper)
|
||||
let graphics = PresentationResourcesChat.principalGraphics(mediaBox: context.account.postbox.mediaBox, knockoutWallpaper: context.sharedContext.immediateExperimentalUISettings.knockoutWallpaper, theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper, bubbleCorners: presentationData.chatBubbleCorners)
|
||||
|
||||
self.backgroundNode.image = graphics.dateStaticBackground
|
||||
self.stickBackgroundNode.image = graphics.dateFloatingBackground
|
||||
|
@ -115,7 +115,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView {
|
||||
let currentForwardInfo = self.appliedForwardInfo
|
||||
|
||||
return { item, params, mergedTop, mergedBottom, dateHeaderAtBottom in
|
||||
let layoutConstants = chatMessageItemLayoutConstants(layoutConstants, params: params)
|
||||
let layoutConstants = chatMessageItemLayoutConstants(layoutConstants, params: params, presentationData: item.presentationData)
|
||||
let incoming = item.message.effectivelyIncoming(item.context.account.peerId)
|
||||
|
||||
let avatarInset: CGFloat
|
||||
|
@ -439,7 +439,7 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
|
||||
if hasThumbnail {
|
||||
fileIconImage = nil
|
||||
} else {
|
||||
let principalGraphics = PresentationResourcesChat.principalGraphics(mediaBox: context.account.postbox.mediaBox, knockoutWallpaper: context.sharedContext.immediateExperimentalUISettings.knockoutWallpaper, theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper)
|
||||
let principalGraphics = PresentationResourcesChat.principalGraphics(mediaBox: context.account.postbox.mediaBox, knockoutWallpaper: context.sharedContext.immediateExperimentalUISettings.knockoutWallpaper, theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper, bubbleCorners: presentationData.chatBubbleCorners)
|
||||
|
||||
fileIconImage = incoming ? principalGraphics.radialIndicatorFileIconIncoming : principalGraphics.radialIndicatorFileIconOutgoing
|
||||
}
|
||||
|
@ -11,9 +11,9 @@ import ContextUI
|
||||
import ChatListUI
|
||||
|
||||
struct ChatMessageItemWidthFill {
|
||||
let compactInset: CGFloat
|
||||
let compactWidthBoundary: CGFloat
|
||||
let freeMaximumFillFactor: CGFloat
|
||||
var compactInset: CGFloat
|
||||
var compactWidthBoundary: CGFloat
|
||||
var freeMaximumFillFactor: CGFloat
|
||||
|
||||
func widthFor(_ width: CGFloat) -> CGFloat {
|
||||
if width <= self.compactWidthBoundary {
|
||||
@ -25,68 +25,68 @@ struct ChatMessageItemWidthFill {
|
||||
}
|
||||
|
||||
struct ChatMessageItemBubbleLayoutConstants {
|
||||
let edgeInset: CGFloat
|
||||
let defaultSpacing: CGFloat
|
||||
let mergedSpacing: CGFloat
|
||||
let maximumWidthFill: ChatMessageItemWidthFill
|
||||
let minimumSize: CGSize
|
||||
let contentInsets: UIEdgeInsets
|
||||
let borderInset: CGFloat
|
||||
let strokeInsets: UIEdgeInsets
|
||||
var edgeInset: CGFloat
|
||||
var defaultSpacing: CGFloat
|
||||
var mergedSpacing: CGFloat
|
||||
var maximumWidthFill: ChatMessageItemWidthFill
|
||||
var minimumSize: CGSize
|
||||
var contentInsets: UIEdgeInsets
|
||||
var borderInset: CGFloat
|
||||
var strokeInsets: UIEdgeInsets
|
||||
}
|
||||
|
||||
struct ChatMessageItemTextLayoutConstants {
|
||||
let bubbleInsets: UIEdgeInsets
|
||||
var bubbleInsets: UIEdgeInsets
|
||||
}
|
||||
|
||||
struct ChatMessageItemImageLayoutConstants {
|
||||
let bubbleInsets: UIEdgeInsets
|
||||
let statusInsets: UIEdgeInsets
|
||||
let defaultCornerRadius: CGFloat
|
||||
let mergedCornerRadius: CGFloat
|
||||
let contentMergedCornerRadius: CGFloat
|
||||
let maxDimensions: CGSize
|
||||
let minDimensions: CGSize
|
||||
var bubbleInsets: UIEdgeInsets
|
||||
var statusInsets: UIEdgeInsets
|
||||
var defaultCornerRadius: CGFloat
|
||||
var mergedCornerRadius: CGFloat
|
||||
var contentMergedCornerRadius: CGFloat
|
||||
var maxDimensions: CGSize
|
||||
var minDimensions: CGSize
|
||||
}
|
||||
|
||||
struct ChatMessageItemVideoLayoutConstants {
|
||||
let maxHorizontalHeight: CGFloat
|
||||
let maxVerticalHeight: CGFloat
|
||||
var maxHorizontalHeight: CGFloat
|
||||
var maxVerticalHeight: CGFloat
|
||||
}
|
||||
|
||||
struct ChatMessageItemInstantVideoConstants {
|
||||
let insets: UIEdgeInsets
|
||||
let dimensions: CGSize
|
||||
var insets: UIEdgeInsets
|
||||
var dimensions: CGSize
|
||||
}
|
||||
|
||||
struct ChatMessageItemFileLayoutConstants {
|
||||
let bubbleInsets: UIEdgeInsets
|
||||
var bubbleInsets: UIEdgeInsets
|
||||
}
|
||||
|
||||
struct ChatMessageItemWallpaperLayoutConstants {
|
||||
let maxTextWidth: CGFloat
|
||||
var maxTextWidth: CGFloat
|
||||
}
|
||||
|
||||
struct ChatMessageItemLayoutConstants {
|
||||
let avatarDiameter: CGFloat
|
||||
let timestampHeaderHeight: CGFloat
|
||||
var avatarDiameter: CGFloat
|
||||
var timestampHeaderHeight: CGFloat
|
||||
|
||||
let bubble: ChatMessageItemBubbleLayoutConstants
|
||||
let image: ChatMessageItemImageLayoutConstants
|
||||
let video: ChatMessageItemVideoLayoutConstants
|
||||
let text: ChatMessageItemTextLayoutConstants
|
||||
let file: ChatMessageItemFileLayoutConstants
|
||||
let instantVideo: ChatMessageItemInstantVideoConstants
|
||||
let wallpapers: ChatMessageItemWallpaperLayoutConstants
|
||||
var bubble: ChatMessageItemBubbleLayoutConstants
|
||||
var image: ChatMessageItemImageLayoutConstants
|
||||
var video: ChatMessageItemVideoLayoutConstants
|
||||
var text: ChatMessageItemTextLayoutConstants
|
||||
var file: ChatMessageItemFileLayoutConstants
|
||||
var instantVideo: ChatMessageItemInstantVideoConstants
|
||||
var wallpapers: ChatMessageItemWallpaperLayoutConstants
|
||||
|
||||
static var `default`: ChatMessageItemLayoutConstants {
|
||||
return self.compact
|
||||
}
|
||||
|
||||
fileprivate static var compact: ChatMessageItemLayoutConstants {
|
||||
let bubble = ChatMessageItemBubbleLayoutConstants(edgeInset: 4.0, defaultSpacing: 2.0 + UIScreenPixel, mergedSpacing: 1.0, maximumWidthFill: ChatMessageItemWidthFill(compactInset: 36.0, compactWidthBoundary: 500.0, freeMaximumFillFactor: 0.85), minimumSize: CGSize(width: 40.0, height: 35.0), contentInsets: UIEdgeInsets(top: 0.0, left: 6.0, bottom: 0.0, right: 0.0), borderInset: UIScreenPixel, strokeInsets: UIEdgeInsets(top: 1.0 - UIScreenPixel, left: 1.0 - UIScreenPixel, bottom: 1.0 - UIScreenPixel, right: 1.0 - UIScreenPixel))
|
||||
let bubble = ChatMessageItemBubbleLayoutConstants(edgeInset: 4.0, defaultSpacing: 2.0 + UIScreenPixel, mergedSpacing: 1.0, maximumWidthFill: ChatMessageItemWidthFill(compactInset: 36.0, compactWidthBoundary: 500.0, freeMaximumFillFactor: 0.85), minimumSize: CGSize(width: 40.0, height: 35.0), contentInsets: UIEdgeInsets(top: 0.0, left: 6.0, bottom: 0.0, right: 0.0), borderInset: UIScreenPixel, strokeInsets: UIEdgeInsets(top: 1.0, left: 1.0, bottom: 1.0, right: 1.0))
|
||||
let text = ChatMessageItemTextLayoutConstants(bubbleInsets: UIEdgeInsets(top: 6.0 + UIScreenPixel, left: 12.0, bottom: 6.0 - UIScreenPixel, right: 12.0))
|
||||
let image = ChatMessageItemImageLayoutConstants(bubbleInsets: UIEdgeInsets(top: 1.0 + UIScreenPixel, left: 1.0 + UIScreenPixel, bottom: 1.0 + UIScreenPixel, right: 1.0 + UIScreenPixel), statusInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 6.0, right: 6.0), defaultCornerRadius: 17.0, mergedCornerRadius: 5.0, contentMergedCornerRadius: 0.0, maxDimensions: CGSize(width: 300.0, height: 300.0), minDimensions: CGSize(width: 170.0, height: 74.0))
|
||||
let image = ChatMessageItemImageLayoutConstants(bubbleInsets: UIEdgeInsets(top: 2.0, left: 2.0, bottom: 2.0, right: 2.0), statusInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 6.0, right: 6.0), defaultCornerRadius: 16.0, mergedCornerRadius: 8.0, contentMergedCornerRadius: 0.0, maxDimensions: CGSize(width: 300.0, height: 300.0), minDimensions: CGSize(width: 170.0, height: 74.0))
|
||||
let video = ChatMessageItemVideoLayoutConstants(maxHorizontalHeight: 250.0, maxVerticalHeight: 360.0)
|
||||
let file = ChatMessageItemFileLayoutConstants(bubbleInsets: UIEdgeInsets(top: 15.0, left: 9.0, bottom: 15.0, right: 12.0))
|
||||
let instantVideo = ChatMessageItemInstantVideoConstants(insets: UIEdgeInsets(top: 4.0, left: 0.0, bottom: 4.0, right: 0.0), dimensions: CGSize(width: 212.0, height: 212.0))
|
||||
@ -98,7 +98,7 @@ struct ChatMessageItemLayoutConstants {
|
||||
fileprivate static var regular: ChatMessageItemLayoutConstants {
|
||||
let bubble = ChatMessageItemBubbleLayoutConstants(edgeInset: 4.0, defaultSpacing: 2.0 + UIScreenPixel, mergedSpacing: 1.0, maximumWidthFill: ChatMessageItemWidthFill(compactInset: 36.0, compactWidthBoundary: 500.0, freeMaximumFillFactor: 0.65), minimumSize: CGSize(width: 40.0, height: 35.0), contentInsets: UIEdgeInsets(top: 0.0, left: 6.0, bottom: 0.0, right: 0.0), borderInset: UIScreenPixel, strokeInsets: UIEdgeInsets(top: 1.0 - UIScreenPixel, left: 1.0 - UIScreenPixel, bottom: 1.0 - UIScreenPixel, right: 1.0 - UIScreenPixel))
|
||||
let text = ChatMessageItemTextLayoutConstants(bubbleInsets: UIEdgeInsets(top: 6.0 + UIScreenPixel, left: 12.0, bottom: 6.0 - UIScreenPixel, right: 12.0))
|
||||
let image = ChatMessageItemImageLayoutConstants(bubbleInsets: UIEdgeInsets(top: 1.0 + UIScreenPixel, left: 1.0 + UIScreenPixel, bottom: 1.0 + UIScreenPixel, right: 1.0 + UIScreenPixel), statusInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 6.0, right: 6.0), defaultCornerRadius: 17.0, mergedCornerRadius: 5.0, contentMergedCornerRadius: 5.0, maxDimensions: CGSize(width: 440.0, height: 440.0), minDimensions: CGSize(width: 170.0, height: 74.0))
|
||||
let image = ChatMessageItemImageLayoutConstants(bubbleInsets: UIEdgeInsets(top: 1.0, left: 1.0, bottom: 1.0, right: 1.0), statusInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 6.0, right: 6.0), defaultCornerRadius: 17.0, mergedCornerRadius: 5.0, contentMergedCornerRadius: 5.0, maxDimensions: CGSize(width: 440.0, height: 440.0), minDimensions: CGSize(width: 170.0, height: 74.0))
|
||||
let video = ChatMessageItemVideoLayoutConstants(maxHorizontalHeight: 250.0, maxVerticalHeight: 360.0)
|
||||
let file = ChatMessageItemFileLayoutConstants(bubbleInsets: UIEdgeInsets(top: 15.0, left: 9.0, bottom: 15.0, right: 12.0))
|
||||
let instantVideo = ChatMessageItemInstantVideoConstants(insets: UIEdgeInsets(top: 4.0, left: 0.0, bottom: 4.0, right: 0.0), dimensions: CGSize(width: 212.0, height: 212.0))
|
||||
@ -108,12 +108,24 @@ struct ChatMessageItemLayoutConstants {
|
||||
}
|
||||
}
|
||||
|
||||
func chatMessageItemLayoutConstants(_ constants: (ChatMessageItemLayoutConstants, ChatMessageItemLayoutConstants), params: ListViewItemLayoutParams) -> ChatMessageItemLayoutConstants {
|
||||
func chatMessageItemLayoutConstants(_ constants: (ChatMessageItemLayoutConstants, ChatMessageItemLayoutConstants), params: ListViewItemLayoutParams, presentationData: ChatPresentationData) -> ChatMessageItemLayoutConstants {
|
||||
var result: ChatMessageItemLayoutConstants
|
||||
if params.width > 680.0 {
|
||||
return constants.1
|
||||
result = constants.1
|
||||
} else {
|
||||
return constants.0
|
||||
result = constants.0
|
||||
}
|
||||
result.image.defaultCornerRadius = presentationData.chatBubbleCorners.mainRadius
|
||||
result.image.mergedCornerRadius = presentationData.chatBubbleCorners.mergeBubbleCorners ? presentationData.chatBubbleCorners.auxiliaryRadius : presentationData.chatBubbleCorners.mainRadius
|
||||
let minRadius: CGFloat = 4.0
|
||||
let maxRadius: CGFloat = 16.0
|
||||
let radiusTransition = (presentationData.chatBubbleCorners.mainRadius - minRadius) / (maxRadius - minRadius)
|
||||
let minInset: CGFloat = 9.0
|
||||
let maxInset: CGFloat = 12.0
|
||||
let textInset: CGFloat = min(maxInset, ceil(maxInset * radiusTransition + minInset * (1.0 - radiusTransition)))
|
||||
result.text.bubbleInsets.left = textInset
|
||||
result.text.bubbleInsets.right = textInset
|
||||
return result
|
||||
}
|
||||
|
||||
enum ChatMessageItemBottomNeighbor {
|
||||
|
@ -159,13 +159,13 @@ class ChatMessageMapBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
if case let .linear(top, _) = position {
|
||||
relativePosition = .linear(top: top, bottom: ChatMessageBubbleRelativePosition.Neighbour)
|
||||
}
|
||||
imageCorners = chatMessageBubbleImageContentCorners(relativeContentPosition: relativePosition, normalRadius: layoutConstants.image.defaultCornerRadius, mergedRadius: layoutConstants.image.mergedCornerRadius, mergedWithAnotherContentRadius: layoutConstants.image.contentMergedCornerRadius)
|
||||
imageCorners = chatMessageBubbleImageContentCorners(relativeContentPosition: relativePosition, normalRadius: layoutConstants.image.defaultCornerRadius, mergedRadius: layoutConstants.image.mergedCornerRadius, mergedWithAnotherContentRadius: layoutConstants.image.contentMergedCornerRadius, layoutConstants: layoutConstants, chatPresentationData: item.presentationData)
|
||||
|
||||
maxTextWidth = constrainedSize.width - bubbleInsets.left + bubbleInsets.right - layoutConstants.text.bubbleInsets.left - layoutConstants.text.bubbleInsets.right - 40.0
|
||||
} else {
|
||||
maxTextWidth = constrainedSize.width - imageSize.width - bubbleInsets.left + bubbleInsets.right - layoutConstants.text.bubbleInsets.right
|
||||
|
||||
imageCorners = chatMessageBubbleImageContentCorners(relativeContentPosition: position, normalRadius: layoutConstants.image.defaultCornerRadius, mergedRadius: layoutConstants.image.mergedCornerRadius, mergedWithAnotherContentRadius: layoutConstants.image.contentMergedCornerRadius)
|
||||
imageCorners = chatMessageBubbleImageContentCorners(relativeContentPosition: position, normalRadius: layoutConstants.image.defaultCornerRadius, mergedRadius: layoutConstants.image.mergedCornerRadius, mergedWithAnotherContentRadius: layoutConstants.image.contentMergedCornerRadius, layoutConstants: layoutConstants, chatPresentationData: item.presentationData)
|
||||
}
|
||||
|
||||
let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: titleString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: max(1.0, maxTextWidth), height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||
|
@ -128,8 +128,8 @@ class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
} else {
|
||||
colors = item.presentationData.theme.theme.chat.message.outgoing.bubble.withoutWallpaper
|
||||
}
|
||||
if colors.fill == colors.stroke {
|
||||
bubbleInsets = UIEdgeInsets()
|
||||
if colors.fill == colors.stroke || colors.stroke.alpha.isZero {
|
||||
bubbleInsets = UIEdgeInsets(top: 1.0, left: 1.0, bottom: 1.0, right: 1.0)
|
||||
} else {
|
||||
bubbleInsets = layoutConstants.bubble.strokeInsets
|
||||
}
|
||||
@ -162,7 +162,7 @@ class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
updatedPosition = .linear(top: top, bottom: .Neighbour)
|
||||
}
|
||||
|
||||
let imageCorners = chatMessageBubbleImageContentCorners(relativeContentPosition: updatedPosition, normalRadius: layoutConstants.image.defaultCornerRadius, mergedRadius: layoutConstants.image.mergedCornerRadius, mergedWithAnotherContentRadius: layoutConstants.image.contentMergedCornerRadius)
|
||||
let imageCorners = chatMessageBubbleImageContentCorners(relativeContentPosition: updatedPosition, normalRadius: layoutConstants.image.defaultCornerRadius, mergedRadius: layoutConstants.image.mergedCornerRadius, mergedWithAnotherContentRadius: layoutConstants.image.contentMergedCornerRadius, layoutConstants: layoutConstants, chatPresentationData: item.presentationData)
|
||||
|
||||
let (refinedWidth, finishLayout) = refineLayout(CGSize(width: constrainedSize.width - bubbleInsets.left - bubbleInsets.right, height: constrainedSize.height), automaticPlayback, wideLayout, imageCorners)
|
||||
|
||||
|
@ -143,7 +143,7 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
||||
let currentItem = self.item
|
||||
|
||||
return { item, params, mergedTop, mergedBottom, dateHeaderAtBottom in
|
||||
let layoutConstants = chatMessageItemLayoutConstants(layoutConstants, params: params)
|
||||
let layoutConstants = chatMessageItemLayoutConstants(layoutConstants, params: params, presentationData: item.presentationData)
|
||||
let incoming = item.message.effectivelyIncoming(item.context.account.peerId)
|
||||
var imageSize: CGSize = CGSize(width: 100.0, height: 100.0)
|
||||
if let telegramFile = telegramFile {
|
||||
|
@ -28,6 +28,7 @@ public final class ChatPresentationData {
|
||||
let nameDisplayOrder: PresentationPersonNameOrder
|
||||
let disableAnimations: Bool
|
||||
let largeEmoji: Bool
|
||||
let chatBubbleCorners: PresentationChatBubbleCorners
|
||||
let animatedEmojiScale: CGFloat
|
||||
let isPreview: Bool
|
||||
|
||||
@ -39,13 +40,14 @@ public final class ChatPresentationData {
|
||||
let messageFixedFont: UIFont
|
||||
let messageBlockQuoteFont: UIFont
|
||||
|
||||
init(theme: ChatPresentationThemeData, fontSize: PresentationFontSize, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, disableAnimations: Bool, largeEmoji: Bool, animatedEmojiScale: CGFloat = 1.0, isPreview: Bool = false) {
|
||||
init(theme: ChatPresentationThemeData, fontSize: PresentationFontSize, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, disableAnimations: Bool, largeEmoji: Bool, chatBubbleCorners: PresentationChatBubbleCorners, animatedEmojiScale: CGFloat = 1.0, isPreview: Bool = false) {
|
||||
self.theme = theme
|
||||
self.fontSize = fontSize
|
||||
self.strings = strings
|
||||
self.dateTimeFormat = dateTimeFormat
|
||||
self.nameDisplayOrder = nameDisplayOrder
|
||||
self.disableAnimations = disableAnimations
|
||||
self.chatBubbleCorners = chatBubbleCorners
|
||||
self.largeEmoji = largeEmoji
|
||||
self.isPreview = isPreview
|
||||
|
||||
|
@ -113,7 +113,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
|
||||
|
||||
self.state = ChatRecentActionsControllerState(chatWallpaper: self.presentationData.chatWallpaper, theme: self.presentationData.theme, strings: self.presentationData.strings, fontSize: self.presentationData.chatFontSize)
|
||||
|
||||
self.chatPresentationDataPromise = Promise(ChatPresentationData(theme: ChatPresentationThemeData(theme: self.presentationData.theme, wallpaper: self.presentationData.chatWallpaper), fontSize: self.presentationData.chatFontSize, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder, disableAnimations: self.presentationData.disableAnimations, largeEmoji: self.presentationData.largeEmoji))
|
||||
self.chatPresentationDataPromise = Promise(ChatPresentationData(theme: ChatPresentationThemeData(theme: self.presentationData.theme, wallpaper: self.presentationData.chatWallpaper), fontSize: self.presentationData.chatFontSize, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder, disableAnimations: self.presentationData.disableAnimations, largeEmoji: self.presentationData.largeEmoji, chatBubbleCorners: self.presentationData.chatBubbleCorners))
|
||||
|
||||
self.eventLogContext = ChannelAdminEventLogContext(postbox: self.context.account.postbox, network: self.context.account.network, peerId: self.peer.id)
|
||||
|
||||
@ -496,7 +496,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
|
||||
|> deliverOnMainQueue).start(next: { [weak self] presentationData in
|
||||
if let strongSelf = self {
|
||||
strongSelf.presentationData = presentationData
|
||||
strongSelf.chatPresentationDataPromise.set(.single(ChatPresentationData(theme: ChatPresentationThemeData(theme: presentationData.theme, wallpaper: presentationData.chatWallpaper), fontSize: presentationData.chatFontSize, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, disableAnimations: presentationData.disableAnimations, largeEmoji: presentationData.largeEmoji)))
|
||||
strongSelf.chatPresentationDataPromise.set(.single(ChatPresentationData(theme: ChatPresentationThemeData(theme: presentationData.theme, wallpaper: presentationData.chatWallpaper), fontSize: presentationData.chatFontSize, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, disableAnimations: presentationData.disableAnimations, largeEmoji: presentationData.largeEmoji, chatBubbleCorners: presentationData.chatBubbleCorners)))
|
||||
|
||||
strongSelf.updateThemeAndStrings(theme: presentationData.theme, strings: presentationData.strings)
|
||||
}
|
||||
|
@ -272,7 +272,10 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
|
||||
self.messageBackgroundNode.contentMode = .scaleToFill
|
||||
|
||||
let outgoing: PresentationThemeBubbleColorComponents = self.presentationData.chatWallpaper.isEmpty ? self.presentationData.theme.chat.message.outgoing.bubble.withoutWallpaper : self.presentationData.theme.chat.message.outgoing.bubble.withWallpaper
|
||||
self.messageBackgroundNode.image = messageBubbleImage(incoming: false, fillColor: outgoing.gradientFill, strokeColor: outgoing.fill == outgoing.gradientFill ? outgoing.stroke : .clear, neighbors: .none, theme: self.presentationData.theme.chat, wallpaper: self.presentationData.chatWallpaper, knockout: false)
|
||||
|
||||
let maxCornerRadius = self.presentationData.chatBubbleCorners.mainRadius
|
||||
let minCornerRadius = self.presentationData.chatBubbleCorners.auxiliaryRadius
|
||||
self.messageBackgroundNode.image = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: maxCornerRadius, incoming: false, fillColor: outgoing.gradientFill, strokeColor: outgoing.fill == outgoing.gradientFill ? outgoing.stroke : .clear, neighbors: .none, theme: self.presentationData.theme.chat, wallpaper: self.presentationData.chatWallpaper, knockout: false)
|
||||
|
||||
self.view.addSubview(self.effectView)
|
||||
self.addSubnode(self.dimNode)
|
||||
@ -376,7 +379,9 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
|
||||
}
|
||||
|
||||
let outgoing: PresentationThemeBubbleColorComponents = self.presentationData.chatWallpaper.isEmpty ? self.presentationData.theme.chat.message.outgoing.bubble.withoutWallpaper : self.presentationData.theme.chat.message.outgoing.bubble.withWallpaper
|
||||
self.messageBackgroundNode.image = messageBubbleImage(incoming: false, fillColor: outgoing.gradientFill, strokeColor: outgoing.fill == outgoing.gradientFill ? outgoing.stroke : .clear, neighbors: .none, theme: self.presentationData.theme.chat, wallpaper: self.presentationData.chatWallpaper, knockout: false)
|
||||
let maxCornerRadius = self.presentationData.chatBubbleCorners.mainRadius
|
||||
let minCornerRadius = self.presentationData.chatBubbleCorners.auxiliaryRadius
|
||||
self.messageBackgroundNode.image = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: maxCornerRadius, incoming: false, fillColor: outgoing.gradientFill, strokeColor: outgoing.fill == outgoing.gradientFill ? outgoing.stroke : .clear, neighbors: .none, theme: self.presentationData.theme.chat, wallpaper: self.presentationData.chatWallpaper, knockout: false)
|
||||
|
||||
for node in self.contentNodes {
|
||||
node.updateTheme(presentationData.theme)
|
||||
|
Binary file not shown.
@ -1094,7 +1094,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
return PeerSelectionControllerImpl(params)
|
||||
}
|
||||
|
||||
public func makeChatMessagePreviewItem(context: AccountContext, message: Message, theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, dateTimeFormat: PresentationDateTimeFormat, nameOrder: PresentationPersonNameOrder, forcedResourceStatus: FileMediaResourceStatus?, tapMessage: ((Message) -> Void)? = nil, clickThroughMessage: (() -> Void)? = nil) -> ListViewItem {
|
||||
public func makeChatMessagePreviewItem(context: AccountContext, message: Message, theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, dateTimeFormat: PresentationDateTimeFormat, nameOrder: PresentationPersonNameOrder, forcedResourceStatus: FileMediaResourceStatus?, tapMessage: ((Message) -> Void)? = nil, clickThroughMessage: (() -> Void)? = nil) -> ListViewItem {
|
||||
let controllerInteraction: ChatControllerInteraction
|
||||
if tapMessage != nil || clickThroughMessage != nil {
|
||||
controllerInteraction = ChatControllerInteraction(openMessage: { _, _ in
|
||||
@ -1139,11 +1139,11 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
controllerInteraction = defaultChatControllerInteraction
|
||||
}
|
||||
|
||||
return ChatMessageItem(presentationData: ChatPresentationData(theme: ChatPresentationThemeData(theme: theme, wallpaper: wallpaper), fontSize: fontSize, strings: strings, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameOrder, disableAnimations: false, largeEmoji: false, animatedEmojiScale: 1.0, isPreview: true), context: context, chatLocation: .peer(message.id.peerId), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .contact, automaticDownloadNetworkType: .cellular, isRecentActions: false, isScheduledMessages: false, contactsPeerIds: Set(), animatedEmojiStickers: [:], forcedResourceStatus: forcedResourceStatus), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes()), disableDate: true, additionalContent: nil)
|
||||
return ChatMessageItem(presentationData: ChatPresentationData(theme: ChatPresentationThemeData(theme: theme, wallpaper: wallpaper), fontSize: fontSize, strings: strings, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameOrder, disableAnimations: false, largeEmoji: false, chatBubbleCorners: chatBubbleCorners, animatedEmojiScale: 1.0, isPreview: true), context: context, chatLocation: .peer(message.id.peerId), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .contact, automaticDownloadNetworkType: .cellular, isRecentActions: false, isScheduledMessages: false, contactsPeerIds: Set(), animatedEmojiStickers: [:], forcedResourceStatus: forcedResourceStatus), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes()), disableDate: true, additionalContent: nil)
|
||||
}
|
||||
|
||||
public func makeChatMessageDateHeaderItem(context: AccountContext, timestamp: Int32, theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, dateTimeFormat: PresentationDateTimeFormat, nameOrder: PresentationPersonNameOrder) -> ListViewItemHeader {
|
||||
return ChatMessageDateHeader(timestamp: timestamp, scheduled: false, presentationData: ChatPresentationData(theme: ChatPresentationThemeData(theme: theme, wallpaper: wallpaper), fontSize: fontSize, strings: strings, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameOrder, disableAnimations: false, largeEmoji: false, animatedEmojiScale: 1.0, isPreview: true), context: context)
|
||||
public func makeChatMessageDateHeaderItem(context: AccountContext, timestamp: Int32, theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, dateTimeFormat: PresentationDateTimeFormat, nameOrder: PresentationPersonNameOrder) -> ListViewItemHeader {
|
||||
return ChatMessageDateHeader(timestamp: timestamp, scheduled: false, presentationData: ChatPresentationData(theme: ChatPresentationThemeData(theme: theme, wallpaper: wallpaper), fontSize: fontSize, strings: strings, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameOrder, disableAnimations: false, largeEmoji: false, chatBubbleCorners: chatBubbleCorners, animatedEmojiScale: 1.0, isPreview: true), context: context)
|
||||
}
|
||||
|
||||
public func openWallet(context: AccountContext, walletContext: OpenWalletContext, present: @escaping (ViewController) -> Void) {
|
||||
|
@ -139,7 +139,7 @@ final class ThemeUpdateManagerImpl: ThemeUpdateManager {
|
||||
theme = updatedTheme
|
||||
}
|
||||
|
||||
return PresentationThemeSettings(theme: theme, themeSpecificAccentColors: current.themeSpecificAccentColors, themeSpecificChatWallpapers: current.themeSpecificChatWallpapers, useSystemFont: current.useSystemFont, fontSize: current.fontSize, listsFontSize: current.listsFontSize, automaticThemeSwitchSetting: automaticThemeSwitchSetting, largeEmoji: current.largeEmoji, disableAnimations: current.disableAnimations)
|
||||
return PresentationThemeSettings(theme: theme, themeSpecificAccentColors: current.themeSpecificAccentColors, themeSpecificChatWallpapers: current.themeSpecificChatWallpapers, useSystemFont: current.useSystemFont, fontSize: current.fontSize, listsFontSize: current.listsFontSize, chatBubbleSettings: current.chatBubbleSettings, automaticThemeSwitchSetting: automaticThemeSwitchSetting, largeEmoji: current.largeEmoji, disableAnimations: current.disableAnimations)
|
||||
})
|
||||
}).start()
|
||||
}
|
||||
|
@ -133,7 +133,7 @@ final class WallpaperUploadManagerImpl: WallpaperUploadManager {
|
||||
var themeSpecificChatWallpapers = current.themeSpecificChatWallpapers
|
||||
themeSpecificChatWallpapers[themeReference.index] = updatedWallpaper
|
||||
themeSpecificChatWallpapers[coloredThemeIndex(reference: themeReference, accentColor: current.themeSpecificAccentColors[themeReference.index])] = updatedWallpaper
|
||||
return PresentationThemeSettings(theme: current.theme, themeSpecificAccentColors: current.themeSpecificAccentColors, themeSpecificChatWallpapers: themeSpecificChatWallpapers, useSystemFont: current.useSystemFont, fontSize: current.fontSize, listsFontSize: current.listsFontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, largeEmoji: current.largeEmoji, disableAnimations: current.disableAnimations)
|
||||
return PresentationThemeSettings(theme: current.theme, themeSpecificAccentColors: current.themeSpecificAccentColors, themeSpecificChatWallpapers: themeSpecificChatWallpapers, useSystemFont: current.useSystemFont, fontSize: current.fontSize, listsFontSize: current.listsFontSize, chatBubbleSettings: current.chatBubbleSettings, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, largeEmoji: current.largeEmoji, disableAnimations: current.disableAnimations)
|
||||
})).start()
|
||||
}
|
||||
|
||||
|
@ -531,6 +531,32 @@ public struct PresentationThemeAccentColor: PostboxCoding, Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
public struct PresentationChatBubbleSettings: PostboxCoding, Equatable {
|
||||
public var mainRadius: Int32
|
||||
public var auxiliaryRadius: Int32
|
||||
public var mergeBubbleCorners: Bool
|
||||
|
||||
public static var `default`: PresentationChatBubbleSettings = PresentationChatBubbleSettings(mainRadius: 16, auxiliaryRadius: 8, mergeBubbleCorners: true)
|
||||
|
||||
public init(mainRadius: Int32, auxiliaryRadius: Int32, mergeBubbleCorners: Bool) {
|
||||
self.mainRadius = mainRadius
|
||||
self.auxiliaryRadius = auxiliaryRadius
|
||||
self.mergeBubbleCorners = mergeBubbleCorners
|
||||
}
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
self.mainRadius = decoder.decodeInt32ForKey("mainRadius", orElse: 16)
|
||||
self.auxiliaryRadius = decoder.decodeInt32ForKey("auxiliaryRadius", orElse: 8)
|
||||
self.mergeBubbleCorners = decoder.decodeInt32ForKey("mergeBubbleCorners", orElse: 1) != 0
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
encoder.encodeInt32(self.mainRadius, forKey: "mainRadius")
|
||||
encoder.encodeInt32(self.auxiliaryRadius, forKey: "auxiliaryRadius")
|
||||
encoder.encodeInt32(self.mergeBubbleCorners ? 1 : 0, forKey: "mergeBubbleCorners")
|
||||
}
|
||||
}
|
||||
|
||||
public struct PresentationThemeSettings: PreferencesEntry {
|
||||
public var theme: PresentationThemeReference
|
||||
public var themeSpecificAccentColors: [Int64: PresentationThemeAccentColor]
|
||||
@ -538,6 +564,7 @@ public struct PresentationThemeSettings: PreferencesEntry {
|
||||
public var useSystemFont: Bool
|
||||
public var fontSize: PresentationFontSize
|
||||
public var listsFontSize: PresentationFontSize
|
||||
public var chatBubbleSettings: PresentationChatBubbleSettings
|
||||
public var automaticThemeSwitchSetting: AutomaticThemeSwitchSetting
|
||||
public var largeEmoji: Bool
|
||||
public var disableAnimations: Bool
|
||||
@ -578,16 +605,17 @@ public struct PresentationThemeSettings: PreferencesEntry {
|
||||
}
|
||||
|
||||
public static var defaultSettings: PresentationThemeSettings {
|
||||
return PresentationThemeSettings(theme: .builtin(.dayClassic), themeSpecificAccentColors: [:], themeSpecificChatWallpapers: [:], useSystemFont: true, fontSize: .regular, listsFontSize: .regular, automaticThemeSwitchSetting: AutomaticThemeSwitchSetting(trigger: .system, theme: .builtin(.night)), largeEmoji: true, disableAnimations: true)
|
||||
return PresentationThemeSettings(theme: .builtin(.dayClassic), themeSpecificAccentColors: [:], themeSpecificChatWallpapers: [:], useSystemFont: true, fontSize: .regular, listsFontSize: .regular, chatBubbleSettings: .default, automaticThemeSwitchSetting: AutomaticThemeSwitchSetting(trigger: .system, theme: .builtin(.night)), largeEmoji: true, disableAnimations: true)
|
||||
}
|
||||
|
||||
public init(theme: PresentationThemeReference, themeSpecificAccentColors: [Int64: PresentationThemeAccentColor], themeSpecificChatWallpapers: [Int64: TelegramWallpaper], useSystemFont: Bool, fontSize: PresentationFontSize, listsFontSize: PresentationFontSize, automaticThemeSwitchSetting: AutomaticThemeSwitchSetting, largeEmoji: Bool, disableAnimations: Bool) {
|
||||
public init(theme: PresentationThemeReference, themeSpecificAccentColors: [Int64: PresentationThemeAccentColor], themeSpecificChatWallpapers: [Int64: TelegramWallpaper], useSystemFont: Bool, fontSize: PresentationFontSize, listsFontSize: PresentationFontSize, chatBubbleSettings: PresentationChatBubbleSettings, automaticThemeSwitchSetting: AutomaticThemeSwitchSetting, largeEmoji: Bool, disableAnimations: Bool) {
|
||||
self.theme = theme
|
||||
self.themeSpecificAccentColors = themeSpecificAccentColors
|
||||
self.themeSpecificChatWallpapers = themeSpecificChatWallpapers
|
||||
self.useSystemFont = useSystemFont
|
||||
self.fontSize = fontSize
|
||||
self.listsFontSize = listsFontSize
|
||||
self.chatBubbleSettings = chatBubbleSettings
|
||||
self.automaticThemeSwitchSetting = automaticThemeSwitchSetting
|
||||
self.largeEmoji = largeEmoji
|
||||
self.disableAnimations = disableAnimations
|
||||
@ -612,6 +640,7 @@ public struct PresentationThemeSettings: PreferencesEntry {
|
||||
let fontSize = PresentationFontSize(rawValue: decoder.decodeInt32ForKey("f", orElse: PresentationFontSize.regular.rawValue)) ?? .regular
|
||||
self.fontSize = fontSize
|
||||
self.listsFontSize = PresentationFontSize(rawValue: decoder.decodeInt32ForKey("lf", orElse: PresentationFontSize.regular.rawValue)) ?? fontSize
|
||||
self.chatBubbleSettings = decoder.decodeObjectForKey("chatBubbleSettings", decoder: { PresentationChatBubbleSettings(decoder: $0) }) as? PresentationChatBubbleSettings ?? PresentationChatBubbleSettings.default
|
||||
self.automaticThemeSwitchSetting = (decoder.decodeObjectForKey("automaticThemeSwitchSetting", decoder: { AutomaticThemeSwitchSetting(decoder: $0) }) as? AutomaticThemeSwitchSetting) ?? AutomaticThemeSwitchSetting(trigger: .system, theme: .builtin(.night))
|
||||
self.largeEmoji = decoder.decodeBoolForKey("largeEmoji", orElse: true)
|
||||
self.disableAnimations = decoder.decodeBoolForKey("disableAnimations", orElse: true)
|
||||
@ -628,6 +657,7 @@ public struct PresentationThemeSettings: PreferencesEntry {
|
||||
encoder.encodeInt32(self.useSystemFont ? 1 : 0, forKey: "useSystemFont")
|
||||
encoder.encodeInt32(self.fontSize.rawValue, forKey: "f")
|
||||
encoder.encodeInt32(self.listsFontSize.rawValue, forKey: "lf")
|
||||
encoder.encodeObject(self.chatBubbleSettings, forKey: "chatBubbleSettings")
|
||||
encoder.encodeObject(self.automaticThemeSwitchSetting, forKey: "automaticThemeSwitchSetting")
|
||||
encoder.encodeBool(self.largeEmoji, forKey: "largeEmoji")
|
||||
encoder.encodeBool(self.disableAnimations, forKey: "disableAnimations")
|
||||
@ -642,39 +672,43 @@ public struct PresentationThemeSettings: PreferencesEntry {
|
||||
}
|
||||
|
||||
public static func ==(lhs: PresentationThemeSettings, rhs: PresentationThemeSettings) -> Bool {
|
||||
return lhs.theme == rhs.theme && lhs.themeSpecificAccentColors == rhs.themeSpecificAccentColors && lhs.themeSpecificChatWallpapers == rhs.themeSpecificChatWallpapers && lhs.useSystemFont == rhs.useSystemFont && lhs.fontSize == rhs.fontSize && lhs.listsFontSize == rhs.listsFontSize && lhs.automaticThemeSwitchSetting == rhs.automaticThemeSwitchSetting && lhs.largeEmoji == rhs.largeEmoji && lhs.disableAnimations == rhs.disableAnimations
|
||||
return lhs.theme == rhs.theme && lhs.themeSpecificAccentColors == rhs.themeSpecificAccentColors && lhs.themeSpecificChatWallpapers == rhs.themeSpecificChatWallpapers && lhs.useSystemFont == rhs.useSystemFont && lhs.fontSize == rhs.fontSize && lhs.listsFontSize == rhs.listsFontSize && lhs.chatBubbleSettings == rhs.chatBubbleSettings && lhs.automaticThemeSwitchSetting == rhs.automaticThemeSwitchSetting && lhs.largeEmoji == rhs.largeEmoji && lhs.disableAnimations == rhs.disableAnimations
|
||||
}
|
||||
|
||||
public func withUpdatedTheme(_ theme: PresentationThemeReference) -> PresentationThemeSettings {
|
||||
return PresentationThemeSettings(theme: theme, themeSpecificAccentColors: self.themeSpecificAccentColors, themeSpecificChatWallpapers: self.themeSpecificChatWallpapers, useSystemFont: self.useSystemFont, fontSize: self.fontSize, listsFontSize: self.listsFontSize, automaticThemeSwitchSetting: self.automaticThemeSwitchSetting, largeEmoji: self.largeEmoji, disableAnimations: self.disableAnimations)
|
||||
return PresentationThemeSettings(theme: theme, themeSpecificAccentColors: self.themeSpecificAccentColors, themeSpecificChatWallpapers: self.themeSpecificChatWallpapers, useSystemFont: self.useSystemFont, fontSize: self.fontSize, listsFontSize: self.listsFontSize, chatBubbleSettings: self.chatBubbleSettings, automaticThemeSwitchSetting: self.automaticThemeSwitchSetting, largeEmoji: self.largeEmoji, disableAnimations: self.disableAnimations)
|
||||
}
|
||||
|
||||
public func withUpdatedThemeSpecificAccentColors(_ themeSpecificAccentColors: [Int64: PresentationThemeAccentColor]) -> PresentationThemeSettings {
|
||||
return PresentationThemeSettings(theme: self.theme, themeSpecificAccentColors: themeSpecificAccentColors, themeSpecificChatWallpapers: self.themeSpecificChatWallpapers, useSystemFont: self.useSystemFont, fontSize: self.fontSize, listsFontSize: self.listsFontSize, automaticThemeSwitchSetting: self.automaticThemeSwitchSetting, largeEmoji: self.largeEmoji, disableAnimations: self.disableAnimations)
|
||||
return PresentationThemeSettings(theme: self.theme, themeSpecificAccentColors: themeSpecificAccentColors, themeSpecificChatWallpapers: self.themeSpecificChatWallpapers, useSystemFont: self.useSystemFont, fontSize: self.fontSize, listsFontSize: self.listsFontSize, chatBubbleSettings: self.chatBubbleSettings, automaticThemeSwitchSetting: self.automaticThemeSwitchSetting, largeEmoji: self.largeEmoji, disableAnimations: self.disableAnimations)
|
||||
}
|
||||
|
||||
public func withUpdatedThemeSpecificChatWallpapers(_ themeSpecificChatWallpapers: [Int64: TelegramWallpaper]) -> PresentationThemeSettings {
|
||||
return PresentationThemeSettings(theme: self.theme, themeSpecificAccentColors: self.themeSpecificAccentColors, themeSpecificChatWallpapers: themeSpecificChatWallpapers, useSystemFont: self.useSystemFont, fontSize: self.fontSize, listsFontSize: self.listsFontSize, automaticThemeSwitchSetting: self.automaticThemeSwitchSetting, largeEmoji: self.largeEmoji, disableAnimations: self.disableAnimations)
|
||||
return PresentationThemeSettings(theme: self.theme, themeSpecificAccentColors: self.themeSpecificAccentColors, themeSpecificChatWallpapers: themeSpecificChatWallpapers, useSystemFont: self.useSystemFont, fontSize: self.fontSize, listsFontSize: self.listsFontSize, chatBubbleSettings: self.chatBubbleSettings, automaticThemeSwitchSetting: self.automaticThemeSwitchSetting, largeEmoji: self.largeEmoji, disableAnimations: self.disableAnimations)
|
||||
}
|
||||
|
||||
public func withUpdatedUseSystemFont(_ useSystemFont: Bool) -> PresentationThemeSettings {
|
||||
return PresentationThemeSettings(theme: self.theme, themeSpecificAccentColors: self.themeSpecificAccentColors, themeSpecificChatWallpapers: self.themeSpecificChatWallpapers, useSystemFont: useSystemFont, fontSize: self.fontSize, listsFontSize: self.listsFontSize, automaticThemeSwitchSetting: self.automaticThemeSwitchSetting, largeEmoji: self.largeEmoji, disableAnimations: self.disableAnimations)
|
||||
return PresentationThemeSettings(theme: self.theme, themeSpecificAccentColors: self.themeSpecificAccentColors, themeSpecificChatWallpapers: self.themeSpecificChatWallpapers, useSystemFont: useSystemFont, fontSize: self.fontSize, listsFontSize: self.listsFontSize, chatBubbleSettings: self.chatBubbleSettings, automaticThemeSwitchSetting: self.automaticThemeSwitchSetting, largeEmoji: self.largeEmoji, disableAnimations: self.disableAnimations)
|
||||
}
|
||||
|
||||
public func withUpdatedFontSizes(fontSize: PresentationFontSize, listsFontSize: PresentationFontSize) -> PresentationThemeSettings {
|
||||
return PresentationThemeSettings(theme: self.theme, themeSpecificAccentColors: self.themeSpecificAccentColors, themeSpecificChatWallpapers: self.themeSpecificChatWallpapers, useSystemFont: self.useSystemFont, fontSize: fontSize, listsFontSize: listsFontSize, automaticThemeSwitchSetting: self.automaticThemeSwitchSetting, largeEmoji: self.largeEmoji, disableAnimations: self.disableAnimations)
|
||||
return PresentationThemeSettings(theme: self.theme, themeSpecificAccentColors: self.themeSpecificAccentColors, themeSpecificChatWallpapers: self.themeSpecificChatWallpapers, useSystemFont: self.useSystemFont, fontSize: fontSize, listsFontSize: listsFontSize, chatBubbleSettings: self.chatBubbleSettings, automaticThemeSwitchSetting: self.automaticThemeSwitchSetting, largeEmoji: self.largeEmoji, disableAnimations: self.disableAnimations)
|
||||
}
|
||||
|
||||
public func withUpdatedChatBubbleSettings(_ chatBubbleSettings: PresentationChatBubbleSettings) -> PresentationThemeSettings {
|
||||
return PresentationThemeSettings(theme: self.theme, themeSpecificAccentColors: self.themeSpecificAccentColors, themeSpecificChatWallpapers: self.themeSpecificChatWallpapers, useSystemFont: self.useSystemFont, fontSize: self.fontSize, listsFontSize: self.listsFontSize, chatBubbleSettings: chatBubbleSettings, automaticThemeSwitchSetting: self.automaticThemeSwitchSetting, largeEmoji: self.largeEmoji, disableAnimations: self.disableAnimations)
|
||||
}
|
||||
|
||||
public func withUpdatedAutomaticThemeSwitchSetting(_ automaticThemeSwitchSetting: AutomaticThemeSwitchSetting) -> PresentationThemeSettings {
|
||||
return PresentationThemeSettings(theme: self.theme, themeSpecificAccentColors: self.themeSpecificAccentColors, themeSpecificChatWallpapers: self.themeSpecificChatWallpapers, useSystemFont: self.useSystemFont, fontSize: self.fontSize, listsFontSize: self.listsFontSize, automaticThemeSwitchSetting: automaticThemeSwitchSetting, largeEmoji: self.largeEmoji, disableAnimations: self.disableAnimations)
|
||||
return PresentationThemeSettings(theme: self.theme, themeSpecificAccentColors: self.themeSpecificAccentColors, themeSpecificChatWallpapers: self.themeSpecificChatWallpapers, useSystemFont: self.useSystemFont, fontSize: self.fontSize, listsFontSize: self.listsFontSize, chatBubbleSettings: self.chatBubbleSettings, automaticThemeSwitchSetting: automaticThemeSwitchSetting, largeEmoji: self.largeEmoji, disableAnimations: self.disableAnimations)
|
||||
}
|
||||
|
||||
public func withUpdatedLargeEmoji(_ largeEmoji: Bool) -> PresentationThemeSettings {
|
||||
return PresentationThemeSettings(theme: self.theme, themeSpecificAccentColors: self.themeSpecificAccentColors, themeSpecificChatWallpapers: self.themeSpecificChatWallpapers, useSystemFont: self.useSystemFont, fontSize: self.fontSize, listsFontSize: self.listsFontSize, automaticThemeSwitchSetting: self.automaticThemeSwitchSetting, largeEmoji: largeEmoji, disableAnimations: self.disableAnimations)
|
||||
return PresentationThemeSettings(theme: self.theme, themeSpecificAccentColors: self.themeSpecificAccentColors, themeSpecificChatWallpapers: self.themeSpecificChatWallpapers, useSystemFont: self.useSystemFont, fontSize: self.fontSize, listsFontSize: self.listsFontSize, chatBubbleSettings: self.chatBubbleSettings, automaticThemeSwitchSetting: self.automaticThemeSwitchSetting, largeEmoji: largeEmoji, disableAnimations: self.disableAnimations)
|
||||
}
|
||||
|
||||
public func withUpdatedDisableAnimations(_ disableAnimations: Bool) -> PresentationThemeSettings {
|
||||
return PresentationThemeSettings(theme: self.theme, themeSpecificAccentColors: self.themeSpecificAccentColors, themeSpecificChatWallpapers: self.themeSpecificChatWallpapers, useSystemFont: self.useSystemFont, fontSize: self.fontSize, listsFontSize: self.listsFontSize, automaticThemeSwitchSetting: self.automaticThemeSwitchSetting, largeEmoji: self.largeEmoji, disableAnimations: disableAnimations)
|
||||
return PresentationThemeSettings(theme: self.theme, themeSpecificAccentColors: self.themeSpecificAccentColors, themeSpecificChatWallpapers: self.themeSpecificChatWallpapers, useSystemFont: self.useSystemFont, fontSize: self.fontSize, listsFontSize: self.listsFontSize, chatBubbleSettings: self.chatBubbleSettings, automaticThemeSwitchSetting: self.automaticThemeSwitchSetting, largeEmoji: self.largeEmoji, disableAnimations: disableAnimations)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user