Merge commit 'bab231a71f5d11524f251185a7eb35ba338bb1d6'

This commit is contained in:
Ali 2019-11-19 23:30:10 +04:00
commit b35f84e794
20 changed files with 718 additions and 189 deletions

View File

@ -66,10 +66,8 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
self.addSubnode(self.contentNode)
}
override public func layout() {
super.layout()
self.contentNode.bounds = self.bounds
self.contentNode.position = CGPoint(x: self.bounds.midX, y: self.bounds.midY)
self.updateScale()
public func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
transition.updatePosition(node: self.contentNode, position: CGPoint(x: size.width / 2.0, y: size.height / 2.0))
transition.updateBounds(node: self.contentNode, bounds: CGRect(origin: CGPoint(), size: size))
}
}

View File

@ -125,8 +125,8 @@ private func encodeText(_ string: String, _ key: Int) -> String {
return result
}
public func doesViewTreeDisableInteractiveTransitionGestureRecognizer(_ view: UIView) -> Bool {
if view.disablesInteractiveTransitionGestureRecognizer {
public func doesViewTreeDisableInteractiveTransitionGestureRecognizer(_ view: UIView, keyboardOnly: Bool = false) -> Bool {
if view.disablesInteractiveTransitionGestureRecognizer && !keyboardOnly {
return true
}
if view.disablesInteractiveKeyboardGestureRecognizer {
@ -136,7 +136,7 @@ public func doesViewTreeDisableInteractiveTransitionGestureRecognizer(_ view: UI
return true
}
if let superview = view.superview {
return doesViewTreeDisableInteractiveTransitionGestureRecognizer(superview)
return doesViewTreeDisableInteractiveTransitionGestureRecognizer(superview, keyboardOnly: keyboardOnly)
}
return false
}
@ -1065,7 +1065,7 @@ public class Window1 {
if let inputHeight = self.windowLayout.inputHeight, !inputHeight.isZero, keyboardGestureBeginLocation.y < self.windowLayout.size.height - inputHeight - (accessoryHeight ?? 0.0) {
var enableGesture = true
if let view = self.hostView.containerView.hitTest(location, with: nil) {
if doesViewTreeDisableInteractiveTransitionGestureRecognizer(view) {
if doesViewTreeDisableInteractiveTransitionGestureRecognizer(view, keyboardOnly: true) {
enableGesture = false
}
}

View File

@ -119,6 +119,8 @@ class ForwardPrivacyChatPreviewItemNode: ListViewItemNode {
super.init(layerBacked: false, dynamicBounce: false)
self.clipsToBounds = true
self.addSubnode(self.containerNode)
self.tooltipContainerNode.addSubnode(self.textNode)
@ -134,8 +136,13 @@ class ForwardPrivacyChatPreviewItemNode: ListViewItemNode {
return { item, params, neighbors in
var updatedBackgroundImage: UIImage?
var backgroundImageContentMode = UIView.ContentMode.scaleAspectFill
if currentItem?.wallpaper != item.wallpaper {
updatedBackgroundImage = chatControllerBackgroundImage(theme: item.theme, wallpaper: item.wallpaper, mediaBox: item.context.sharedContext.accountManager.mediaBox, knockoutMode: item.context.sharedContext.immediateExperimentalUISettings.knockoutWallpaper)
if case .gradient = item.wallpaper {
backgroundImageContentMode = .scaleToFill
}
}
let insets: UIEdgeInsets
@ -222,6 +229,7 @@ class ForwardPrivacyChatPreviewItemNode: ListViewItemNode {
if let updatedBackgroundImage = updatedBackgroundImage {
strongSelf.backgroundNode.image = updatedBackgroundImage
strongSelf.backgroundNode.contentMode = backgroundImageContentMode
}
strongSelf.topStripeNode.backgroundColor = item.theme.list.itemBlocksSeparatorColor
strongSelf.bottomStripeNode.backgroundColor = item.theme.list.itemBlocksSeparatorColor
@ -263,8 +271,9 @@ class ForwardPrivacyChatPreviewItemNode: ListViewItemNode {
strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.theme, top: hasTopCorners, bottom: hasBottomCorners) : nil
strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight)))
strongSelf.maskNode.frame = strongSelf.backgroundNode.frame.insetBy(dx: params.leftInset, dy: 0.0)
let backgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight)))
strongSelf.backgroundNode.frame = backgroundFrame.insetBy(dx: 0.0, dy: -100.0)
strongSelf.maskNode.frame = backgroundFrame.insetBy(dx: params.leftInset, dy: 0.0)
strongSelf.topStripeNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: layoutSize.width, height: separatorHeight))
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height + bottomStripeOffset), size: CGSize(width: layoutSize.width - bottomStripeInset, height: separatorHeight))

View File

