diff --git a/submodules/SettingsUI/Sources/Themes/EditThemeController.swift b/submodules/SettingsUI/Sources/Themes/EditThemeController.swift index 85579eb30d..2562df5eca 100644 --- a/submodules/SettingsUI/Sources/Themes/EditThemeController.swift +++ b/submodules/SettingsUI/Sources/Themes/EditThemeController.swift @@ -14,6 +14,7 @@ import PresentationDataUtils import LegacyMediaPickerUI import WallpaperResources import AccountContext +import MediaResources private final class EditThemeControllerArguments { let context: AccountContext @@ -503,11 +504,40 @@ public func editThemeController(context: AccountContext, mode: EditThemeControll resolvedWallpaper = nil } + + let prepare: Signal + if let resolvedWallpaper = resolvedWallpaper, case let .file(file) = resolvedWallpaper, resolvedWallpaper.isPattern { + let resource = file.file.resource + let representation = CachedPatternWallpaperRepresentation(color: file.settings.color ?? 0xd6e2ee, bottomColor: file.settings.bottomColor, intensity: file.settings.intensity ?? 50, rotation: file.settings.rotation) + + var data: Data? + if let path = context.account.postbox.mediaBox.completedResourcePath(resource), let maybeData = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedRead) { + data = maybeData + } else if let path = context.sharedContext.accountManager.mediaBox.completedResourcePath(resource), let maybeData = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedRead) { + data = maybeData + } + + if let data = data { + context.sharedContext.accountManager.mediaBox.storeResourceData(resource.id, data: data, synchronous: true) + prepare = (context.sharedContext.accountManager.mediaBox.cachedResourceRepresentation(resource, representation: representation, complete: true, fetch: true) + |> filter({ $0.complete }) + |> take(1) + |> castError(CreateThemeError.self) + |> mapToSignal { _ -> Signal in + return .complete() + }) + } else { + prepare = .complete() + } + } else { + prepare = .complete() + } + switch mode { case .create: if let themeResource = themeResource { - let _ = (createTheme(account: context.account, title: state.title, resource: themeResource, thumbnailData: themeThumbnailData, settings: settings) - |> deliverOnMainQueue).start(next: { next in + let _ = (prepare |> then(createTheme(account: context.account, title: state.title, resource: themeResource, thumbnailData: themeThumbnailData, settings: settings) + |> deliverOnMainQueue)).start(next: { next in if case let .result(resultTheme) = next { let _ = applyTheme(accountManager: context.sharedContext.accountManager, account: context.account, theme: resultTheme).start() let _ = (updatePresentationThemeSettingsInteractively(accountManager: context.sharedContext.accountManager, { current in @@ -540,8 +570,8 @@ public func editThemeController(context: AccountContext, mode: EditThemeControll }) } case let .edit(info): - let _ = (updateTheme(account: context.account, accountManager: context.sharedContext.accountManager, theme: info.theme, title: state.title, slug: state.slug, resource: themeResource, settings: settings) - |> deliverOnMainQueue).start(next: { next in + let _ = (prepare |> then(updateTheme(account: context.account, accountManager: context.sharedContext.accountManager, theme: info.theme, title: state.title, slug: state.slug, resource: themeResource, settings: settings) + |> deliverOnMainQueue)).start(next: { next in if case let .result(resultTheme) = next { let _ = applyTheme(accountManager: context.sharedContext.accountManager, account: context.account, theme: resultTheme).start() let _ = (updatePresentationThemeSettingsInteractively(accountManager: context.sharedContext.accountManager, { current in diff --git a/submodules/SettingsUI/Sources/Themes/ThemePreviewController.swift b/submodules/SettingsUI/Sources/Themes/ThemePreviewController.swift index 456dbdd291..fe2d7d90e6 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemePreviewController.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemePreviewController.swift @@ -41,6 +41,8 @@ public final class ThemePreviewController: ViewController { return self._ready } + private var validLayout: ContainerViewLayout? + private var didPlayPresentationAnimation = false private var presentationData: PresentationData @@ -399,11 +401,11 @@ public final class ThemePreviewController: ViewController { } } |> deliverOnMainQueue).start(next: { [weak self] previousDefaultTheme in - if let strongSelf = self { + if let strongSelf = self, let layout = strongSelf.validLayout, layout.size.width >= 375.0 { Queue.mainQueue().after(0.3) { let navigationController = strongSelf.navigationController as? NavigationController if let (previousDefaultTheme, autoNightMode) = previousDefaultTheme { - strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .actionSucceeded(title: strongSelf.presentationData.strings.Theme_ThemeChanged, text: strongSelf.presentationData.strings.Theme_ThemeChangedText, cancel: strongSelf.presentationData.strings.Undo_Undo), elevatedLayout: false, animateInAsReplacement: false, action: { value in + strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .actionSucceeded(title: strongSelf.presentationData.strings.Theme_ThemeChanged, text: strongSelf.presentationData.strings.Theme_ThemeChangedText, cancel: strongSelf.presentationData.strings.Undo_Undo), elevatedLayout: true, animateInAsReplacement: false, action: { value in if value == .undo { let _ = updatePresentationThemeSettingsInteractively(accountManager: context.sharedContext.accountManager, { current -> PresentationThemeSettings in var updated: PresentationThemeSettings @@ -435,6 +437,8 @@ public final class ThemePreviewController: ViewController { override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { super.containerLayoutUpdated(layout, transition: transition) + self.validLayout = layout + self.controllerNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationHeight, transition: transition) } diff --git a/submodules/SettingsUI/Sources/Themes/ThemeSettingsThemeItem.swift b/submodules/SettingsUI/Sources/Themes/ThemeSettingsThemeItem.swift index 7ebda9a51d..cde23ef767 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemeSettingsThemeItem.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemeSettingsThemeItem.swift @@ -26,7 +26,7 @@ private struct ThemeSettingsThemeEntry: Comparable, Identifiable { let wallpaper: TelegramWallpaper? var stableId: Int64 { - return self.themeReference.index + return self.themeReference.generalThemeReference.index } static func ==(lhs: ThemeSettingsThemeEntry, rhs: ThemeSettingsThemeEntry) -> Bool { diff --git a/submodules/SettingsUI/Sources/Themes/WallpaperGalleryToolbarNode.swift b/submodules/SettingsUI/Sources/Themes/WallpaperGalleryToolbarNode.swift index 2e66ab7dba..d00958df6a 100644 --- a/submodules/SettingsUI/Sources/Themes/WallpaperGalleryToolbarNode.swift +++ b/submodules/SettingsUI/Sources/Themes/WallpaperGalleryToolbarNode.swift @@ -31,8 +31,10 @@ final class WallpaperGalleryToolbarNode: ASDisplayNode { } } - private let cancelButton = HighlightableButtonNode() - private let doneButton = HighlightableButtonNode() + private let cancelButton = HighlightTrackingButtonNode() + private let cancelHighlightBackgroundNode = ASDisplayNode() + private let doneButton = HighlightTrackingButtonNode() + private let doneHighlightBackgroundNode = ASDisplayNode() private let separatorNode = ASDisplayNode() private let topSeparatorNode = ASDisplayNode() @@ -47,7 +49,9 @@ final class WallpaperGalleryToolbarNode: ASDisplayNode { super.init() + self.addSubnode(self.cancelHighlightBackgroundNode) self.addSubnode(self.cancelButton) + self.addSubnode(self.doneHighlightBackgroundNode) self.addSubnode(self.doneButton) self.addSubnode(self.separatorNode) self.addSubnode(self.topSeparatorNode) @@ -57,11 +61,11 @@ final class WallpaperGalleryToolbarNode: ASDisplayNode { self.cancelButton.highligthedChanged = { [weak self] highlighted in if let strongSelf = self { if highlighted { - strongSelf.cancelButton.backgroundColor = strongSelf.theme.list.itemHighlightedBackgroundColor + strongSelf.cancelHighlightBackgroundNode.layer.removeAnimation(forKey: "opacity") + strongSelf.cancelHighlightBackgroundNode.alpha = 1.0 } else { - UIView.animate(withDuration: 0.3, animations: { - strongSelf.cancelButton.backgroundColor = .clear - }) + strongSelf.cancelHighlightBackgroundNode.alpha = 0.0 + strongSelf.cancelHighlightBackgroundNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3) } } } @@ -69,11 +73,11 @@ final class WallpaperGalleryToolbarNode: ASDisplayNode { self.doneButton.highligthedChanged = { [weak self] highlighted in if let strongSelf = self { if highlighted { - strongSelf.doneButton.backgroundColor = strongSelf.theme.list.itemHighlightedBackgroundColor + strongSelf.doneHighlightBackgroundNode.layer.removeAnimation(forKey: "opacity") + strongSelf.doneHighlightBackgroundNode.alpha = 1.0 } else { - UIView.animate(withDuration: 0.3, animations: { - strongSelf.doneButton.backgroundColor = .clear - }) + strongSelf.doneHighlightBackgroundNode.alpha = 0.0 + strongSelf.doneHighlightBackgroundNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3) } } } @@ -92,6 +96,8 @@ final class WallpaperGalleryToolbarNode: ASDisplayNode { self.backgroundColor = theme.rootController.tabBar.backgroundColor self.separatorNode.backgroundColor = theme.rootController.tabBar.separatorColor self.topSeparatorNode.backgroundColor = theme.rootController.tabBar.separatorColor + self.cancelHighlightBackgroundNode.backgroundColor = theme.list.itemHighlightedBackgroundColor + self.doneHighlightBackgroundNode.backgroundColor = theme.list.itemHighlightedBackgroundColor let cancelTitle: String switch self.cancelButtonType { @@ -118,7 +124,9 @@ final class WallpaperGalleryToolbarNode: ASDisplayNode { func updateLayout(size: CGSize, layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { self.cancelButton.frame = CGRect(origin: CGPoint(), size: CGSize(width: floor(size.width / 2.0), height: size.height)) + self.cancelHighlightBackgroundNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: floor(size.width / 2.0), height: size.height)) self.doneButton.frame = CGRect(origin: CGPoint(x: floor(size.width / 2.0), y: 0.0), size: CGSize(width: size.width - floor(size.width / 2.0), height: size.height)) + self.doneHighlightBackgroundNode.frame = CGRect(origin: CGPoint(x: floor(size.width / 2.0), y: 0.0), size: CGSize(width: size.width - floor(size.width / 2.0), height: size.height)) self.separatorNode.frame = CGRect(origin: CGPoint(x: floor(size.width / 2.0), y: 0.0), size: CGSize(width: UIScreenPixel, height: size.height + layout.intrinsicInsets.bottom)) self.topSeparatorNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: UIScreenPixel)) } diff --git a/submodules/SyncCore/Sources/TelegramTheme.swift b/submodules/SyncCore/Sources/TelegramTheme.swift index 626658e29c..f6a4121213 100644 --- a/submodules/SyncCore/Sources/TelegramTheme.swift +++ b/submodules/SyncCore/Sources/TelegramTheme.swift @@ -25,11 +25,11 @@ public final class TelegramThemeSettings: PostboxCoding, Equatable { } public let baseTheme: TelegramBaseTheme - public let accentColor: Int32 - public let messageColors: (top: Int32, bottom: Int32)? + public let accentColor: UInt32 + public let messageColors: (top: UInt32, bottom: UInt32)? public let wallpaper: TelegramWallpaper? - public init(baseTheme: TelegramBaseTheme, accentColor: Int32, messageColors: (top: Int32, bottom: Int32)?, wallpaper: TelegramWallpaper?) { + public init(baseTheme: TelegramBaseTheme, accentColor: UInt32, messageColors: (top: UInt32, bottom: UInt32)?, wallpaper: TelegramWallpaper?) { self.baseTheme = baseTheme self.accentColor = accentColor self.messageColors = messageColors @@ -38,9 +38,9 @@ public final class TelegramThemeSettings: PostboxCoding, Equatable { public init(decoder: PostboxDecoder) { self.baseTheme = TelegramBaseTheme(rawValue: decoder.decodeInt32ForKey("baseTheme", orElse: 0)) ?? .classic - self.accentColor = decoder.decodeInt32ForKey("accent", orElse: 0) + self.accentColor = UInt32(bitPattern: decoder.decodeInt32ForKey("accent", orElse: 0)) if let topMessageColor = decoder.decodeOptionalInt32ForKey("topMessage"), let bottomMessageColor = decoder.decodeOptionalInt32ForKey("bottomMessage") { - self.messageColors = (topMessageColor, bottomMessageColor) + self.messageColors = (UInt32(bitPattern: topMessageColor), UInt32(bitPattern: bottomMessageColor)) } else { self.messageColors = nil } @@ -49,10 +49,10 @@ public final class TelegramThemeSettings: PostboxCoding, Equatable { public func encode(_ encoder: PostboxEncoder) { encoder.encodeInt32(self.baseTheme.rawValue, forKey: "baseTheme") - encoder.encodeInt32(self.accentColor, forKey: "accent") + encoder.encodeInt32(Int32(bitPattern: self.accentColor), forKey: "accent") if let (topMessageColor, bottomMessageColor) = self.messageColors { - encoder.encodeInt32(topMessageColor, forKey: "topMessage") - encoder.encodeInt32(bottomMessageColor, forKey: "bottomMessage") + encoder.encodeInt32(Int32(bitPattern: topMessageColor), forKey: "topMessage") + encoder.encodeInt32(Int32(bitPattern: bottomMessageColor), forKey: "bottomMessage") } else { encoder.encodeNil(forKey: "topMessage") encoder.encodeNil(forKey: "bottomMessage") diff --git a/submodules/TelegramCore/Sources/Theme.swift b/submodules/TelegramCore/Sources/Theme.swift index 5cc5d2f73f..217d2e0545 100644 --- a/submodules/TelegramCore/Sources/Theme.swift +++ b/submodules/TelegramCore/Sources/Theme.swift @@ -48,11 +48,11 @@ extension TelegramThemeSettings { convenience init?(apiThemeSettings: Api.ThemeSettings) { switch apiThemeSettings { case let .themeSettings(flags, baseTheme, accentColor, messageTopColor, messageBottomColor, wallpaper): - var messageColors: (Int32, Int32)? + var messageColors: (UInt32, UInt32)? if let messageTopColor = messageTopColor, let messageBottomColor = messageBottomColor { - messageColors = (messageTopColor, messageBottomColor) + messageColors = (UInt32(bitPattern: messageTopColor), UInt32(bitPattern: messageBottomColor)) } - self.init(baseTheme: TelegramBaseTheme(apiBaseTheme: baseTheme) ?? .classic, accentColor: accentColor, messageColors: messageColors, wallpaper: wallpaper.flatMap(TelegramWallpaper.init(apiWallpaper:))) + self.init(baseTheme: TelegramBaseTheme(apiBaseTheme: baseTheme) ?? .classic, accentColor: UInt32(bitPattern: accentColor), messageColors: messageColors, wallpaper: wallpaper.flatMap(TelegramWallpaper.init(apiWallpaper:))) default: return nil } @@ -72,6 +72,15 @@ extension TelegramThemeSettings { flags |= 1 << 1 } - return .inputThemeSettings(flags: flags, baseTheme: self.baseTheme.apiBaseTheme, accentColor: self.accentColor, messageTopColor: self.messageColors?.0, messageBottomColor: self.messageColors?.1, wallpaper: inputWallpaper, wallpaperSettings: inputWallpaperSettings) + var messageTopColor: Int32? + var messageBottomColor: Int32? + if let color = self.messageColors?.0 { + messageTopColor = Int32(bitPattern: color) + } + if let color = self.messageColors?.1 { + messageBottomColor = Int32(bitPattern: color) + } + + return .inputThemeSettings(flags: flags, baseTheme: self.baseTheme.apiBaseTheme, accentColor: Int32(bitPattern: self.accentColor), messageTopColor: messageTopColor, messageBottomColor: messageBottomColor, wallpaper: inputWallpaper, wallpaperSettings: inputWallpaperSettings) } } diff --git a/submodules/TelegramPresentationData/Sources/PresentationThemeCodable.swift b/submodules/TelegramPresentationData/Sources/PresentationThemeCodable.swift index 30c8e19f04..05203cb0ee 100644 --- a/submodules/TelegramPresentationData/Sources/PresentationThemeCodable.swift +++ b/submodules/TelegramPresentationData/Sources/PresentationThemeCodable.swift @@ -41,7 +41,7 @@ extension TelegramWallpaper: Codable { default: let optionKeys = ["motion", "blur"] - if value.count == 6, let color = UIColor(hexString: value) { + if [6, 8].contains(value.count), let color = UIColor(hexString: value) { self = .color(color.argb) } else { let components = value.components(separatedBy: " ") @@ -80,7 +80,7 @@ extension TelegramWallpaper: Codable { if optionKeys.contains(component) { continue } - if component.count == 6, let value = UIColor(hexString: component) { + if [6, 8].contains(component.count), let value = UIColor(hexString: component) { if color == nil { color = value.argb } else if bottomColor == nil { diff --git a/submodules/TelegramUI/TelegramUI/ChatHistoryListNode.swift b/submodules/TelegramUI/TelegramUI/ChatHistoryListNode.swift index 2057d72f89..f0205a0cda 100644 --- a/submodules/TelegramUI/TelegramUI/ChatHistoryListNode.swift +++ b/submodules/TelegramUI/TelegramUI/ChatHistoryListNode.swift @@ -1766,7 +1766,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode { self.selectionScrollDisplayLink = ConstantDisplayLinkAnimator(update: { [weak self] in self?.selectionScrollActivationTimer = nil if let strongSelf = self, let delta = strongSelf.selectionScrollDelta { - let distance: CGFloat = 10.0 * min(1.0, 0.15 + abs(delta * delta)) + let distance: CGFloat = 15.0 * min(1.0, 0.15 + abs(delta * delta)) let direction: ListViewScrollDirection = delta > 0.0 ? .up : .down strongSelf.scrollWithDirection(direction, distance: distance) diff --git a/submodules/UndoUI/Sources/UndoOverlayControllerNode.swift b/submodules/UndoUI/Sources/UndoOverlayControllerNode.swift index ff48060730..e5308845aa 100644 --- a/submodules/UndoUI/Sources/UndoOverlayControllerNode.swift +++ b/submodules/UndoUI/Sources/UndoOverlayControllerNode.swift @@ -153,7 +153,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode { self.textNode.attributedText = attributedText displayUndo = true undoText = cancel - self.originalRemainingSeconds = 3 + self.originalRemainingSeconds = 5 case let .emoji(path, text): self.iconNode = nil self.iconCheckNode = nil @@ -535,7 +535,12 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode { self.checkTimer() } + var dismissed = false func animateOut(completion: @escaping () -> Void) { + guard !self.dismissed else { + return + } + self.dismissed = true self.panelNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, delay: 0.0, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue, removeOnCompletion: false, completion: { _ in }) self.panelWrapperNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, delay: 0.0, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue, removeOnCompletion: false) { _ in completion() diff --git a/submodules/WallpaperResources/Sources/WallpaperResources.swift b/submodules/WallpaperResources/Sources/WallpaperResources.swift index e2cd0eceb9..a6b5270bac 100644 --- a/submodules/WallpaperResources/Sources/WallpaperResources.swift +++ b/submodules/WallpaperResources/Sources/WallpaperResources.swift @@ -527,7 +527,7 @@ public func patternColor(for color: UIColor, intensity: CGFloat, prominent: Bool } else { brightness = max(0.0, min(1.0, 1.0 - brightness * 0.65)) } - let alpha = (prominent ? 0.5 : 0.4) * intensity + let alpha = (prominent ? 0.6 : 0.55) * intensity return UIColor(hue: hue, saturation: saturation, brightness: brightness, alpha: alpha) } return .black