@ -0,0 +1,345 @@
import UIKit
import Display
private let colorPairs: [(UInt32, UInt32)] = [
(0xbdc3c7, 0x2c3e50),
(0xee9ca7, 0xffdde1),
(0x2193b0, 0x6dd5ed),
(0xb92b27, 0x1565c0),
(0x373b44, 0x4286f4),
(0xff0099, 0x493240),
(0x8e2de2, 0x4a00e0),
(0x1f4037, 0x99f2c8),
(0xf953c6, 0xb91d73),
(0xc31432, 0x240b36),
(0xf12711, 0xf5af19),
(0x659999, 0xf4791f),
(0xdd3e54, 0x6be585),
(0x8360c3, 0x2ebf91),
(0x544a7d, 0xffd452),
(0x009fff, 0xec2f4b),
(0x654ea3, 0xeaafc8),
(0xff416c, 0xff4b2b),
(0xa8ff78, 0x78ffd6),
(0xed213a, 0x93291e),
(0xfdc830, 0xf37335),
(0x00b4db, 0x0083b0),
(0xffefba, 0xffffff),
(0x005aa7, 0xfffde4),
(0xda4453, 0x89216b),
(0x636363, 0xa2ab58),
(0xad5389, 0x3c1053),
(0xa8c0ff, 0x3f2b96),
(0x333333, 0xdd1818),
(0x4e54c8, 0x8f94fb),
(0xbc4e9c, 0xf80759),
(0x3e5151, 0xdecba4),
(0x11998e, 0x38ef7d),
(0x108dc7, 0xef8e38),
(0xfc5c7d, 0x6a82fb),
(0xfc466b, 0x3f5efb),
(0xc94b4b, 0x4b134f),
(0x23074d, 0xcc5333),
(0xfffbd5, 0xb20a2c),
(0x00b09b, 0x96c93d),
(0xd3cce3, 0xe9e4f0),
(0x3c3b3f, 0x605c3c),
(0xcac531, 0xf3f9a7),
(0x800080, 0xffc0cb),
(0x00f260, 0x0575e6),
(0xfc4a1a, 0xf7b733),
(0x74ebd5, 0xacb6e5),
(0x6d6027, 0xd3cbb8),
(0xe1eec3, 0xf05053),
(0x22c1c3, 0xfdbb2d),
(0xff9966, 0xff5e62),
(0x7f00ff, 0xe100ff),
(0xc9d6ff, 0xe2e2e2),
(0x396afc, 0x2948ff),
(0xd9a7c7, 0xfffcdc),
(0x06beb6, 0x48b1bf),
(0x642b73, 0xc6426e),
(0x1c92d2, 0xf2fcfe),
(0x000000, 0x0f9b0f),
(0x36d1dc, 0x5b86e5),
(0xcb356b, 0xbd3f32),
(0x283c86, 0x45a247),
(0xef3b36, 0xffffff),
(0xc0392b, 0x8e44ad),
(0x159957, 0x155799),
(0x000046, 0x1cb5e0),
(0x007991, 0x78ffd6),
(0x56ccf2, 0x2f80ed),
(0xf2994a, 0xf2c94c),
(0xeb5757, 0x000000),
(0xe44d26, 0xf16529),
(0x4ac29a, 0xbdfff3),
(0xb2fefa, 0x0ed2f7),
(0x30e8bf, 0xff8235),
(0xd66d75, 0xe29587),
(0x20002c, 0xcbb4d4),
(0xc33764, 0x1d2671),
(0xf7971e, 0xffd200),
(0x34e89e, 0x0f3443),
(0x6190e8, 0xa7bfe8),
(0x44a08d, 0x093637),
(0x200122, 0x6f0000),
(0x0575e6, 0x021b79),
(0x4568dc, 0xb06ab3),
(0x43c6ac, 0x191654),
(0x093028, 0x237a57),
(0x43c6ac, 0xf8ffae),
(0xffafbd, 0xffc3a0),
(0xf0f2f0, 0x000c40),
(0xe8cbc0, 0x636fa4),
(0xdce35b, 0x45b649),
(0xc0c0aa, 0x1cefff),
(0xdbe6f6, 0xc5796d),
(0x3494e6, 0xec6ead),
(0x67b26f, 0x4ca2cd),
(0xf3904f, 0x3b4371),
(0xee0979, 0xff6a00),
(0x41295a, 0x2f0743),
(0xf4c4f3, 0xfc67fa),
(0x00c3ff, 0xffff1c),
(0xff7e5f, 0xfeb47b),
(0xfffc00, 0xffffff),
(0xff00cc, 0x333399),
(0xde6161, 0x2657eb),
(0xef32d9, 0x89fffd),
(0x3a6186, 0x89253e),
(0x4ecdc4, 0x556270),
(0xa1ffce, 0xfaffd1),
(0xbe93c5, 0x7bc6cc),
(0xbdc3c7, 0x2c3e50),
(0xffd89b, 0x19547b),
(0x808080, 0x3fada8),
(0xfceabb, 0xf8b500),
(0xf85032, 0xe73827),
(0xf79d00, 0x64f38c),
(0xcb2d3e, 0xef473a),
(0x56ab2f, 0xa8e063),
(0x000428, 0x004e92),
(0x42275a, 0x734b6d),
(0x141e30, 0x243b55),
(0xf00000, 0xdc281e),
(0x2c3e50, 0xfd746c),
(0x2c3e50, 0x4ca1af),
(0xe96443, 0x904e95),
(0x0b486b, 0xf56217),
(0x3a7bd5, 0x3a6073),
(0x00d2ff, 0x928dab),
(0x2196f3, 0xf44336),
(0xff5f6d, 0xffc371),
(0xff4b1f, 0xff9068),
(0x16bffd, 0xcb3066),
(0xeecda3, 0xef629f),
(0x1d4350, 0xa43931),
(0xa80077, 0x66ff00),
(0xf7ff00, 0xdb36a4),
(0xff4b1f, 0x1fddff),
(0xba5370, 0xf4e2d8),
(0xe0eafc, 0xcfdef3),
(0x4ca1af, 0xc4e0e5),
(0x000000, 0x434343),
(0x4b79a1, 0x283e51),
(0x834d9b, 0xd04ed6),
(0x0099f7, 0xf11712),
(0x2980b9, 0x2c3e50),
(0x5a3f37, 0x2c7744),
(0x4da0b0, 0xd39d38),
(0x5614b0, 0xdbd65c),
(0x2f7336, 0xaa3a38),
(0x1e3c72, 0x2a5298),
(0x114357, 0xf29492),
(0xfd746c, 0xff9068),
(0xeacda3, 0xd6ae7b),
(0x6a3093, 0xa044ff),
(0x457fca, 0x5691c8),
(0xb24592, 0xf15f79),
(0xc02425, 0xf0cb35),
(0x403a3e, 0xbe5869),
(0xc2e59c, 0x64b3f4),
(0xffb75e, 0xed8f03),
(0x8e0e00, 0x1f1c18),
(0x76b852, 0x8dc26f),
(0x673ab7, 0x512da8),
(0x00c9ff, 0x92fe9d),
(0xf46b45, 0xeea849),
(0x005c97, 0x363795),
(0xe53935, 0xe35d5b),
(0xfc00ff, 0x00dbde),
(0x2c3e50, 0x3498db),
(0xccccb2, 0x757519),
(0x304352, 0xd7d2cc),
(0xee9ca7, 0xffdde1),
(0xba8b02, 0x181818),
(0x525252, 0x3d72b4),
(0x004ff9, 0xfff94c),
(0x6a9113, 0x141517),
(0xf1f2b5, 0x135058),
(0xd1913c, 0xffd194),
(0x7b4397, 0xdc2430),
(0x8e9eab, 0xeef2f3),
(0x136a8a, 0x267871),
(0x00bf8f, 0x001510),
(0xff0084, 0x33001b),
(0x6441a5, 0x2a0845),
(0xffb347, 0xffcc33),
(0x43cea2, 0x185a9d),
(0xffa17f, 0x00223e),
(0x360033, 0x0b8793),
(0x948e99, 0x2e1437),
(0x1e130c, 0x9a8478),
(0xd38312, 0xa83279),
(0x73c8a9, 0x373b44),
(0xabbaab, 0xffffff),
(0xfdfc47, 0x24fe41),
(0x83a4d4, 0xb6fbff),
(0x485563, 0x29323c),
(0x52c234, 0x061700),
(0xfe8c00, 0xf83600),
(0x00c6ff, 0x0072ff),
(0x70e1f5, 0xffd194),
(0x556270, 0xff6b6b),
(0x9d50bb, 0x6e48aa),
(0x780206, 0x061161),
(0xb3ffab, 0x12fff7),
(0xaaffa9, 0x11ffbd),
(0x000000, 0xe74c3c),
(0xf0c27b, 0x4b1248),
(0xff4e50, 0xf9d423),
(0xadd100, 0x7b920a),
(0xfbd3e9, 0xbb377d),
(0x606c88, 0x3f4c6b),
(0xc9ffbf, 0xffafbd),
(0x649173, 0xdbd5a4),
(0xb993d6, 0x8ca6db),
(0x870000, 0x190a05),
(0x00d2ff, 0x3a7bd5),
(0xd3959b, 0xbfe6ba),
(0xdad299, 0xb0dab9),
(0xf2709c, 0xff9472),
(0xe6dada, 0x274046),
(0x5d4157, 0xa8caba),
(0xddd6f3, 0xfaaca8),
(0x616161, 0x9bc5c3),
(0x50c9c3, 0x96deda),
(0x215f00, 0xe4e4d9),
(0xc21500, 0xffc500),
(0xefefbb, 0xd4d3dd),
(0xffeeee, 0xddefbb),
(0x666600, 0x999966),
(0xde6262, 0xffb88c),
(0xe9d362, 0x333333),
(0xd53369, 0xcbad6d),
(0xa73737, 0x7a2828),
(0xf857a6, 0xff5858),
(0x4b6cb7, 0x182848),
(0xfc354c, 0x0abfbc),
(0x414d0b, 0x727a17),
(0xe43a15, 0xe65245),
(0xc04848, 0x480048),
(0x5f2c82, 0x49a09d),
(0xec6f66, 0xf3a183),
(0x7474bf, 0x348ac7),
(0xece9e6, 0xffffff),
(0xdae2f8, 0xd6a4a4),
(0xed4264, 0xffedbc),
(0xdc2424, 0x4a569d),
(0x24c6dc, 0x514a9d),
(0x283048, 0x859398),
(0x3d7eaa, 0xffe47a),
(0x1cd8d2, 0x93edc7),
(0x232526, 0x414345),
(0x757f9a, 0xd7dde8),
(0x5c258d, 0x4389a2),
(0x134e5e, 0x71b280),
(0x2bc0e4, 0xeaecc6),
(0x085078, 0x85d8ce),
(0x4776e6, 0x8e54e9),
(0x614385, 0x516395),
(0x1f1c2c, 0x928dab),
(0x16222a, 0x3a6073),
(0xff8008, 0xffc837),
(0x1d976c, 0x93f9b9),
(0xeb3349, 0xf45c43),
(0xdd5e89, 0xf7bb97),
(0x4cb8c4, 0x3cd3ad),
(0x1d2b64, 0xf8cdda),
(0xff512f, 0xf09819),
(0x1a2980, 0x26d0ce),
(0xaa076b, 0x61045f),
(0xff512f, 0xdd2476),
(0xf09819, 0xedde5d),
(0x403b4a, 0xe7e9bb),
(0xe55d87, 0x5fc3e4),
(0x003973, 0xe5e5be),
(0x3ca55c, 0xb5ac49),
(0x348f50, 0x56b4d3),
(0xda22ff, 0x9733ee),
(0x02aab0, 0x00cdac),
(0xede574, 0xe1f5c4),
(0xd31027, 0xea384d),
(0x16a085, 0xf4d03f),
(0x603813, 0xb29f94),
(0xe52d27, 0xb31217),
(0xff6e7f, 0xbfe9ff),
(0x314755, 0x26a0da),
(0x2b5876, 0x4e4376),
(0xe65c00, 0xf9d423),
(0x2193b0, 0x6dd5ed),
(0xcc2b5e, 0x753a88),
(0xec008c, 0xfc6767),
(0x1488cc, 0x2b32b2),
(0x00467f, 0xa5cc82),
(0x076585, 0xffffff),
(0xbbd2c5, 0x536976),
(0x9796f0, 0xfbc7d4),
(0xb79891, 0x94716b),
(0x536976, 0x292e49),
(0xacb6e5, 0x86fde8),
(0xffe000, 0x799f0c),
(0x00416a, 0xe4e5e6),
(0xffe259, 0xffa751),
(0x799f0c, 0xacbb78),
(0x334d50, 0xcbcaa5),
(0xf7f8f8, 0xacbb78),
(0xffe000, 0x799f0c),
(0x00416a, 0xe4e5e6)
]
func generateGradientColors(color: UIColor) -> (UIColor, UIColor) {
var nearest: (colors: (lhs: UInt32, rhs: UInt32), distance: Int32)?
for (lhs, rhs) in colorPairs {
let lhsDistance = color.distance(to: UIColor(rgb: lhs))
let rhsDistance = color.distance(to: UIColor(rgb: lhs))
if let currentNearest = nearest {
if lhsDistance < currentNearest.distance || rhsDistance < currentNearest.distance {
if lhsDistance < rhsDistance {
nearest = ((lhs, rhs), lhsDistance)
} else {
nearest = ((rhs, lhs), rhsDistance)
}
}
} else {
if lhsDistance < rhsDistance {
nearest = ((lhs, rhs), lhsDistance)
} else {
nearest = ((rhs, lhs), rhsDistance)
}
}
}
if let colors = nearest?.colors {
var colorHsv = color.hsv
var similarColorHsv = UIColor(rgb: colors.0).hsv
var complementingColorHsv = UIColor(rgb: colors.1).hsv
var correction = (similarColorHsv.0 > 0.0 ? colorHsv.0 / similarColorHsv.0 : 1.0, similarColorHsv.1 > 0.0 ? colorHsv.1 / similarColorHsv.1 : 1.0, similarColorHsv.2 > 0.0 ? colorHsv.2 / similarColorHsv.2 : 1.0)
var correctedComplementingColor = UIColor(hue: min(1.0, complementingColorHsv.0 * correction.0), saturation: min(1.0, complementingColorHsv.1 * correction.1), brightness: min(1.0, complementingColorHsv.2 * correction.2), alpha: 1.0)
return (color, correctedComplementingColor)
} else {
return (color, color)
}
}

View File

@ -103,7 +103,7 @@ private let colors: [UInt32: String] = [
0x54a5f8: "Blue"
]
private let adjectives = [
private let adjectives: [String] = [
"Ancient",
"Antique",
"Autumn",
@ -213,7 +213,7 @@ private let adjectives = [
"Winsome"
]
private let subjectives = [
private let subjectives: [String] = [
"Ambrosia",
"Attack",
"Avalanche",
@ -301,7 +301,7 @@ func generateThemeName(accentColor: UIColor) -> String {
var nearest: (color: UInt32, distance: Int32)?
for (color, _) in colors {
let distance = accentColor.distance(to: UIColor(rgb: color))
if let currentNearest = nearest {
if let currentNearest = nearest {
if distance < currentNearest.distance {
nearest = (color, distance)
}
@ -312,7 +312,6 @@ func generateThemeName(accentColor: UIColor) -> String {
if let color = nearest?.color, let colorName = colors[color]?.capitalized {
if arc4random() % 2 == 0 {
return "\((adjectives.randomElement() ?? "").capitalized) \(colorName)"
} else {
return "\(colorName) \((subjectives.randomElement() ?? "").capitalized)"

View File

@ -143,6 +143,7 @@ final class ThemeAccentColorController: ViewController {
self.controllerNode.themeUpdated = { [weak self] theme in
if let strongSelf = self {
strongSelf.navigationBar?.updatePresentationData(NavigationBarPresentationData(presentationTheme: theme, presentationStrings: strongSelf.presentationData.strings))
strongSelf.segmentedTitleView.theme = theme
}
}

View File

@ -203,19 +203,25 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
case .accent:
strongSelf.updateState({ current in
var updated = current
updated.accentColor = firstColor
if let firstColor = firstColor {
updated.accentColor = firstColor
}
return updated
})
case .background:
strongSelf.updateState({ current in
var updated = current
updated.backgroundColors = (firstColor, secondColor)
if let firstColor = firstColor {
updated.backgroundColors = (firstColor, secondColor)
}
return updated
})
case .messages:
strongSelf.updateState({ current in
var updated = current
updated.messagesColors = (firstColor, secondColor)
if let firstColor = firstColor {
updated.messagesColors = (firstColor, secondColor)
}
return updated
})
}
@ -313,6 +319,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
override func didLoad() {
super.didLoad()
self.scrollNode.view.bounces = false
self.scrollNode.view.disablesInteractiveTransitionGestureRecognizer = true
self.scrollNode.view.showsHorizontalScrollIndicator = false
self.scrollNode.view.isPagingEnabled = true
@ -615,7 +622,10 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
self.colorPanelNode.updateLayout(size: colorPanelFrame.size, transition: transition)
transition.updateFrame(node: self.messagesContainerNode, frame: CGRect(x: 0.0, y: navigationBarHeight, width: bounds.width, height: bounds.height - bottomInset - navigationBarHeight))
transition.updateFrame(node: self.chatBackgroundNode, frame: CGRect(x: 0.0, y: 0.0, width: bounds.width, height: bounds.height - (colorPanelHeight - colorPanelOffset)))
let backgroundSize = CGSize(width: bounds.width, height: bounds.height - (colorPanelHeight - colorPanelOffset))
transition.updateFrame(node: self.chatBackgroundNode, frame: CGRect(origin: CGPoint(), size: backgroundSize))
self.chatBackgroundNode.updateLayout(size: backgroundSize, transition: transition)
var messagesBottomInset: CGFloat = 0.0
if pageControlAlpha > 0.0 {

View File

@ -212,7 +212,7 @@ public final class ThemePreviewController: ViewController {
var resolvedWallpaper: TelegramWallpaper?
let signal = theme
let setup = theme
|> mapToSignal { theme -> Signal<PresentationThemeReference, NoError> in
guard let theme = theme else {
return .complete()
@ -317,7 +317,7 @@ public final class ThemePreviewController: ViewController {
}
var cancelImpl: (() -> Void)?
let progressSignal = Signal<Never, NoError> { [weak self] subscriber in
let progress = Signal<Never, NoError> { [weak self] subscriber in
let controller = OverlayStatusController(theme: presentationData.theme, type: .loading(cancelled: {
cancelImpl?()
}))
@ -331,11 +331,11 @@ public final class ThemePreviewController: ViewController {
|> runOn(Queue.mainQueue())
|> delay(0.35, queue: Queue.mainQueue())
let progressDisposable = progressSignal.start()
let progressDisposable = progress.start()
cancelImpl = {
disposable.set(nil)
}
disposable.set((signal
disposable.set((setup
|> afterDisposed {
Queue.mainQueue().async {
progressDisposable.dispose()
@ -343,7 +343,9 @@ public final class ThemePreviewController: ViewController {
}
|> deliverOnMainQueue).start(completed: {[weak self] in
if let strongSelf = self {
strongSelf.dismiss()
Queue.mainQueue().after(0.3) {
strongSelf.dismiss()
}
}
}))
}

View File

@ -279,6 +279,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
override func didLoad() {
super.didLoad()
self.scrollNode.view.bounces = false
self.scrollNode.view.disablesInteractiveTransitionGestureRecognizer = true
self.scrollNode.view.showsHorizontalScrollIndicator = false
self.scrollNode.view.isPagingEnabled = true
@ -552,6 +553,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.messagesContainerNode.frame = self.chatContainerNode.bounds
self.instantChatBackgroundNode.frame = self.chatContainerNode.bounds
self.instantChatBackgroundNode.updateLayout(size: self.instantChatBackgroundNode.bounds.size, transition: .immediate)
self.remoteChatBackgroundNode.frame = self.chatContainerNode.bounds
self.blurredNode.frame = self.chatContainerNode.bounds

View File

@ -123,6 +123,8 @@ class ThemeSettingsChatPreviewItemNode: ListViewItemNode {
super.init(layerBacked: false, dynamicBounce: false)
self.clipsToBounds = true
self.addSubnode(self.containerNode)
}
@ -133,8 +135,13 @@ class ThemeSettingsChatPreviewItemNode: ListViewItemNode {
return { item, params, neighbors in
var updatedBackgroundImage: UIImage?
var backgroundImageContentMode = UIView.ContentMode.scaleAspectFill
if currentItem?.wallpaper != item.wallpaper {
updatedBackgroundImage = chatControllerBackgroundImage(theme: item.theme, wallpaper: item.wallpaper, mediaBox: item.context.sharedContext.accountManager.mediaBox, knockoutMode: item.context.sharedContext.immediateExperimentalUISettings.knockoutWallpaper)
if case .gradient = item.wallpaper {
backgroundImageContentMode = .scaleToFill
}
}
let insets: UIEdgeInsets
@ -216,6 +223,7 @@ class ThemeSettingsChatPreviewItemNode: ListViewItemNode {
if let updatedBackgroundImage = updatedBackgroundImage {
strongSelf.backgroundNode.image = updatedBackgroundImage
strongSelf.backgroundNode.contentMode = backgroundImageContentMode
}
strongSelf.topStripeNode.backgroundColor = item.theme.list.itemBlocksSeparatorColor
strongSelf.bottomStripeNode.backgroundColor = item.theme.list.itemBlocksSeparatorColor
@ -258,8 +266,9 @@ class ThemeSettingsChatPreviewItemNode: ListViewItemNode {
strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.theme, top: hasTopCorners, bottom: hasBottomCorners) : nil
strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight)))
strongSelf.maskNode.frame = strongSelf.backgroundNode.frame.insetBy(dx: params.leftInset, dy: 0.0)
let backgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight)))
strongSelf.backgroundNode.frame = backgroundFrame.insetBy(dx: 0.0, dy: -100.0)
strongSelf.maskNode.frame = backgroundFrame.insetBy(dx: params.leftInset, dy: 0.0)
strongSelf.topStripeNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: layoutSize.width, height: separatorHeight))
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height + bottomStripeOffset), size: CGSize(width: layoutSize.width - bottomStripeInset, height: separatorHeight))
}

View File

@ -477,14 +477,16 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
var themeSpecificChatWallpapers = current.themeSpecificChatWallpapers
var themeSpecificAccentColors = current.themeSpecificAccentColors
var themeSpecificBubbleColors = current.themeSpecificBubbleColors
themeSpecificAccentColors[currentTheme.index] = color
themeSpecificBubbleColors[currentTheme.index] = nil
if let wallpaper = current.themeSpecificChatWallpapers[currentTheme.index], wallpaper.hasWallpaper {
} else {
themeSpecificChatWallpapers[currentTheme.index] = theme.chat.defaultWallpaper
}
return PresentationThemeSettings(theme: current.theme, themeSpecificAccentColors: themeSpecificAccentColors, themeSpecificBubbleColors: current.themeSpecificBubbleColors, themeSpecificChatWallpapers: themeSpecificChatWallpapers, useSystemFont: current.useSystemFont, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, largeEmoji: current.largeEmoji, disableAnimations: current.disableAnimations)
return PresentationThemeSettings(theme: current.theme, themeSpecificAccentColors: themeSpecificAccentColors, themeSpecificBubbleColors: themeSpecificBubbleColors, themeSpecificChatWallpapers: themeSpecificChatWallpapers, useSystemFont: current.useSystemFont, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, largeEmoji: current.largeEmoji, disableAnimations: current.disableAnimations)
}).start()
}, openAccentColorPicker: { themeReference in
let controller = ThemeAccentColorController(context: context, themeReference: themeReference, section: .accent)

View File

@ -31,10 +31,36 @@ private func textInputBackgroundImage(fieldColor: UIColor, strokeColor: UIColor,
}
}
private func generateSwatchImage(theme: PresentationTheme, color: UIColor) -> UIImage? {
return generateImage(CGSize(width: 21.0, height: 21.0), rotatedContext: { size, context in
let bounds = CGRect(origin: CGPoint(), size: size)
context.clear(bounds)
let fillColor = color
var strokeColor: UIColor?
let inputBackgroundColor = theme.chat.inputPanel.inputBackgroundColor
if fillColor.distance(to: inputBackgroundColor) < 200 {
strokeColor = theme.chat.inputPanel.inputStrokeColor
if strokeColor!.distance(to: inputBackgroundColor) < 200 {
strokeColor = theme.chat.inputPanel.inputControlColor
}
}
context.setFillColor(fillColor.cgColor)
context.setLineWidth(1.0)
context.fillEllipse(in: bounds)
if let strokeColor = strokeColor {
context.setStrokeColor(strokeColor.cgColor)
context.strokeEllipse(in: bounds.insetBy(dx: 1.0, dy: 1.0))
}
})
}
private class ColorInputFieldNode: ASDisplayNode, UITextFieldDelegate {
private var theme: PresentationTheme
private let swatchNode: ASDisplayNode
private let swatchNode: ASImageNode
private let removeButton: HighlightableButtonNode
private let textBackgroundNode: ASImageNode
private let selectionNode: ASDisplayNode
@ -48,18 +74,14 @@ private class ColorInputFieldNode: ASDisplayNode, UITextFieldDelegate {
var colorRemoved: (() -> Void)?
var colorSelected: (() -> Void)?
private var color: UIColor?
private var isDefault = false {
didSet {
self.updateSelectionVisibility()
}
}
var color: UIColor = .white {
didSet {
self.setColor(self.color, update: false)
}
}
var isRemovable: Bool = false {
didSet {
self.removeButton.isUserInteractionEnabled = self.isRemovable
@ -78,7 +100,9 @@ private class ColorInputFieldNode: ASDisplayNode, UITextFieldDelegate {
private var previousIsDefault: Bool?
private var previousColor: UIColor?
private var validLayout: CGSize?
private var validLayout: (CGSize, Bool)?
private var returned = false
init(theme: PresentationTheme) {
self.theme = theme
@ -99,8 +123,9 @@ private class ColorInputFieldNode: ASDisplayNode, UITextFieldDelegate {
self.prefixNode = ASTextNode()
self.prefixNode.attributedText = NSAttributedString(string: "#", font: Font.regular(17.0), textColor: self.theme.chat.inputPanel.inputTextColor)
self.swatchNode = ASDisplayNode()
self.swatchNode.cornerRadius = 10.5
self.swatchNode = ASImageNode()
self.swatchNode.displaysAsynchronously = false
self.swatchNode.displayWithoutProcessing = true
self.removeButton = HighlightableButtonNode()
self.removeButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Settings/ThemeColorRemoveIcon"), color: theme.chat.inputPanel.inputControlColor), for: .normal)
@ -150,21 +175,24 @@ private class ColorInputFieldNode: ASDisplayNode, UITextFieldDelegate {
}
func setColor(_ color: UIColor, isDefault: Bool = false, update: Bool = true, ended: Bool = true) {
self.color = color
self.isDefault = isDefault
let text = color.hexString.uppercased()
self.textFieldNode.textField.text = text
self.textFieldNode.textField.textColor = isDefault ? self.theme.chat.inputPanel.inputPlaceholderColor : self.theme.chat.inputPanel.inputTextColor
if let size = self.validLayout {
if let (size, _) = self.validLayout {
self.updateSelectionLayout(size: size, transition: .immediate)
}
if update {
self.colorChanged?(color, ended)
}
self.swatchNode.backgroundColor = color
self.swatchNode.image = generateSwatchImage(theme: self.theme, color: color)
}
@objc private func removePressed() {
self.colorRemoved?()
self.removeButton.layer.removeAnimation(forKey: "opacity")
self.removeButton.alpha = 1.0
}
@objc private func tapped() {
@ -178,7 +206,11 @@ private class ColorInputFieldNode: ASDisplayNode, UITextFieldDelegate {
textField.text = updated.uppercased()
textField.textColor = self.theme.chat.inputPanel.inputTextColor
if let size = self.validLayout {
if updated.count == 6, let color = UIColor(hexString: updated) {
self.setColor(color)
}
if let (size, _) = self.validLayout {
self.updateSelectionLayout(size: size, transition: .immediate)
}
}
@ -190,18 +222,25 @@ private class ColorInputFieldNode: ASDisplayNode, UITextFieldDelegate {
self.setColor(color)
}
if let size = self.validLayout {
if let (size, _) = self.validLayout {
self.updateSelectionLayout(size: size, transition: .immediate)
}
}
@objc func textFieldShouldReturn(_ textField: UITextField) -> Bool {
self.returned = true
if let text = self.textFieldNode.textField.text, text.count == 6, let color = UIColor(hexString: text) {
self.setColor(color)
} else {
self.setColor(self.previousColor ?? .black, isDefault: self.previousIsDefault ?? false)
}
self.textFieldNode.resignFirstResponder()
return false
}
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
if self.isSelected {
self.returned = false
self.previousColor = self.color
self.previousIsDefault = self.isDefault
@ -215,9 +254,7 @@ private class ColorInputFieldNode: ASDisplayNode, UITextFieldDelegate {
}
@objc func textFieldDidEndEditing(_ textField: UITextField) {
if let text = self.textFieldNode.textField.text, text.count == 6, let color = UIColor(hexString: text) {
self.setColor(color)
} else {
if !self.returned {
self.setColor(self.previousColor ?? .black, isDefault: self.previousIsDefault ?? false)
}
}
@ -225,28 +262,31 @@ private class ColorInputFieldNode: ASDisplayNode, UITextFieldDelegate {
private func updateSelectionLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
self.measureNode.attributedText = NSAttributedString(string: self.textFieldNode.textField.text ?? "", font: self.textFieldNode.textField.font)
let size = self.measureNode.updateLayout(size)
transition.updateFrame(node: self.selectionNode, frame: CGRect(x: 47.0, y: 6.0, width: max(45.0, size.width), height: 20.0))
transition.updateFrame(node: self.selectionNode, frame: CGRect(x: self.textFieldNode.frame.minX, y: 6.0, width: max(45.0, size.width), height: 20.0))
}
private func updateSelectionVisibility() {
self.selectionNode.isHidden = !self.isSelected || self.isDefault
}
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
self.validLayout = size
func updateLayout(size: CGSize, condensed: Bool, transition: ContainedViewLayoutTransition) {
self.validLayout = (size, condensed)
transition.updateFrame(node: self.swatchNode, frame: CGRect(origin: CGPoint(x: 6.0, y: 6.0), size: CGSize(width: 21.0, height: 21.0)))
let textPadding: CGFloat = condensed ? 31.0 : 37.0
transition.updateFrame(node: self.textBackgroundNode, frame: CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height))
transition.updateFrame(node: self.textFieldNode, frame: CGRect(x: 47.0, y: 1.0, width: size.width - 61.0, height: size.height - 2.0))
transition.updateFrame(node: self.textFieldNode, frame: CGRect(x: textPadding + 10.0, y: 1.0, width: size.width - (21.0 + textPadding), height: size.height - 2.0))
self.updateSelectionLayout(size: size, transition: transition)
let prefixSize = self.prefixNode.measure(size)
transition.updateFrame(node: self.prefixNode, frame: CGRect(origin: CGPoint(x: 37.0 - UIScreenPixel, y: 6.0), size: prefixSize))
transition.updateFrame(node: self.prefixNode, frame: CGRect(origin: CGPoint(x: textPadding - UIScreenPixel, y: 6.0), size: prefixSize))
let removeSize = CGSize(width: 33.0, height: 33.0)
transition.updateFrame(node: self.removeButton, frame: CGRect(origin: CGPoint(x: size.width - removeSize.width, y: 0.0), size: removeSize))
let removeOffset: CGFloat = condensed ? 3.0 : 0.0
transition.updateFrame(node: self.removeButton, frame: CGRect(origin: CGPoint(x: size.width - removeSize.width + removeOffset, y: 0.0), size: removeSize))
transition.updateAlpha(node: self.removeButton, alpha: self.isRemovable ? 1.0 : 0.0)
}
}
@ -280,7 +320,7 @@ final class WallpaperColorPanelNode: ASDisplayNode {
private let doneButton: HighlightableButtonNode
private let colorPickerNode: WallpaperColorPickerNode
var colorsChanged: ((UIColor, UIColor?, Bool) -> Void)?
var colorsChanged: ((UIColor?, UIColor?, Bool) -> Void)?
var colorSelected: (() -> Void)?
private var validLayout: CGSize?
@ -341,21 +381,23 @@ final class WallpaperColorPanelNode: ASDisplayNode {
strongSelf.updateState({ current in
var updated = current
updated.selection = .first
if let defaultColor = current.defaultColor {
if let defaultColor = current.defaultColor, updated.secondColor == nil {
updated.firstColor = nil
} else {
updated.firstColor = updated.secondColor ?? updated.firstColor
}
updated.secondColor = nil
return updated
}, animated: strongSelf.state.defaultColor == nil)
}, animated: strongSelf.state.secondColor != nil)
}
}
self.firstColorFieldNode.colorSelected = { [weak self] in
if let strongSelf = self {
strongSelf.updateState({ current in
var updated = current
updated.selection = .first
if updated.selection != .none {
updated.selection = .first
}
return updated
})
@ -376,7 +418,9 @@ final class WallpaperColorPanelNode: ASDisplayNode {
if let strongSelf = self {
strongSelf.updateState({ current in
var updated = current
updated.selection = .first
if updated.selection != .none {
updated.selection = .first
}
updated.secondColor = nil
return updated
})
@ -423,7 +467,7 @@ final class WallpaperColorPanelNode: ASDisplayNode {
break
}
return updated
}, updateLayout: true)
}, updateLayout: false)
}
}
}
@ -443,15 +487,21 @@ final class WallpaperColorPanelNode: ASDisplayNode {
self.state = f(self.state)
let firstColor: UIColor
var firstColorIsDefault = false
if let color = self.state.firstColor {
firstColor = color
} else if let defaultColor = self.state.defaultColor {
firstColor = defaultColor
firstColorIsDefault = true
} else {
firstColor = .white
}
let secondColor = self.state.secondColor
if secondColor == nil && previousSecondColor != nil && firstColor == previousSecondColor && animated {
self.animateLeftColorFieldOut()
}
self.firstColorFieldNode.setColor(firstColor, isDefault: self.state.firstColor == nil, update: false)
if let secondColor = secondColor {
self.secondColorFieldNode.setColor(secondColor, update: false)
@ -473,13 +523,66 @@ final class WallpaperColorPanelNode: ASDisplayNode {
}
if self.state.firstColor?.rgb != previousFirstColor?.rgb || self.state.secondColor?.rgb != previousSecondColor?.rgb {
self.colorsChanged?(firstColor, secondColor, updateLayout)
self.colorsChanged?(firstColorIsDefault ? nil : firstColor, secondColor, updateLayout)
}
}
private func animateLeftColorFieldOut() {
guard let size = self.validLayout else {
return
}
let condensedLayout = size.width < 375.0
let leftInset: CGFloat
let fieldSpacing: CGFloat
if condensedLayout {
leftInset = 6.0
fieldSpacing = 40.0
} else {
leftInset = 15.0
fieldSpacing = 45.0
}
let rightInsetWithButton: CGFloat = 42.0
let offset: CGFloat = -(self.secondColorFieldNode.frame.minX - leftInset)
if let fieldSnapshotView = self.firstColorFieldNode.view.snapshotView(afterScreenUpdates: false) {
fieldSnapshotView.frame = self.firstColorFieldNode.frame
self.view.addSubview(fieldSnapshotView)
fieldSnapshotView.layer.animatePosition(from: CGPoint(), to: CGPoint(x: offset, y: 0.0), duration: 0.3, delay: 0.0, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, removeOnCompletion: false, additive: true, force: false) { _ in
fieldSnapshotView.removeFromSuperview()
}
}
if let buttonSnapshotView = self.swapButton.view.snapshotContentTree() {
buttonSnapshotView.frame = self.swapButton.frame
self.view.addSubview(buttonSnapshotView)
buttonSnapshotView.layer.animatePosition(from: CGPoint(), to: CGPoint(x: offset, y: 0.0), duration: 0.3, delay: 0.0, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, removeOnCompletion: false, additive: true, force: false) { _ in
buttonSnapshotView.removeFromSuperview()
}
}
self.swapButton.alpha = 0.0
let buttonOffset: CGFloat = (rightInsetWithButton - 13.0) / 2.0
var buttonFrame = self.addButton.frame
buttonFrame.origin.x = size.width
self.addButton.frame = buttonFrame
self.addButton.alpha = 1.0
self.firstColorFieldNode.frame = self.secondColorFieldNode.frame
var fieldFrame = self.secondColorFieldNode.frame
fieldFrame.origin.x = fieldFrame.maxX + fieldSpacing
self.secondColorFieldNode.frame = fieldFrame
}
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
self.validLayout = size
let condensedLayout = size.width < 375.0
let separatorHeight = UIScreenPixel
let topPanelHeight: CGFloat = 47.0
transition.updateFrame(node: self.backgroundNode, frame: CGRect(x: 0.0, y: 0.0, width: size.width, height: topPanelHeight))
@ -487,11 +590,20 @@ final class WallpaperColorPanelNode: ASDisplayNode {
transition.updateFrame(node: self.bottomSeparatorNode, frame: CGRect(x: 0.0, y: topPanelHeight, width: size.width, height: separatorHeight))
let fieldHeight: CGFloat = 33.0
let leftInset: CGFloat = 15.0
let rightInset: CGFloat = 15.0
let leftInset: CGFloat
let rightInset: CGFloat
let fieldSpacing: CGFloat
if condensedLayout {
leftInset = 6.0
rightInset = 6.0
fieldSpacing = 40.0
} else {
leftInset = 15.0
rightInset = 15.0
fieldSpacing = 45.0
}
let rightInsetWithButton: CGFloat = 42.0
let fieldSpacing: CGFloat = 45.0
let buttonSize = CGSize(width: 26.0, height: 26.0)
let buttonOffset: CGFloat = (rightInsetWithButton - 13.0) / 2.0
let swapButtonFrame = CGRect(origin: CGPoint(x: self.state.secondColor != nil ? floor((size.width - 26.0) / 2.0) : (self.state.secondColorAvailable ? size.width - rightInsetWithButton + floor((rightInsetWithButton - buttonSize.width) / 2.0) : size.width + buttonOffset), y: floor((topPanelHeight - buttonSize.height) / 2.0)), size: buttonSize)
@ -523,11 +635,11 @@ final class WallpaperColorPanelNode: ASDisplayNode {
let firstFieldFrame = CGRect(x: leftInset, y: (topPanelHeight - fieldHeight) / 2.0, width: self.state.secondColor != nil ? floorToScreenPixels((size.width - fieldSpacing) / 2.0) - leftInset : size.width - leftInset - (self.state.secondColorAvailable ? rightInsetWithButton : rightInset), height: fieldHeight)
transition.updateFrame(node: self.firstColorFieldNode, frame: firstFieldFrame)
self.firstColorFieldNode.updateLayout(size: firstFieldFrame.size, transition: transition)
self.firstColorFieldNode.updateLayout(size: firstFieldFrame.size, condensed: condensedLayout, transition: transition)
let secondFieldFrame = CGRect(x: firstFieldFrame.maxX + fieldSpacing, y: (topPanelHeight - fieldHeight) / 2.0, width: firstFieldFrame.width, height: fieldHeight)
transition.updateFrame(node: self.secondColorFieldNode, frame: secondFieldFrame)
self.secondColorFieldNode.updateLayout(size: secondFieldFrame.size, transition: transition)
self.secondColorFieldNode.updateLayout(size: secondFieldFrame.size, condensed: condensedLayout, transition: transition)
let colorPickerSize = CGSize(width: size.width, height: size.height - topPanelHeight - separatorHeight)
transition.updateFrame(node: self.colorPickerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: topPanelHeight + separatorHeight), size: colorPickerSize))
@ -555,9 +667,9 @@ final class WallpaperColorPanelNode: ASDisplayNode {
let firstColor = current.firstColor ?? current.defaultColor
if let color = firstColor {
updated.firstColor = color
var hsv = color.hsv
updated.secondColor = UIColor(hue: hsv.0, saturation: hsv.1, brightness: hsv.2 < 0.4 ? hsv.2 + 0.4 : hsv.2 - 0.4 , alpha: 1.0)
updated.secondColor = generateGradientColors(color: color).1
//var hsv = color.hsv
//updated.secondColor = UIColor(hue: hsv.0, saturation: hsv.1, brightness: hsv.2 < 0.4 ? hsv.2 + 0.4 : hsv.2 - 0.4 , alpha: 1.0)
}
return updated

View File

@ -342,7 +342,7 @@ public class WallpaperGalleryController: ViewController {
let colorPanelNode = WallpaperColorPanelNode(theme: presentationData.theme, strings: presentationData.strings)
colorPanelNode.colorsChanged = { [weak self] color, _, ended in
if let strongSelf = self {
if let strongSelf = self , let color = color {
strongSelf.updateEntries(color: color, preview: !ended)
}
}

View File

@ -11,6 +11,7 @@ private func makeDarkPresentationTheme(accentColor: UIColor, bubbleColors: (UICo
let badgeTextColor: UIColor
let secondaryBadgeTextColor: UIColor
let outgoingBubbleFillColor: UIColor
var outgoingBubbleFillGradientColor: UIColor
let outgoingBubbleHighlightedFillColor: UIColor
let outgoingScamColor: UIColor
@ -21,44 +22,54 @@ private func makeDarkPresentationTheme(accentColor: UIColor, bubbleColors: (UICo
var accentColor = accentColor
if accentColor.rgb == UIColor.white.rgb {
badgeFillColor = .white
badgeTextColor = .black
secondaryBadgeTextColor = .black
if accentColor.rgb == UIColor.white.rgb && bubbleColors == nil {
badgeFillColor = UIColor(rgb: 0xffffff)
badgeTextColor = UIColor(rgb: 0x000000)
secondaryBadgeTextColor = UIColor(rgb: 0x000000)
outgoingBubbleFillColor = UIColor(rgb: 0x313131)
outgoingBubbleFillGradientColor = outgoingBubbleFillColor
outgoingBubbleHighlightedFillColor = UIColor(rgb: 0x464646)
outgoingScamColor = destructiveColor
outgoingPrimaryTextColor = .white
outgoingPrimaryTextColor = UIColor(rgb: 0xffffff)
outgoingSecondaryTextColor = UIColor(rgb: 0xffffff, alpha: 0.5)
outgoingLinkTextColor = .white
outgoingLinkTextColor = UIColor(rgb: 0xffffff)
outgoingCheckColor = UIColor(rgb: 0xffffff, alpha: 0.5)
} else {
badgeFillColor = destructiveColor
badgeTextColor = .white
outgoingBubbleFillColor = accentColor
badgeTextColor = UIColor(rgb: 0xffffff)
if let bubbleColors = bubbleColors {
outgoingBubbleFillColor = bubbleColors.0
outgoingBubbleFillGradientColor = bubbleColors.1 ?? bubbleColors.0
} else {
outgoingBubbleFillColor = accentColor.withMultiplied(hue: 0.966, saturation: 0.61, brightness: 0.98)
outgoingBubbleFillGradientColor = accentColor
}
outgoingBubbleHighlightedFillColor = accentColor.withMultipliedBrightnessBy(1.421)
let lightness = accentColor.lightness
if lightness > 0.7 {
outgoingScamColor = .black
secondaryBadgeTextColor = .black
outgoingPrimaryTextColor = .black
let outgoingBubbleLightnessColor = outgoingBubbleFillColor.mixedWith(outgoingBubbleFillGradientColor, alpha: 0.5)
if outgoingBubbleLightnessColor.lightness > 0.7 {
outgoingScamColor = UIColor(rgb: 0x000000)
outgoingPrimaryTextColor = UIColor(rgb: 0x000000)
outgoingSecondaryTextColor = UIColor(rgb: 0x000000, alpha: 0.5)
outgoingLinkTextColor = .black
outgoingLinkTextColor = UIColor(rgb: 0x000000)
outgoingCheckColor = UIColor(rgb: 0x000000, alpha: 0.5)
} else {
outgoingScamColor = .white
secondaryBadgeTextColor = .white
outgoingPrimaryTextColor = .white
outgoingScamColor = UIColor(rgb: 0xffffff)
outgoingPrimaryTextColor = UIColor(rgb: 0xffffff)
outgoingSecondaryTextColor = UIColor(rgb: 0xffffff, alpha: 0.5)
outgoingLinkTextColor = .white
outgoingLinkTextColor = UIColor(rgb: 0xffffff)
outgoingCheckColor = UIColor(rgb: 0xffffff, alpha: 0.5)
let hsv = accentColor.hsv
accentColor = UIColor(hue: hsv.0, saturation: hsv.1, brightness: max(hsv.2, 0.55), alpha: 1.0)
}
if accentColor.lightness > 0.7 {
secondaryBadgeTextColor = UIColor(rgb: 0x000000)
} else {
secondaryBadgeTextColor = UIColor(rgb: 0xffffff)
let accentColorHsv = accentColor.hsv
accentColor = UIColor(hue: accentColorHsv.0, saturation: accentColorHsv.1, brightness: max(accentColorHsv.2, 0.55), alpha: 1.0)
}
}
@ -221,7 +232,7 @@ private func makeDarkPresentationTheme(accentColor: UIColor, bubbleColors: (UICo
let message = PresentationThemeChatMessage(
incoming: PresentationThemePartedColors(bubble: PresentationThemeBubbleColor(withWallpaper: PresentationThemeBubbleColorComponents(fill: UIColor(rgb: 0x262628), highlightedFill: UIColor(rgb: 0x353539), stroke: UIColor(rgb: 0x262628)), withoutWallpaper: PresentationThemeBubbleColorComponents(fill: UIColor(rgb: 0x262628), highlightedFill: UIColor(rgb: 0x353539), stroke: UIColor(rgb: 0x262628))), primaryTextColor: .white, secondaryTextColor: UIColor(rgb: 0xffffff, alpha: 0.5), linkTextColor: accentColor, linkHighlightColor: accentColor.withAlphaComponent(0.5), scamColor: destructiveColor, textHighlightColor: UIColor(rgb: 0xf5c038), accentTextColor: accentColor, accentControlColor: accentColor, mediaActiveControlColor: accentColor, mediaInactiveControlColor: accentColor.withAlphaComponent(0.4), mediaControlInnerBackgroundColor: UIColor(rgb: 0x262628), pendingActivityColor: UIColor(rgb: 0xffffff, alpha: 0.5), fileTitleColor: accentColor, fileDescriptionColor: UIColor(rgb: 0xffffff, alpha: 0.5), fileDurationColor: UIColor(rgb: 0xffffff, alpha: 0.5), mediaPlaceholderColor: UIColor(rgb: 0x1f1f1f).mixedWith(.white, alpha: 0.05), polls: PresentationThemeChatBubblePolls(radioButton: UIColor(rgb: 0x737373), radioProgress: accentColor, highlight: accentColor.withAlphaComponent(0.12), separator: UIColor(rgb: 0x000000), bar: accentColor), actionButtonsFillColor: PresentationThemeVariableColor(withWallpaper: UIColor(rgb: 0x000000, alpha: 0.5), withoutWallpaper: UIColor(rgb: 0x000000, alpha: 0.5)), actionButtonsStrokeColor: PresentationThemeVariableColor(color: UIColor(rgb: 0xb2b2b2, alpha: 0.18)), actionButtonsTextColor: PresentationThemeVariableColor(color: UIColor(rgb: 0xffffff)), textSelectionColor: accentColor.withAlphaComponent(0.2), textSelectionKnobColor: accentColor),
outgoing: PresentationThemePartedColors(bubble: PresentationThemeBubbleColor(withWallpaper: PresentationThemeBubbleColorComponents(fill: outgoingBubbleFillColor, highlightedFill: outgoingBubbleHighlightedFillColor, stroke: outgoingBubbleFillColor), withoutWallpaper: PresentationThemeBubbleColorComponents(fill: outgoingBubbleFillColor, highlightedFill: outgoingBubbleHighlightedFillColor, stroke: outgoingBubbleFillColor)), primaryTextColor: outgoingPrimaryTextColor, secondaryTextColor: outgoingSecondaryTextColor, linkTextColor: outgoingLinkTextColor, linkHighlightColor: UIColor.white.withAlphaComponent(0.5), scamColor: outgoingScamColor, textHighlightColor: UIColor(rgb: 0xf5c038), accentTextColor: outgoingPrimaryTextColor, accentControlColor: outgoingPrimaryTextColor, mediaActiveControlColor: outgoingPrimaryTextColor, mediaInactiveControlColor: outgoingSecondaryTextColor, mediaControlInnerBackgroundColor: outgoingBubbleFillColor, pendingActivityColor: outgoingSecondaryTextColor, fileTitleColor: outgoingPrimaryTextColor, fileDescriptionColor: outgoingSecondaryTextColor, fileDurationColor: outgoingSecondaryTextColor, mediaPlaceholderColor: UIColor(rgb: 0x313131).mixedWith(.white, alpha: 0.05), polls: PresentationThemeChatBubblePolls(radioButton: outgoingPrimaryTextColor, radioProgress: outgoingPrimaryTextColor, highlight: outgoingPrimaryTextColor.withAlphaComponent(0.12), separator: outgoingSecondaryTextColor, bar: outgoingPrimaryTextColor), actionButtonsFillColor: PresentationThemeVariableColor(withWallpaper: UIColor(rgb: 0x000000, alpha: 0.5), withoutWallpaper: UIColor(rgb: 0x000000, alpha: 0.5)), actionButtonsStrokeColor: PresentationThemeVariableColor(color: UIColor(rgb: 0xb2b2b2, alpha: 0.18)), actionButtonsTextColor: PresentationThemeVariableColor(color: UIColor(rgb: 0xffffff)), textSelectionColor: UIColor.white.withAlphaComponent(0.2), textSelectionKnobColor: UIColor.white),
outgoing: PresentationThemePartedColors(bubble: PresentationThemeBubbleColor(withWallpaper: PresentationThemeBubbleColorComponents(fill: outgoingBubbleFillColor, gradientFill: outgoingBubbleFillGradientColor, highlightedFill: outgoingBubbleHighlightedFillColor, stroke: outgoingBubbleFillColor), withoutWallpaper: PresentationThemeBubbleColorComponents(fill: outgoingBubbleFillColor, gradientFill: outgoingBubbleFillGradientColor, highlightedFill: outgoingBubbleHighlightedFillColor, stroke: outgoingBubbleFillColor)), primaryTextColor: outgoingPrimaryTextColor, secondaryTextColor: outgoingSecondaryTextColor, linkTextColor: outgoingLinkTextColor, linkHighlightColor: UIColor.white.withAlphaComponent(0.5), scamColor: outgoingScamColor, textHighlightColor: UIColor(rgb: 0xf5c038), accentTextColor: outgoingPrimaryTextColor, accentControlColor: outgoingPrimaryTextColor, mediaActiveControlColor: outgoingPrimaryTextColor, mediaInactiveControlColor: outgoingSecondaryTextColor, mediaControlInnerBackgroundColor: outgoingBubbleFillColor, pendingActivityColor: outgoingSecondaryTextColor, fileTitleColor: outgoingPrimaryTextColor, fileDescriptionColor: outgoingSecondaryTextColor, fileDurationColor: outgoingSecondaryTextColor, mediaPlaceholderColor: UIColor(rgb: 0x313131).mixedWith(.white, alpha: 0.05), polls: PresentationThemeChatBubblePolls(radioButton: outgoingPrimaryTextColor, radioProgress: outgoingPrimaryTextColor, highlight: outgoingPrimaryTextColor.withAlphaComponent(0.12), separator: outgoingSecondaryTextColor, bar: outgoingPrimaryTextColor), actionButtonsFillColor: PresentationThemeVariableColor(withWallpaper: UIColor(rgb: 0x000000, alpha: 0.5), withoutWallpaper: UIColor(rgb: 0x000000, alpha: 0.5)), actionButtonsStrokeColor: PresentationThemeVariableColor(color: UIColor(rgb: 0xb2b2b2, alpha: 0.18)), actionButtonsTextColor: PresentationThemeVariableColor(color: UIColor(rgb: 0xffffff)), textSelectionColor: UIColor.white.withAlphaComponent(0.2), textSelectionKnobColor: UIColor.white),
freeform: PresentationThemeBubbleColor(withWallpaper: PresentationThemeBubbleColorComponents(fill: UIColor(rgb: 0x1f1f1f), highlightedFill: UIColor(rgb: 0x2a2a2a), stroke: UIColor(rgb: 0x1f1f1f)), withoutWallpaper: PresentationThemeBubbleColorComponents(fill: UIColor(rgb: 0x1f1f1f), highlightedFill: UIColor(rgb: 0x2a2a2a), stroke: UIColor(rgb: 0x1f1f1f))),
infoPrimaryTextColor: .white,
infoLinkTextColor: accentColor,

View File

@ -31,14 +31,38 @@ private func makeDarkPresentationTheme(accentColor: UIColor, bubbleColors: (UICo
let mainFreeTextColor = accentColor.withMultiplied(hue: 1.019, saturation: 0.097, brightness: 0.56)
var outgoingBubbleFillColor = accentColor.withMultiplied(hue: 1.019, saturation: 0.731, brightness: 0.59)
var outgoingBubbleFillGradientColor = outgoingBubbleFillColor
let outgoingBubbleFillColor: UIColor
let outgoingBubbleFillGradientColor: UIColor
let outgoingBubbleHighlightedFillColor: UIColor
let outgoingScamColor: UIColor
let outgoingPrimaryTextColor: UIColor
let outgoingSecondaryTextColor: UIColor
let outgoingLinkTextColor: UIColor
let outgoingCheckColor: UIColor
if let bubbleColors = bubbleColors {
outgoingBubbleFillColor = bubbleColors.0
outgoingBubbleFillGradientColor = bubbleColors.1 ?? bubbleColors.0
} else {
outgoingBubbleFillGradientColor = accentColor.withMultiplied(hue: 1.019, saturation: 0.731, brightness: 0.59)
outgoingBubbleFillColor = outgoingBubbleFillGradientColor.withMultiplied(hue: 0.966, saturation: 0.61, brightness: 0.98)
}
let outgoingBubbleLightnessColor = outgoingBubbleFillColor.mixedWith(outgoingBubbleFillGradientColor, alpha: 0.5)
if outgoingBubbleLightnessColor.lightness > 0.7 {
outgoingScamColor = UIColor(rgb: 0x000000)
outgoingPrimaryTextColor = UIColor(rgb: 0x000000)
outgoingSecondaryTextColor = UIColor(rgb: 0x000000, alpha: 0.5)
outgoingLinkTextColor = UIColor(rgb: 0x000000)
outgoingCheckColor = UIColor(rgb: 0x000000, alpha: 0.5)
} else {
outgoingScamColor = UIColor(rgb: 0xffffff)
outgoingPrimaryTextColor = UIColor(rgb: 0xffffff)
outgoingSecondaryTextColor = UIColor(rgb: 0xffffff, alpha: 0.5)
outgoingLinkTextColor = UIColor(rgb: 0xffffff)
outgoingCheckColor = UIColor(rgb: 0xffffff, alpha: 0.5)
}
let highlightedIncomingBubbleColor = accentColor.withMultiplied(hue: 1.03, saturation: 0.463, brightness: 0.29)
let highlightedOutgoingBubbleColor = accentColor.withMultiplied(hue: 1.019, saturation: 0.609, brightness: 0.63)
@ -206,13 +230,13 @@ private func makeDarkPresentationTheme(accentColor: UIColor, bubbleColors: (UICo
let message = PresentationThemeChatMessage(
incoming: PresentationThemePartedColors(bubble: PresentationThemeBubbleColor(withWallpaper: PresentationThemeBubbleColorComponents(fill: mainBackgroundColor, highlightedFill: highlightedIncomingBubbleColor, stroke: mainBackgroundColor), withoutWallpaper: PresentationThemeBubbleColorComponents(fill: mainBackgroundColor, highlightedFill: highlightedIncomingBubbleColor, stroke: mainBackgroundColor)), primaryTextColor: .white, secondaryTextColor: mainSecondaryTextColor.withAlphaComponent(0.5), linkTextColor: accentColor, linkHighlightColor: accentColor.withAlphaComponent(0.5), scamColor: destructiveColor, textHighlightColor: UIColor(rgb: 0xf5c038), accentTextColor: accentColor, accentControlColor: accentColor, mediaActiveControlColor: accentColor, mediaInactiveControlColor: accentColor.withAlphaComponent(0.5), mediaControlInnerBackgroundColor: mainBackgroundColor, pendingActivityColor: mainSecondaryTextColor.withAlphaComponent(0.5), fileTitleColor: accentColor, fileDescriptionColor: mainSecondaryTextColor.withAlphaComponent(0.5), fileDurationColor: mainSecondaryTextColor.withAlphaComponent(0.5), mediaPlaceholderColor: accentColor.withMultiplied(hue: 1.019, saturation: 0.585, brightness: 0.23), polls: PresentationThemeChatBubblePolls(radioButton: accentColor.withMultiplied(hue: 0.995, saturation: 0.317, brightness: 0.51), radioProgress: accentColor, highlight: accentColor.withAlphaComponent(0.12), separator: mainSeparatorColor, bar: accentColor), actionButtonsFillColor: PresentationThemeVariableColor(withWallpaper: additionalBackgroundColor.withAlphaComponent(0.5), withoutWallpaper: additionalBackgroundColor.withAlphaComponent(0.5)), actionButtonsStrokeColor: PresentationThemeVariableColor(color: buttonStrokeColor), actionButtonsTextColor: PresentationThemeVariableColor(color: .white), textSelectionColor: accentColor.withAlphaComponent(0.2), textSelectionKnobColor: accentColor),
outgoing: PresentationThemePartedColors(bubble: PresentationThemeBubbleColor(withWallpaper: PresentationThemeBubbleColorComponents(fill: outgoingBubbleFillColor, gradientFill: outgoingBubbleFillGradientColor, highlightedFill: highlightedOutgoingBubbleColor, stroke: outgoingBubbleFillColor), withoutWallpaper: PresentationThemeBubbleColorComponents(fill: outgoingBubbleFillColor, gradientFill: outgoingBubbleFillGradientColor, highlightedFill: highlightedOutgoingBubbleColor, stroke: outgoingBubbleFillColor)), primaryTextColor: .white, secondaryTextColor: mainSecondaryTextColor.withAlphaComponent(0.5), linkTextColor: accentColor, linkHighlightColor: accentColor.withAlphaComponent(0.5), scamColor: destructiveColor, textHighlightColor: UIColor(rgb: 0xf5c038), accentTextColor: .white, accentControlColor: .white, mediaActiveControlColor: .white, mediaInactiveControlColor: UIColor(rgb: 0xffffff, alpha: 0.5), mediaControlInnerBackgroundColor: outgoingBubbleFillColor, pendingActivityColor: mainSecondaryTextColor.withAlphaComponent(0.5), fileTitleColor: .white, fileDescriptionColor: mainSecondaryTextColor.withAlphaComponent(0.5), fileDurationColor: mainSecondaryTextColor.withAlphaComponent(0.5), mediaPlaceholderColor: accentColor.withMultiplied(hue: 1.019, saturation: 0.804, brightness: 0.51), polls: PresentationThemeChatBubblePolls(radioButton: .white, radioProgress: accentColor.withMultiplied(hue: 0.99, saturation: 0.56, brightness: 1.0), highlight: accentColor.withMultiplied(hue: 0.99, saturation: 0.56, brightness: 1.0).withAlphaComponent(0.12), separator: mainSeparatorColor, bar: .white), actionButtonsFillColor: PresentationThemeVariableColor(withWallpaper: additionalBackgroundColor.withAlphaComponent(0.5), withoutWallpaper: additionalBackgroundColor.withAlphaComponent(0.5)), actionButtonsStrokeColor: PresentationThemeVariableColor(color: buttonStrokeColor), actionButtonsTextColor: PresentationThemeVariableColor(color: .white), textSelectionColor: UIColor.white.withAlphaComponent(0.2), textSelectionKnobColor: UIColor.white),
outgoing: PresentationThemePartedColors(bubble: PresentationThemeBubbleColor(withWallpaper: PresentationThemeBubbleColorComponents(fill: outgoingBubbleFillColor, gradientFill: outgoingBubbleFillGradientColor, highlightedFill: highlightedOutgoingBubbleColor, stroke: outgoingBubbleFillColor), withoutWallpaper: PresentationThemeBubbleColorComponents(fill: outgoingBubbleFillColor, gradientFill: outgoingBubbleFillGradientColor, highlightedFill: highlightedOutgoingBubbleColor, stroke: outgoingBubbleFillColor)), primaryTextColor: outgoingPrimaryTextColor, secondaryTextColor: outgoingSecondaryTextColor, linkTextColor: outgoingLinkTextColor, linkHighlightColor: UIColor.white.withAlphaComponent(0.5), scamColor: outgoingScamColor, textHighlightColor: UIColor(rgb: 0xf5c038), accentTextColor: outgoingPrimaryTextColor, accentControlColor: outgoingPrimaryTextColor, mediaActiveControlColor: outgoingPrimaryTextColor, mediaInactiveControlColor: outgoingSecondaryTextColor, mediaControlInnerBackgroundColor: outgoingBubbleFillColor, pendingActivityColor: outgoingSecondaryTextColor, fileTitleColor: outgoingPrimaryTextColor, fileDescriptionColor: outgoingSecondaryTextColor, fileDurationColor: outgoingSecondaryTextColor, mediaPlaceholderColor: accentColor.withMultiplied(hue: 1.019, saturation: 0.804, brightness: 0.51), polls: PresentationThemeChatBubblePolls(radioButton: outgoingPrimaryTextColor, radioProgress: accentColor.withMultiplied(hue: 0.99, saturation: 0.56, brightness: 1.0), highlight: accentColor.withMultiplied(hue: 0.99, saturation: 0.56, brightness: 1.0).withAlphaComponent(0.12), separator: mainSeparatorColor, bar: outgoingPrimaryTextColor), actionButtonsFillColor: PresentationThemeVariableColor(withWallpaper: additionalBackgroundColor.withAlphaComponent(0.5), withoutWallpaper: additionalBackgroundColor.withAlphaComponent(0.5)), actionButtonsStrokeColor: PresentationThemeVariableColor(color: buttonStrokeColor), actionButtonsTextColor: PresentationThemeVariableColor(color: .white), textSelectionColor: UIColor.white.withAlphaComponent(0.2), textSelectionKnobColor: UIColor.white),
freeform: PresentationThemeBubbleColor(withWallpaper: PresentationThemeBubbleColorComponents(fill: mainBackgroundColor, highlightedFill: highlightedIncomingBubbleColor, stroke: mainBackgroundColor), withoutWallpaper: PresentationThemeBubbleColorComponents(fill: mainBackgroundColor, highlightedFill: highlightedIncomingBubbleColor, stroke: mainBackgroundColor)),
infoPrimaryTextColor: UIColor(rgb: 0xffffff),
infoLinkTextColor: accentColor,
outgoingCheckColor: accentColor.withMultiplied(hue: 0.99, saturation: 0.743, brightness: 1.0),
outgoingCheckColor: outgoingCheckColor,
mediaDateAndStatusFillColor: UIColor(white: 0.0, alpha: 0.5),
mediaDateAndStatusTextColor: .white,
mediaDateAndStatusTextColor: UIColor(rgb: 0xffffff),
shareButtonFillColor: PresentationThemeVariableColor(color: additionalBackgroundColor.withAlphaComponent(0.5)),
shareButtonStrokeColor: PresentationThemeVariableColor(color: buttonStrokeColor),
shareButtonForegroundColor: PresentationThemeVariableColor(color: UIColor(rgb: 0xb2b2b2)),

View File

@ -1610,25 +1610,16 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
}
}, scheduleCurrentMessage: { [weak self] in
if let strongSelf = self, let peer = strongSelf.presentationInterfaceState.renderedPeer?.peer {
let mode: ChatScheduleTimeControllerMode
if peer.id == strongSelf.context.account.peerId {
mode = .reminders
} else {
mode = .scheduledMessages(sendWhenOnlineAvailable: peer.id.namespace == Namespaces.Peer.CloudUser)
}
let controller = ChatScheduleTimeController(context: strongSelf.context, mode: mode, minimalTime: strongSelf.presentationInterfaceState.slowmodeState?.timeout, completion: { [weak self] scheduleTime in
if let strongSelf = self {
strongSelf.presentScheduleTimePicker(completion: { [weak self] time in
if let strongSelf = self {
strongSelf.chatDisplayNode.sendCurrentMessage(scheduleTime: scheduleTime, completion: { [weak self] in
strongSelf.chatDisplayNode.sendCurrentMessage(scheduleTime: time, completion: { [weak self] in
if let strongSelf = self, !strongSelf.presentationInterfaceState.isScheduledMessages {
strongSelf.openScheduledMessages()
}
})
}
})
strongSelf.chatDisplayNode.dismissInput()
strongSelf.present(controller, in: .window(.root))
}
}, sendScheduledMessagesNow: { [weak self] messageIds in
if let strongSelf = self {
@ -1642,21 +1633,14 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
}
}, editScheduledMessagesTime: { [weak self] messageIds in
if let strongSelf = self, let messageId = messageIds.first, let peer = strongSelf.presentationInterfaceState.renderedPeer?.peer {
let mode: ChatScheduleTimeControllerMode
if peer.id == strongSelf.context.account.peerId {
mode = .reminders
} else {
mode = .scheduledMessages(sendWhenOnlineAvailable: peer.id.namespace == Namespaces.Peer.CloudUser)
}
if let strongSelf = self, let messageId = messageIds.first {
let _ = (strongSelf.context.account.postbox.transaction { transaction -> Message? in
return transaction.getMessage(messageId)
} |> deliverOnMainQueue).start(next: { [weak self] message in
guard let strongSelf = self, let message = message else {
return
}
let controller = ChatScheduleTimeController(context: strongSelf.context, mode: mode, currentTime: message.timestamp, minimalTime: strongSelf.presentationInterfaceState.slowmodeState?.timeout, completion: { [weak self] scheduleTime in
strongSelf.presentScheduleTimePicker(selectedTime: message.timestamp, completion: { [weak self] time in
if let strongSelf = self {
var entities: TextEntitiesMessageAttribute?
for attribute in message.attributes {
@ -1665,14 +1649,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
break
}
}
let signal = requestEditMessage(account: strongSelf.context.account, messageId: messageId, text: message.text, media: .keep, entities: entities, disableUrlPreview: false, scheduleTime: scheduleTime)
let signal = requestEditMessage(account: strongSelf.context.account, messageId: messageId, text: message.text, media: .keep, entities: entities, disableUrlPreview: false, scheduleTime: time)
strongSelf.editMessageDisposable.set((signal |> deliverOnMainQueue).start(next: { result in
}, error: { error in
}))
}
})
strongSelf.chatDisplayNode.dismissInput()
strongSelf.present(controller, in: .window(.root))
})
}
}, performTextSelectionAction: { [weak self] _, text, action in
@ -5511,24 +5493,16 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
}
}, presentSchedulePicker: { [weak self] done in
guard let strongSelf = self else {
return
}
let mode: ChatScheduleTimeControllerMode
if peer.id == strongSelf.context.account.peerId {
mode = .reminders
} else {
mode = .scheduledMessages(sendWhenOnlineAvailable: peer.id.namespace == Namespaces.Peer.CloudUser)
}
let controller = ChatScheduleTimeController(context: strongSelf.context, mode: mode, minimalTime: strongSelf.presentationInterfaceState.slowmodeState?.timeout, completion: { [weak self] time in
if let strongSelf = self {
done(time)
if !strongSelf.presentationInterfaceState.isScheduledMessages {
strongSelf.openScheduledMessages()
if let strongSelf = self {
strongSelf.presentScheduleTimePicker(completion: { [weak self] time in
if let strongSelf = self {
done(time)
if !strongSelf.presentationInterfaceState.isScheduledMessages {
strongSelf.openScheduledMessages()
}
}
}
})
strongSelf.present(controller, in: .window(.root))
})
}
})
}
}, openFileGallery: {
@ -5558,24 +5532,16 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: nil, text: strongSelf.presentationData.strings.Chat_AttachmentMultipleFilesDisabled, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
}, presentSchedulePicker: { [weak self] done in
guard let strongSelf = self, let peer = strongSelf.presentationInterfaceState.renderedPeer?.peer else {
return
if let strongSelf = self {
strongSelf.presentScheduleTimePicker(completion: { [weak self] time in
if let strongSelf = self {
done(time)
if !strongSelf.presentationInterfaceState.isScheduledMessages {
strongSelf.openScheduledMessages()
}
}
})
}
let mode: ChatScheduleTimeControllerMode
if peer.id == strongSelf.context.account.peerId {
mode = .reminders
} else {
mode = .scheduledMessages(sendWhenOnlineAvailable: peer.id.namespace == Namespaces.Peer.CloudUser)
}
let controller = ChatScheduleTimeController(context: strongSelf.context, mode: mode, minimalTime: strongSelf.presentationInterfaceState.slowmodeState?.timeout, completion: { [weak self] time in
if let strongSelf = self {
done(time)
if !strongSelf.presentationInterfaceState.isScheduledMessages {
strongSelf.openScheduledMessages()
}
}
})
strongSelf.present(controller, in: .window(.root))
}, sendMessagesWithSignals: { [weak self] signals, silentPosting, scheduleTime in
if !inputText.string.isEmpty {
//strongSelf.clearInputText()
@ -5758,24 +5724,16 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
}, presentSchedulePicker: { [weak self] done in
guard let strongSelf = self, let peer = strongSelf.presentationInterfaceState.renderedPeer?.peer else {
return
if let strongSelf = self {
strongSelf.presentScheduleTimePicker(completion: { [weak self] time in
if let strongSelf = self {
done(time)
if !strongSelf.presentationInterfaceState.isScheduledMessages {
strongSelf.openScheduledMessages()
}
}
})
}
let mode: ChatScheduleTimeControllerMode
if peer.id == strongSelf.context.account.peerId {
mode = .reminders
} else {
mode = .scheduledMessages(sendWhenOnlineAvailable: peer.id.namespace == Namespaces.Peer.CloudUser)
}
let controller = ChatScheduleTimeController(context: strongSelf.context, mode: mode, minimalTime: strongSelf.presentationInterfaceState.slowmodeState?.timeout, completion: { [weak self] time in
if let strongSelf = self {
done(time)
if !strongSelf.presentationInterfaceState.isScheduledMessages {
strongSelf.openScheduledMessages()
}
}
})
strongSelf.present(controller, in: .window(.root))
})
controller.descriptionGenerator = legacyAssetPickerItemGenerator()
controller.completionBlock = { [weak legacyController] signals, silentPosting, scheduleTime in
@ -6048,19 +6006,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
donateSendMessageIntent(account: self.context.account, sharedContext: self.context.sharedContext, peerIds: [peerId])
} else {
let mode: ChatScheduleTimeControllerMode
if peerId == self.context.account.peerId {
mode = .reminders
} else {
mode = .scheduledMessages(sendWhenOnlineAvailable: peerId.namespace == Namespaces.Peer.CloudUser)
}
let controller = ChatScheduleTimeController(context: self.context, mode: mode, minimalTime: self.presentationInterfaceState.slowmodeState?.timeout, dismissByTapOutside: false, completion: { [weak self] time in
self.presentScheduleTimePicker(dismissByTapOutside: false, completion: { [weak self] time in
if let strongSelf = self {
strongSelf.sendMessages(strongSelf.transformEnqueueMessages(messages, silentPosting: false, scheduleTime: time), commit: true)
}
})
self.chatDisplayNode.dismissInput()
self.present(controller, in: .window(.root))
}
}
@ -8182,6 +8132,35 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
self.effectiveNavigationController?.pushViewController(controller)
}
private func presentScheduleTimePicker(selectedTime: Int32? = nil, dismissByTapOutside: Bool = true, completion: @escaping (Int32) -> Void) {
guard case let .peer(peerId) = self.chatLocation else {
return
}
let _ = (self.context.account.viewTracker.peerView(peerId)
|> take(1)
|> deliverOnMainQueue).start(next: { [weak self] peerView in
guard let strongSelf = self, let peer = peerViewMainPeer(peerView) else {
return
}
var sendWhenOnlineAvailable = false
if let presence = peerView.peerPresences[peer.id] as? TelegramUserPresence, case .present = presence.status {
sendWhenOnlineAvailable = true
}
let mode: ChatScheduleTimeControllerMode
if peerId == strongSelf.context.account.peerId {
mode = .reminders
} else {
mode = .scheduledMessages(sendWhenOnlineAvailable: sendWhenOnlineAvailable)
}
let controller = ChatScheduleTimeController(context: strongSelf.context, peerId: peerId, mode: mode, currentTime: selectedTime, minimalTime: strongSelf.presentationInterfaceState.slowmodeState?.timeout, dismissByTapOutside: dismissByTapOutside, completion: { time in
completion(time)
})
strongSelf.chatDisplayNode.dismissInput()
strongSelf.present(controller, in: .window(.root))
})
}
private var effectiveNavigationController: NavigationController? {
if let navigationController = self.navigationController as? NavigationController {
return navigationController

View File

@ -759,6 +759,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
}
transition.updateFrame(node: self.backgroundNode, frame: contentBounds)
self.backgroundNode.updateLayout(size: contentBounds.size, transition: transition)
transition.updateFrame(node: self.historyNodeContainer, frame: contentBounds)
transition.updateBounds(node: self.historyNode, bounds: CGRect(origin: CGPoint(), size: contentBounds.size))
transition.updatePosition(node: self.historyNode, position: CGPoint(x: contentBounds.size.width / 2.0, y: contentBounds.size.height / 2.0))

View File

@ -197,8 +197,7 @@ final class ChatMessageDateHeaderNode: ListViewItemHeaderNode {
let (size, apply) = labelLayout(TextNodeLayoutArguments(attributedString: attributedString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 320.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
let _ = apply()
self.labelNode.frame = CGRect(origin: CGPoint(), size: size.size)
self.setNeedsLayout()
}

View File

@ -21,7 +21,9 @@ final class ChatScheduleTimeController: ViewController {
private var animatedIn = false
private let context: AccountContext
private let peerId: PeerId
private let mode: ChatScheduleTimeControllerMode
private let editingTime: Bool
private let currentTime: Int32?
private let minimalTime: Int32?
private let dismissByTapOutside: Bool
@ -29,10 +31,12 @@ final class ChatScheduleTimeController: ViewController {
private var presentationDataDisposable: Disposable?
init(context: AccountContext, mode: ChatScheduleTimeControllerMode, currentTime: Int32? = nil, minimalTime: Int32? = nil, dismissByTapOutside: Bool = true, completion: @escaping (Int32) -> Void) {
init(context: AccountContext, peerId: PeerId, mode: ChatScheduleTimeControllerMode, currentTime: Int32? = nil, minimalTime: Int32? = nil, dismissByTapOutside: Bool = true, completion: @escaping (Int32) -> Void) {
self.context = context
self.peerId = peerId
self.mode = mode
self.currentTime = currentTime
self.editingTime = currentTime != nil
self.currentTime = currentTime != scheduleWhenOnlineTimestamp ? currentTime : nil
self.minimalTime = minimalTime
self.dismissByTapOutside = dismissByTapOutside
self.completion = completion
@ -64,8 +68,27 @@ final class ChatScheduleTimeController: ViewController {
override public func loadDisplayNode() {
self.displayNode = ChatScheduleTimeControllerNode(context: self.context, mode: self.mode, currentTime: self.currentTime, minimalTime: self.minimalTime, dismissByTapOutside: self.dismissByTapOutside)
self.controllerNode.completion = { [weak self] time in
self?.completion(time != scheduleWhenOnlineTimestamp ? time + 5 : time)
self?.dismiss()
guard let strongSelf = self else {
return
}
if time == scheduleWhenOnlineTimestamp {
let _ = (strongSelf.context.account.viewTracker.peerView(strongSelf.peerId)
|> take(1)
|> deliverOnMainQueue).start(next: { [weak self] peerView in
guard let strongSelf = self, let peer = peerViewMainPeer(peerView) else {
return
}
let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970)
if !strongSelf.editingTime, let presence = peerView.peerPresences[peer.id] as? TelegramUserPresence, case let .present(statusTimestamp) = presence.status, statusTimestamp >= timestamp {
strongSelf.completion(0)
} else {
strongSelf.completion(time)
}
})
} else {
strongSelf.completion(time + 5)
}
strongSelf.dismiss()
}
self.controllerNode.dismiss = { [weak self] in
self?.presentingViewController?.dismiss(animated: false, completion: nil)

View File

@ -106,7 +106,8 @@ private final class DeviceContactDataModernContext: DeviceContactDataContext {
CNContactUrlAddressesKey as CNKeyDescriptor,
CNContactOrganizationNameKey as CNKeyDescriptor,
CNContactJobTitleKey as CNKeyDescriptor,
CNContactDepartmentNameKey as CNKeyDescriptor
CNContactDepartmentNameKey as CNKeyDescriptor,
CNContactNoteKey as CNKeyDescriptor
]
guard let contact = try? self.store.unifiedContact(withIdentifier: stableId, keysToFetch: keysToFetch) else {
@ -128,7 +129,8 @@ private final class DeviceContactDataModernContext: DeviceContactDataContext {
CNContactUrlAddressesKey as CNKeyDescriptor,
CNContactOrganizationNameKey as CNKeyDescriptor,
CNContactJobTitleKey as CNKeyDescriptor,
CNContactDepartmentNameKey as CNKeyDescriptor
CNContactDepartmentNameKey as CNKeyDescriptor,
CNContactNoteKey as CNKeyDescriptor
]
guard let current = try? self.store.unifiedContact(withIdentifier: stableId, keysToFetch: keysToFetch) else {
@ -254,7 +256,8 @@ private final class DeviceContactDataModernContext: DeviceContactDataContext {
CNContactUrlAddressesKey as CNKeyDescriptor,
CNContactOrganizationNameKey as CNKeyDescriptor,
CNContactJobTitleKey as CNKeyDescriptor,
CNContactDepartmentNameKey as CNKeyDescriptor
CNContactDepartmentNameKey as CNKeyDescriptor,
CNContactNoteKey as CNKeyDescriptor
]
guard let current = try? self.store.unifiedContact(withIdentifier: stableId, keysToFetch: keysToFetch) else {