From 85e03431d63f4eab20ce588bc94c6a07932bcf77 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Mon, 16 Aug 2021 23:35:25 +0300 Subject: [PATCH 1/2] Show trending icon in packs scroller when trending strip is dismissed in the grid --- .../Sources/ChatMediaInputNode.swift | 20 +++++++++++-------- .../Sources/ChatMediaInputTrendingItem.swift | 1 - 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/submodules/TelegramUI/Sources/ChatMediaInputNode.swift b/submodules/TelegramUI/Sources/ChatMediaInputNode.swift index 1bd87f3af8..fea4e9e675 100644 --- a/submodules/TelegramUI/Sources/ChatMediaInputNode.swift +++ b/submodules/TelegramUI/Sources/ChatMediaInputNode.swift @@ -162,11 +162,14 @@ func preparedChatMediaInputGridEntryTransition(account: Account, view: ItemColle return ChatMediaInputGridTransition(deletions: deletions, insertions: insertions, updates: updates, updateFirstIndexInSectionOffset: firstIndexInSectionOffset, stationaryItems: stationaryItems, scrollToItem: scrollToItem, updateOpaqueState: opaqueState, animated: animated) } -func chatMediaInputPanelEntries(view: ItemCollectionsView, savedStickers: OrderedItemListView?, recentStickers: OrderedItemListView?, temporaryPackOrder: [ItemCollectionId]? = nil, peerSpecificPack: PeerSpecificPackData?, canInstallPeerSpecificPack: CanInstallPeerSpecificPack, theme: PresentationTheme, hasGifs: Bool = true, hasSettings: Bool = true, expanded: Bool = false) -> [ChatMediaInputPanelEntry] { +func chatMediaInputPanelEntries(view: ItemCollectionsView, savedStickers: OrderedItemListView?, recentStickers: OrderedItemListView?, temporaryPackOrder: [ItemCollectionId]? = nil, trendingIsDismissed: Bool = false, peerSpecificPack: PeerSpecificPackData?, canInstallPeerSpecificPack: CanInstallPeerSpecificPack, theme: PresentationTheme, hasGifs: Bool = true, hasSettings: Bool = true, expanded: Bool = false) -> [ChatMediaInputPanelEntry] { var entries: [ChatMediaInputPanelEntry] = [] if hasGifs { entries.append(.recentGifs(theme, expanded)) } + if trendingIsDismissed { + entries.append(.trending(true, theme, expanded)) + } if let savedStickers = savedStickers, !savedStickers.items.isEmpty { entries.append(.savedStickers(theme, expanded)) } @@ -251,7 +254,7 @@ func chatMediaInputPanelGifModeEntries(theme: PresentationTheme, reactions: [Str return entries } -func chatMediaInputGridEntries(view: ItemCollectionsView, savedStickers: OrderedItemListView?, recentStickers: OrderedItemListView?, peerSpecificPack: PeerSpecificPackData?, canInstallPeerSpecificPack: CanInstallPeerSpecificPack, trendingPacks: [FeaturedStickerPackItem], dismissedTrendingStickerPacks: [ItemCollectionId.Id]? = nil, hasSearch: Bool = true, hasAccessories: Bool = true, strings: PresentationStrings, theme: PresentationTheme) -> [ChatMediaInputGridEntry] { +func chatMediaInputGridEntries(view: ItemCollectionsView, savedStickers: OrderedItemListView?, recentStickers: OrderedItemListView?, peerSpecificPack: PeerSpecificPackData?, canInstallPeerSpecificPack: CanInstallPeerSpecificPack, trendingPacks: [FeaturedStickerPackItem], trendingIsDismissed: Bool = false, hasSearch: Bool = true, hasAccessories: Bool = true, strings: PresentationStrings, theme: PresentationTheme) -> [ChatMediaInputGridEntry] { var entries: [ChatMediaInputGridEntry] = [] if hasSearch && view.lower == nil { @@ -279,10 +282,6 @@ func chatMediaInputGridEntries(view: ItemCollectionsView, savedStickers: Ordered } } - var trendingIsDismissed = false - if let dismissedTrendingStickerPacks = dismissedTrendingStickerPacks, Set(trendingPacks.map({ $0.info.id.id })) == Set(dismissedTrendingStickerPacks) { - trendingIsDismissed = true - } if !trendingIsDismissed { entries.append(.trendingList(theme: theme, strings: strings, packs: trendingPacks)) } @@ -1106,10 +1105,15 @@ final class ChatMediaInputNode: ChatInputNode { for info in view.collectionInfos { installedPacks.insert(info.0) } + + var trendingIsDismissed = false + if let dismissedTrendingStickerPacks = dismissedTrendingStickerPacks, Set(trendingPacks.map({ $0.info.id.id })) == Set(dismissedTrendingStickerPacks) { + trendingIsDismissed = true + } - let panelEntries = chatMediaInputPanelEntries(view: view, savedStickers: savedStickers, recentStickers: recentStickers, temporaryPackOrder: temporaryPackOrder, peerSpecificPack: peerSpecificPack.0, canInstallPeerSpecificPack: peerSpecificPack.1, theme: theme, expanded: panelExpanded) + let panelEntries = chatMediaInputPanelEntries(view: view, savedStickers: savedStickers, recentStickers: recentStickers, temporaryPackOrder: temporaryPackOrder, trendingIsDismissed: trendingIsDismissed, peerSpecificPack: peerSpecificPack.0, canInstallPeerSpecificPack: peerSpecificPack.1, theme: theme, expanded: panelExpanded) let gifPaneEntries = chatMediaInputPanelGifModeEntries(theme: theme, reactions: reactions, animatedEmojiStickers: animatedEmojiStickers, expanded: panelExpanded) - var gridEntries = chatMediaInputGridEntries(view: view, savedStickers: savedStickers, recentStickers: recentStickers, peerSpecificPack: peerSpecificPack.0, canInstallPeerSpecificPack: peerSpecificPack.1, trendingPacks: trendingPacks, dismissedTrendingStickerPacks: dismissedTrendingStickerPacks, strings: strings, theme: theme) + var gridEntries = chatMediaInputGridEntries(view: view, savedStickers: savedStickers, recentStickers: recentStickers, peerSpecificPack: peerSpecificPack.0, canInstallPeerSpecificPack: peerSpecificPack.1, trendingPacks: trendingPacks, trendingIsDismissed: trendingIsDismissed, strings: strings, theme: theme) if view.higher == nil { var hasTopSeparator = true diff --git a/submodules/TelegramUI/Sources/ChatMediaInputTrendingItem.swift b/submodules/TelegramUI/Sources/ChatMediaInputTrendingItem.swift index b2d9cd33ea..f27923b5c8 100644 --- a/submodules/TelegramUI/Sources/ChatMediaInputTrendingItem.swift +++ b/submodules/TelegramUI/Sources/ChatMediaInputTrendingItem.swift @@ -133,7 +133,6 @@ final class ChatMediaInputTrendingItemNode: ListViewItemNode { if self.elevated != elevated { self.elevated = elevated - self.badgeBackground.isHidden = !self.elevated } self.containerNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: expandedBoundingSize) From 46917eaaf33fbcd409d0dfc11121c72d0bd1de85 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Tue, 17 Aug 2021 15:07:59 +0400 Subject: [PATCH 2/2] Various theme color picking fixes --- .../Themes/ThemeAccentColorController.swift | 18 +- .../ThemeAccentColorControllerNode.swift | 60 ++-- .../Themes/WallpaperColorPanelNode.swift | 60 +--- .../Themes/WallpaperColorPickerNode.swift | 281 ++++++++++++------ .../Themes/WallpaperGalleryController.swift | 14 +- .../Themes/WallpaperPatternPanelNode.swift | 4 +- 6 files changed, 250 insertions(+), 187 deletions(-) diff --git a/submodules/SettingsUI/Sources/Themes/ThemeAccentColorController.swift b/submodules/SettingsUI/Sources/Themes/ThemeAccentColorController.swift index ce33330196..627794a1a0 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemeAccentColorController.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemeAccentColorController.swift @@ -155,11 +155,11 @@ final class ThemeAccentColorController: ViewController { var coloredWallpaper: TelegramWallpaper? if !state.backgroundColors.isEmpty { if let patternWallpaper = state.patternWallpaper { - coloredWallpaper = patternWallpaper.withUpdatedSettings(WallpaperSettings(colors: state.backgroundColors, intensity: state.patternIntensity, rotation: state.rotation)) + coloredWallpaper = patternWallpaper.withUpdatedSettings(WallpaperSettings(colors: state.backgroundColors.map { $0.rgb }, intensity: state.patternIntensity, rotation: state.rotation)) } else if state.backgroundColors.count >= 2 { - coloredWallpaper = .gradient(TelegramWallpaper.Gradient(id: nil, colors: state.backgroundColors, settings: WallpaperSettings(rotation: state.rotation))) + coloredWallpaper = .gradient(TelegramWallpaper.Gradient(id: nil, colors: state.backgroundColors.map { $0.rgb }, settings: WallpaperSettings(rotation: state.rotation))) } else { - coloredWallpaper = .color(state.backgroundColors[0]) + coloredWallpaper = .color(state.backgroundColors[0].rgb) } } @@ -201,13 +201,13 @@ final class ThemeAccentColorController: ViewController { } if let themeReference = generalThemeReference { - updatedTheme = makePresentationTheme(mediaBox: context.sharedContext.accountManager.mediaBox, themeReference: themeReference, accentColor: state.accentColor, backgroundColors: state.backgroundColors, bubbleColors: state.messagesColors, wallpaper: coloredWallpaper ?? state.initialWallpaper, serviceBackgroundColor: serviceBackgroundColor) ?? defaultPresentationTheme + updatedTheme = makePresentationTheme(mediaBox: context.sharedContext.accountManager.mediaBox, themeReference: themeReference, accentColor: state.accentColor.color, backgroundColors: state.backgroundColors.map { $0.rgb }, bubbleColors: state.messagesColors.map { $0.rgb }, wallpaper: coloredWallpaper ?? state.initialWallpaper, serviceBackgroundColor: serviceBackgroundColor) ?? defaultPresentationTheme } else { - updatedTheme = customizePresentationTheme(theme, editing: false, accentColor: state.accentColor, backgroundColors: state.backgroundColors, bubbleColors: state.messagesColors, wallpaper: state.initialWallpaper ?? coloredWallpaper) + updatedTheme = customizePresentationTheme(theme, editing: false, accentColor: state.accentColor.color, backgroundColors: state.backgroundColors.map { $0.rgb }, bubbleColors: state.messagesColors.map { $0.rgb }, wallpaper: state.initialWallpaper ?? coloredWallpaper) } if hasSettings, let baseTheme = baseTheme { - settings = TelegramThemeSettings(baseTheme: baseTheme, accentColor: state.accentColor, messageColors: state.messagesColors, wallpaper: coloredWallpaper) + settings = TelegramThemeSettings(baseTheme: baseTheme, accentColor: state.accentColor.color, messageColors: state.messagesColors.map { $0.rgb }, wallpaper: coloredWallpaper) } completion(updatedTheme, settings) @@ -226,12 +226,12 @@ final class ThemeAccentColorController: ViewController { let wallpaper = coloredWallpaper ?? state.initialWallpaper - let settings = TelegramThemeSettings(baseTheme: baseTheme, accentColor: state.accentColor, messageColors: state.messagesColors, wallpaper: wallpaper) + let settings = TelegramThemeSettings(baseTheme: baseTheme, accentColor: state.accentColor.rgb, messageColors: state.messagesColors.map { $0.rgb }, wallpaper: wallpaper) let baseThemeReference = PresentationThemeReference.builtin(PresentationBuiltinThemeReference(baseTheme: baseTheme)) let apply: Signal if create { - apply = (prepareWallpaper |> then(createTheme(account: context.account, title: generateThemeName(accentColor: state.accentColor), resource: nil, thumbnailData: nil, settings: settings))) + apply = (prepareWallpaper |> then(createTheme(account: context.account, title: generateThemeName(accentColor: state.accentColor.color), resource: nil, thumbnailData: nil, settings: settings))) |> mapToSignal { next -> Signal in if case let .result(resultTheme) = next { let _ = applyTheme(accountManager: context.sharedContext.accountManager, account: context.account, theme: resultTheme).start() @@ -552,7 +552,7 @@ final class ThemeAccentColorController: ViewController { messageColors = [] } - let initialState = ThemeColorState(section: strongSelf.section, accentColor: accentColor, initialWallpaper: initialWallpaper, backgroundColors: backgroundColors, patternWallpaper: patternWallpaper, patternIntensity: patternIntensity, defaultMessagesColor: defaultMessagesColor, messagesColors: messageColors, rotation: rotation) + let initialState = ThemeColorState(section: strongSelf.section, accentColor: HSBColor(color: accentColor), initialWallpaper: initialWallpaper, backgroundColors: backgroundColors.map { HSBColor(rgb: $0) }, patternWallpaper: patternWallpaper, patternIntensity: patternIntensity, defaultMessagesColor: defaultMessagesColor.flatMap { HSBColor(color: $0) }, messagesColors: messageColors.map { HSBColor(rgb: $0) }, rotation: rotation) strongSelf.controllerNode.updateState({ _ in return initialState diff --git a/submodules/SettingsUI/Sources/Themes/ThemeAccentColorControllerNode.swift b/submodules/SettingsUI/Sources/Themes/ThemeAccentColorControllerNode.swift index 0680d731df..192d23aca3 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemeAccentColorControllerNode.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemeAccentColorControllerNode.swift @@ -39,17 +39,17 @@ struct ThemeColorState { fileprivate var colorPanelCollapsed: Bool fileprivate var displayPatternPanel: Bool - var accentColor: UIColor + var accentColor: HSBColor var initialWallpaper: TelegramWallpaper? - var backgroundColors: [UInt32] + var backgroundColors: [HSBColor] fileprivate var preview: Bool fileprivate var previousPatternWallpaper: TelegramWallpaper? var patternWallpaper: TelegramWallpaper? var patternIntensity: Int32 - var defaultMessagesColor: UIColor? - var messagesColors: [UInt32] + var defaultMessagesColor: HSBColor? + var messagesColors: [HSBColor] var rotation: Int32 @@ -57,7 +57,7 @@ struct ThemeColorState { self.section = nil self.colorPanelCollapsed = false self.displayPatternPanel = false - self.accentColor = .clear + self.accentColor = HSBColor(hue: 0.0, saturation: 0.0, brightness: 1.0) self.initialWallpaper = nil self.backgroundColors = [] self.preview = false @@ -69,7 +69,7 @@ struct ThemeColorState { self.rotation = 0 } - init(section: ThemeColorSection, accentColor: UIColor, initialWallpaper: TelegramWallpaper?, backgroundColors: [UInt32], patternWallpaper: TelegramWallpaper?, patternIntensity: Int32, defaultMessagesColor: UIColor?, messagesColors: [UInt32], rotation: Int32 = 0) { + init(section: ThemeColorSection, accentColor: HSBColor, initialWallpaper: TelegramWallpaper?, backgroundColors: [HSBColor], patternWallpaper: TelegramWallpaper?, patternIntensity: Int32, defaultMessagesColor: HSBColor?, messagesColors: [HSBColor], rotation: Int32 = 0) { self.section = section self.colorPanelCollapsed = false self.displayPatternPanel = false @@ -116,9 +116,9 @@ struct ThemeColorState { private func calcPatternColors(for state: ThemeColorState) -> [UIColor] { if state.backgroundColors.count >= 1 { let patternIntensity = CGFloat(state.patternIntensity) / 100.0 - let topPatternColor = UIColor(rgb: state.backgroundColors[0]).withAlphaComponent(patternIntensity) + let topPatternColor = state.backgroundColors[0].color.withAlphaComponent(patternIntensity) if state.backgroundColors.count >= 2 { - let bottomPatternColor = UIColor(rgb: state.backgroundColors[1]).withAlphaComponent(patternIntensity) + let bottomPatternColor = state.backgroundColors[1].color.withAlphaComponent(patternIntensity) return [topPatternColor, bottomPatternColor] } else { return [topPatternColor, topPatternColor] @@ -176,7 +176,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate private let serviceBackgroundColorPromise = Promise() private var wallpaperDisposable = MetaDisposable() - private var currentBackgroundColors: ([UInt32], Int32?, Int32?)? + private var currentBackgroundColors: ([HSBColor], Int32?, Int32?)? private var currentBackgroundPromise = Promise<(UIColor, UIColor?)?>() private var patternWallpaper: TelegramWallpaper? @@ -332,7 +332,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate switch section { case .accent: if let firstColor = colors.first { - updated.accentColor = UIColor(rgb: firstColor) + updated.accentColor = firstColor } case .background: updated.backgroundColors = colors @@ -420,7 +420,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate |> mapToThrottled { next -> Signal in return .single(next) |> then(.complete() |> delay(0.0166667, queue: self.queue)) } - |> map { state -> (PresentationTheme?, TelegramWallpaper, UIColor, [UInt32], Int32, PatternWallpaperArguments, Bool) in + |> map { state -> (PresentationTheme?, TelegramWallpaper, UIColor, [HSBColor], Int32, PatternWallpaperArguments, Bool) in let accentColor = state.accentColor var backgroundColors = state.backgroundColors let messagesColors = state.messagesColors @@ -434,7 +434,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate if !backgroundColors.isEmpty { if let patternWallpaper = state.patternWallpaper, case let .file(file) = patternWallpaper { - wallpaper = patternWallpaper.withUpdatedSettings(WallpaperSettings(colors: backgroundColors, intensity: state.patternIntensity, rotation: state.rotation)) + wallpaper = patternWallpaper.withUpdatedSettings(WallpaperSettings(colors: backgroundColors.map { $0.rgb }, intensity: state.patternIntensity, rotation: state.rotation)) let dimensions = file.file.dimensions ?? PixelDimensions(width: 100, height: 100) var convertedRepresentations: [ImageRepresentationWithReference] = [] @@ -443,22 +443,22 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate } convertedRepresentations.append(ImageRepresentationWithReference(representation: .init(dimensions: dimensions, resource: file.file.resource, progressiveSizes: [], immediateThumbnailData: nil), reference: .wallpaper(wallpaper: .slug(file.slug), resource: file.file.resource))) } else if backgroundColors.count >= 2 { - wallpaper = .gradient(TelegramWallpaper.Gradient(id: nil, colors: backgroundColors, settings: WallpaperSettings(rotation: state.rotation))) + wallpaper = .gradient(TelegramWallpaper.Gradient(id: nil, colors: backgroundColors.map { $0.rgb }, settings: WallpaperSettings(rotation: state.rotation))) } else { - wallpaper = .color(backgroundColors.first ?? 0xffffff) + wallpaper = .color(backgroundColors.first?.rgb ?? 0xffffff) } } else if let themeReference = mode.themeReference, case let .builtin(theme) = themeReference, state.initialWallpaper == nil { var suggestedWallpaper: TelegramWallpaper switch theme { case .dayClassic: - let topColor = accentColor.withMultiplied(hue: 1.010, saturation: 0.414, brightness: 0.957) - let bottomColor = accentColor.withMultiplied(hue: 1.019, saturation: 0.867, brightness: 0.965) + let topColor = HSBColor(color: accentColor.color.withMultiplied(hue: 1.010, saturation: 0.414, brightness: 0.957)) + let bottomColor = HSBColor(color: accentColor.color.withMultiplied(hue: 1.019, saturation: 0.867, brightness: 0.965)) suggestedWallpaper = .gradient(TelegramWallpaper.Gradient(id: nil, colors: [topColor.rgb, bottomColor.rgb], settings: WallpaperSettings())) - backgroundColors = [topColor.rgb, bottomColor.rgb] + backgroundColors = [topColor, bottomColor] case .nightAccent: - let color = accentColor.withMultiplied(hue: 1.024, saturation: 0.573, brightness: 0.18) + let color = HSBColor(color: accentColor.color.withMultiplied(hue: 1.024, saturation: 0.573, brightness: 0.18)) suggestedWallpaper = .color(color.rgb) - backgroundColors = [color.rgb] + backgroundColors = [color] default: suggestedWallpaper = .builtin(WallpaperSettings()) } @@ -472,9 +472,9 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate if !updateOnlyWallpaper { if let themeReference = mode.themeReference { - updatedTheme = makePresentationTheme(mediaBox: context.sharedContext.accountManager.mediaBox, themeReference: themeReference, accentColor: accentColor, backgroundColors: backgroundColors, bubbleColors: messagesColors, serviceBackgroundColor: serviceBackgroundColor, preview: true) ?? defaultPresentationTheme + updatedTheme = makePresentationTheme(mediaBox: context.sharedContext.accountManager.mediaBox, themeReference: themeReference, accentColor: accentColor.color, backgroundColors: backgroundColors.map { $0.rgb }, bubbleColors: messagesColors.map { $0.rgb }, serviceBackgroundColor: serviceBackgroundColor, preview: true) ?? defaultPresentationTheme } else if case let .edit(theme, _, _, _, _, _) = mode { - updatedTheme = customizePresentationTheme(theme, editing: false, accentColor: accentColor, backgroundColors: backgroundColors, bubbleColors: messagesColors) + updatedTheme = customizePresentationTheme(theme, editing: false, accentColor: accentColor.color, backgroundColors: backgroundColors.map { $0.rgb }, bubbleColors: messagesColors.map { $0.rgb }) } else { updatedTheme = theme } @@ -516,7 +516,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate strongSelf.wallpaper = wallpaper strongSelf.patternArguments = patternArguments - strongSelf.colorsButtonNode.colors = backgroundColors.map(UIColor.init(rgb:)) + strongSelf.colorsButtonNode.colors = backgroundColors.map { $0.color } if !preview { if !backgroundColors.isEmpty { @@ -573,6 +573,8 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate override func didLoad() { super.didLoad() + self.view.disablesInteractiveModalDismiss = true + self.scrollNode.view.bounces = false self.scrollNode.view.disablesInteractiveTransitionGestureRecognizer = true self.scrollNode.view.showsHorizontalScrollIndicator = false @@ -619,18 +621,18 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate if sectionChanged, let section = self.state.section { self.view.endEditing(true) - var colors: [UInt32] - var defaultColor: UIColor? + var colors: [HSBColor] + var defaultColor: HSBColor? switch section { case .accent: - colors = [self.state.accentColor.rgb] + colors = [self.state.accentColor] case .background: if let themeReference = self.mode.themeReference, case let .builtin(theme) = themeReference { switch theme { case .dayClassic: - defaultColor = self.state.accentColor.withMultiplied(hue: 1.019, saturation: 0.867, brightness: 0.965) + defaultColor = HSBColor(color: self.state.accentColor.color.withMultiplied(hue: 1.019, saturation: 0.867, brightness: 0.965)) case .nightAccent: - defaultColor = self.state.accentColor.withMultiplied(hue: 1.024, saturation: 0.573, brightness: 0.18) + defaultColor = HSBColor(color: self.state.accentColor.color.withMultiplied(hue: 1.024, saturation: 0.573, brightness: 0.18)) default: break } @@ -644,7 +646,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate if let defaultMessagesColor = self.state.defaultMessagesColor { defaultColor = defaultMessagesColor } else if let themeReference = self.mode.themeReference, case let .builtin(theme) = themeReference, theme == .nightAccent { - defaultColor = self.state.accentColor.withMultiplied(hue: 1.019, saturation: 0.731, brightness: 0.59) + defaultColor = HSBColor(color: self.state.accentColor.color.withMultiplied(hue: 1.019, saturation: 0.731, brightness: 0.59)) } else { defaultColor = self.state.accentColor } @@ -656,7 +658,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate } if colors.isEmpty, let defaultColor = defaultColor { - colors = [defaultColor.rgb] + colors = [defaultColor] } let maximumNumberOfColors: Int diff --git a/submodules/SettingsUI/Sources/Themes/WallpaperColorPanelNode.swift b/submodules/SettingsUI/Sources/Themes/WallpaperColorPanelNode.swift index 65aa51cdb6..44b4743597 100644 --- a/submodules/SettingsUI/Sources/Themes/WallpaperColorPanelNode.swift +++ b/submodules/SettingsUI/Sources/Themes/WallpaperColorPanelNode.swift @@ -312,7 +312,7 @@ private class ColorInputFieldNode: ASDisplayNode, UITextFieldDelegate { struct WallpaperColorPanelNodeState: Equatable { var selection: Int? - var colors: [UInt32] + var colors: [HSBColor] var maximumNumberOfColors: Int var rotateAvailable: Bool var rotation: Int32 @@ -390,7 +390,7 @@ final class WallpaperColorPanelNode: ASDisplayNode { private var sampleItemNodes: [ColorSampleItemNode] = [] private let multiColorFieldNode: ColorInputFieldNode - var colorsChanged: (([UInt32], Bool) -> Void)? + var colorsChanged: (([HSBColor], Bool) -> Void)? var colorSelected: (() -> Void)? var rotate: (() -> Void)? @@ -456,7 +456,7 @@ final class WallpaperColorPanelNode: ASDisplayNode { var updated = current updated.preview = !ended if let index = strongSelf.state.selection { - updated.colors[index] = color.rgb + updated.colors[index] = HSBColor(color: color) } return updated }) @@ -486,7 +486,7 @@ final class WallpaperColorPanelNode: ASDisplayNode { var updated = current updated.preview = true if let index = strongSelf.state.selection { - updated.colors[index] = color.rgb + updated.colors[index] = color } return updated }, updateLayout: false) @@ -498,7 +498,7 @@ final class WallpaperColorPanelNode: ASDisplayNode { var updated = current updated.preview = false if let index = strongSelf.state.selection { - updated.colors[index] = color.rgb + updated.colors[index] = color } return updated }, updateLayout: false) @@ -528,7 +528,7 @@ final class WallpaperColorPanelNode: ASDisplayNode { if let index = self.state.selection { if self.state.colors.count > index { - self.colorPickerNode.color = UIColor(rgb: self.state.colors[index]) + self.colorPickerNode.color = self.state.colors[index] } } @@ -536,15 +536,15 @@ final class WallpaperColorPanelNode: ASDisplayNode { self.updateLayout(size: size, transition: animated ? .animated(duration: 0.3, curve: .easeInOut) : .immediate) } - if let index = state.selection { + if let index = self.state.selection { if self.state.colors.count > index { - self.multiColorFieldNode.setColor(UIColor(rgb: self.state.colors[index]), update: false) + self.multiColorFieldNode.setColor(self.state.colors[index].color, update: false) } } - for i in 0 ..< state.colors.count { + for i in 0 ..< self.state.colors.count { if i < self.sampleItemNodes.count { - self.sampleItemNodes[i].update(size: self.sampleItemNodes[i].bounds.size, color: UIColor(rgb: state.colors[i]), isSelected: state.selection == i) + self.sampleItemNodes[i].update(size: self.sampleItemNodes[i].bounds.size, color: self.state.colors[i].color, isSelected: state.selection == i) } } @@ -658,7 +658,7 @@ final class WallpaperColorPanelNode: ASDisplayNode { } itemNode.frame = CGRect(origin: CGPoint(x: nextSampleX, y: (topPanelHeight - sampleItemSize) / 2.0), size: CGSize(width: sampleItemSize, height: sampleItemSize)) nextSampleX += sampleItemSize - itemNode.update(size: itemNode.bounds.size, color: UIColor(rgb: self.state.colors[i]), isSelected: self.state.selection == i) + itemNode.update(size: itemNode.bounds.size, color: self.state.colors[i].color, isSelected: self.state.selection == i) if animateIn { transition.animateTransformScale(node: itemNode, from: 0.1) @@ -722,9 +722,9 @@ final class WallpaperColorPanelNode: ASDisplayNode { var current = current if current.colors.count < current.maximumNumberOfColors { if current.colors.isEmpty { - current.colors.append(0xffffff) + current.colors.append(HSBColor(rgb: 0xffffff)) } else if current.simpleGradientGeneration { - var hsb = UIColor(rgb: current.colors[0]).hsb + var hsb = current.colors[0].values if hsb.1 > 0.5 { hsb.1 -= 0.15 } else { @@ -735,7 +735,7 @@ final class WallpaperColorPanelNode: ASDisplayNode { } else { hsb.0 += 0.05 } - current.colors.append(UIColor(hue: hsb.0, saturation: hsb.1, brightness: hsb.2, alpha: 1.0).rgb) + current.colors.append(HSBColor(values: hsb)) } else { current.colors.append(current.colors[current.colors.count - 1]) } @@ -743,38 +743,6 @@ final class WallpaperColorPanelNode: ASDisplayNode { } return current }) - - /*self.firstColorFieldNode.setSkipEndEditingIfNeeded() - - self.updateState({ current in - var updated = current - updated.selection = .index(1) - - let firstColor = current.firstColor ?? current.defaultColor - if let color = firstColor { - updated.firstColor = color - - let secondColor: UIColor - if updated.simpleGradientGeneration { - var hsb = color.hsb - if hsb.1 > 0.5 { - hsb.1 -= 0.15 - } else { - hsb.1 += 0.15 - } - if hsb.0 > 0.5 { - hsb.0 -= 0.05 - } else { - hsb.0 += 0.05 - } - updated.secondColor = UIColor(hue: hsb.0, saturation: hsb.1, brightness: hsb.2, alpha: 1.0) - } else { - updated.secondColor = generateGradientColors(color: color).1 - } - } - - return updated - })*/ } override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { diff --git a/submodules/SettingsUI/Sources/Themes/WallpaperColorPickerNode.swift b/submodules/SettingsUI/Sources/Themes/WallpaperColorPickerNode.swift index 48b935af57..4f8acaa470 100644 --- a/submodules/SettingsUI/Sources/Themes/WallpaperColorPickerNode.swift +++ b/submodules/SettingsUI/Sources/Themes/WallpaperColorPickerNode.swift @@ -89,11 +89,10 @@ private final class HSBParameter: NSObject { } private final class WallpaperColorKnobNode: ASDisplayNode { - var hsb: (CGFloat, CGFloat, CGFloat) = (0.0, 0.0, 1.0) { + var color: HSBColor = HSBColor(hue: 0.0, saturation: 0.0, brightness: 1.0) { didSet { - if self.hsb != oldValue { - let color = UIColor(hue: hsb.0, saturation: hsb.1, brightness: hsb.2, alpha: 1.0) - self.colorNode.backgroundColor = color + if self.color != oldValue { + self.colorNode.backgroundColor = self.color.color } } } @@ -166,6 +165,64 @@ private final class WallpaperColorHueSaturationNode: ASDisplayNode { context.setFillColor(UIColor(rgb: 0x000000, alpha: 1.0 - parameters.value).cgColor) context.fill(bounds) } + + var tap: ((CGPoint) -> Void)? + var panBegan: ((CGPoint) -> Void)? + var panChanged: ((CGPoint, Bool) -> Void)? + + var initialTouchLocation: CGPoint? + var touchMoved = false + var previousTouchLocation: CGPoint? + override func touchesBegan(_ touches: Set, with event: UIEvent?) { + super.touchesBegan(touches, with: event) + + if let touchLocation = touches.first?.location(in: self.view) { + self.touchMoved = false + self.initialTouchLocation = touchLocation + self.previousTouchLocation = nil + } + } + + override func touchesMoved(_ touches: Set, with event: UIEvent?) { + super.touchesMoved(touches, with: event) + + if let touchLocation = touches.first?.location(in: self.view), let initialLocation = self.initialTouchLocation { + let dX = touchLocation.x - initialLocation.x + let dY = touchLocation.y - initialLocation.y + if !self.touchMoved && dX * dX + dY * dY > 3.0 { + self.touchMoved = true + self.panBegan?(touchLocation) + self.previousTouchLocation = touchLocation + } else if let previousTouchLocation = self.previousTouchLocation { + let dX = touchLocation.x - previousTouchLocation.x + let dY = touchLocation.y - previousTouchLocation.y + let translation = CGPoint(x: dX, y: dY) + + self.panChanged?(translation, false) + self.previousTouchLocation = touchLocation + } + } + } + + override func touchesEnded(_ touches: Set, with event: UIEvent?) { + super.touchesEnded(touches, with: event) + + if self.touchMoved { + if let touchLocation = touches.first?.location(in: self.view), let previousTouchLocation = self.previousTouchLocation { + let dX = touchLocation.x - previousTouchLocation.x + let dY = touchLocation.y - previousTouchLocation.y + let translation = CGPoint(x: dX, y: dY) + + self.panChanged?(translation, true) + } + } else if let touchLocation = self.initialTouchLocation { + self.tap?(touchLocation) + } + } + + override func touchesCancelled(_ touches: Set?, with event: UIEvent?) { + super.touchesCancelled(touches, with: event) + } } private final class WallpaperColorBrightnessNode: ASDisplayNode { @@ -209,6 +266,50 @@ private final class WallpaperColorBrightnessNode: ASDisplayNode { } } +struct HSBColor: Equatable { + static func == (lhs: HSBColor, rhs: HSBColor) -> Bool { + return lhs.values.h == rhs.values.h && lhs.values.s == rhs.values.s && lhs.values.b == rhs.values.b + } + + let values: (h: CGFloat, s: CGFloat, b: CGFloat) + + var hue: CGFloat { + return self.values.h + } + + var saturation: CGFloat { + return self.values.s + } + + var brightness: CGFloat { + return self.values.b + } + + var rgb: UInt32 { + return self.color.rgb + } + + init(values: (h: CGFloat, s: CGFloat, b: CGFloat)) { + self.values = values + } + + init(hue: CGFloat, saturation: CGFloat, brightness: CGFloat) { + self.values = (h: hue, s: saturation, b: brightness) + } + + init(color: UIColor) { + self.values = color.hsb + } + + init(rgb: UInt32) { + self.init(color: UIColor(rgb: rgb)) + } + + var color: UIColor { + return UIColor(hue: self.values.h, saturation: self.values.s, brightness: self.values.b, alpha: 1.0) + } +} + final class WallpaperColorPickerNode: ASDisplayNode { private let brightnessNode: WallpaperColorBrightnessNode private let brightnessKnobNode: ASImageNode @@ -217,21 +318,16 @@ final class WallpaperColorPickerNode: ASDisplayNode { private var validLayout: CGSize? - var colorHsb: (CGFloat, CGFloat, CGFloat) = (0.0, 1.0, 1.0) - var color: UIColor { - get { - return UIColor(hue: self.colorHsb.0, saturation: self.colorHsb.1, brightness: self.colorHsb.2, alpha: 1.0) - } - set { - let newHsb = newValue.hsb - if newHsb != self.colorHsb { - self.colorHsb = newHsb + var color: HSBColor = HSBColor(hue: 0.0, saturation: 1.0, brightness: 1.0) { + didSet { + if self.color != oldValue { self.update() } } } - var colorChanged: ((UIColor) -> Void)? - var colorChangeEnded: ((UIColor) -> Void)? + + var colorChanged: ((HSBColor) -> Void)? + var colorChangeEnded: ((HSBColor) -> Void)? init(strings: PresentationStrings) { self.brightnessNode = WallpaperColorBrightnessNode() @@ -253,16 +349,79 @@ final class WallpaperColorPickerNode: ASDisplayNode { self.addSubnode(self.colorKnobNode) self.update() + + self.colorNode.tap = { [weak self] location in + guard let strongSelf = self, let size = strongSelf.validLayout else { + return + } + + let colorHeight = size.height - 66.0 + + let newHue = max(0.0, min(1.0, location.x / size.width)) + let newSaturation = max(0.0, min(1.0, (1.0 - location.y / colorHeight))) + strongSelf.color = HSBColor(hue: newHue, saturation: newSaturation, brightness: strongSelf.color.brightness) + + strongSelf.updateKnobLayout(size: size, panningColor: false, transition: .immediate) + + strongSelf.update() + strongSelf.colorChangeEnded?(strongSelf.color) + } + + self.colorNode.panBegan = { [weak self] location in + guard let strongSelf = self, let size = strongSelf.validLayout else { + return + } + + let previousColor = strongSelf.color + + let colorHeight = size.height - 66.0 + + let newHue = max(0.0, min(1.0, location.x / size.width)) + let newSaturation = max(0.0, min(1.0, (1.0 - location.y / colorHeight))) + strongSelf.color = HSBColor(hue: newHue, saturation: newSaturation, brightness: strongSelf.color.brightness) + + strongSelf.updateKnobLayout(size: size, panningColor: true, transition: .immediate) + + if strongSelf.color != previousColor { + strongSelf.colorChanged?(strongSelf.color) + } + } + + self.colorNode.panChanged = { [weak self] translation, ended in + guard let strongSelf = self, let size = strongSelf.validLayout else { + return + } + + let previousColor = strongSelf.color + + let colorHeight = size.height - 66.0 + + let newHue = max(0.0, min(1.0, strongSelf.color.hue + translation.x / size.width)) + let newSaturation = max(0.0, min(1.0, strongSelf.color.saturation - translation.y / colorHeight)) + strongSelf.color = HSBColor(hue: newHue, saturation: newSaturation, brightness: strongSelf.color.brightness) + + if ended { + strongSelf.updateKnobLayout(size: size, panningColor: false, transition: .animated(duration: 0.3, curve: .easeInOut)) + } else { + strongSelf.updateKnobLayout(size: size, panningColor: true, transition: .immediate) + } + + if strongSelf.color != previousColor || ended { + strongSelf.update() + if ended { + strongSelf.colorChangeEnded?(strongSelf.color) + } else { + strongSelf.colorChanged?(strongSelf.color) + } + } + } } override func didLoad() { super.didLoad() - let colorPanRecognizer = UIPanGestureRecognizer(target: self, action: #selector(WallpaperColorPickerNode.colorPan)) - self.colorNode.view.addGestureRecognizer(colorPanRecognizer) - - let colorTapRecognizer = UITapGestureRecognizer(target: self, action: #selector(WallpaperColorPickerNode.colorTap)) - self.colorNode.view.addGestureRecognizer(colorTapRecognizer) + self.view.disablesInteractiveTransitionGestureRecognizer = true + self.view.disablesInteractiveModalDismiss = true let brightnessPanRecognizer = UIPanGestureRecognizer(target: self, action: #selector(WallpaperColorPickerNode.brightnessPan)) self.brightnessNode.view.addGestureRecognizer(brightnessPanRecognizer) @@ -270,16 +429,16 @@ final class WallpaperColorPickerNode: ASDisplayNode { private func update() { self.backgroundColor = .white - self.colorNode.value = self.colorHsb.2 - self.brightnessNode.hsb = self.colorHsb - self.colorKnobNode.hsb = self.colorHsb + self.colorNode.value = self.color.brightness + self.brightnessNode.hsb = self.color.values + self.colorKnobNode.color = self.color } private func updateKnobLayout(size: CGSize, panningColor: Bool, transition: ContainedViewLayoutTransition) { let knobSize = CGSize(width: 45.0, height: 45.0) let colorHeight = size.height - 66.0 - var colorKnobFrame = CGRect(x: floorToScreenPixels(-knobSize.width / 2.0 + size.width * self.colorHsb.0), y: floorToScreenPixels(-knobSize.height / 2.0 + (colorHeight * (1.0 - self.colorHsb.1))), width: knobSize.width, height: knobSize.height) + var colorKnobFrame = CGRect(x: floorToScreenPixels(-knobSize.width / 2.0 + size.width * self.color.hue), y: floorToScreenPixels(-knobSize.height / 2.0 + (colorHeight * (1.0 - self.color.saturation))), width: knobSize.width, height: knobSize.height) var origin = colorKnobFrame.origin if !panningColor { origin = CGPoint(x: max(0.0, min(origin.x, size.width - knobSize.width)), y: max(0.0, min(origin.y, colorHeight - knobSize.height))) @@ -291,7 +450,7 @@ final class WallpaperColorPickerNode: ASDisplayNode { let inset: CGFloat = 15.0 let brightnessKnobSize = CGSize(width: 12.0, height: 55.0) - let brightnessKnobFrame = CGRect(x: inset - brightnessKnobSize.width / 2.0 + (size.width - inset * 2.0) * (1.0 - self.colorHsb.2), y: size.height - 65.0, width: brightnessKnobSize.width, height: brightnessKnobSize.height) + let brightnessKnobFrame = CGRect(x: inset - brightnessKnobSize.width / 2.0 + (size.width - inset * 2.0) * (1.0 - self.color.brightness), y: size.height - 65.0, width: brightnessKnobSize.width, height: brightnessKnobSize.height) transition.updateFrame(node: self.brightnessKnobNode, frame: brightnessKnobFrame) } @@ -307,72 +466,6 @@ final class WallpaperColorPickerNode: ASDisplayNode { self.updateKnobLayout(size: size, panningColor: false, transition: .immediate) } - @objc private func colorTap(_ recognizer: UITapGestureRecognizer) { - guard let size = self.validLayout, recognizer.state == .recognized else { - return - } - - let colorHeight = size.height - 66.0 - - let location = recognizer.location(in: recognizer.view) - let newHue = max(0.0, min(1.0, location.x / size.width)) - let newSaturation = max(0.0, min(1.0, (1.0 - location.y / colorHeight))) - self.colorHsb.0 = newHue - self.colorHsb.1 = newSaturation - - self.updateKnobLayout(size: size, panningColor: false, transition: .immediate) - - self.update() - self.colorChangeEnded?(self.color) - } - - @objc private func colorPan(_ recognizer: UIPanGestureRecognizer) { - guard let size = self.validLayout else { - return - } - - let previousColor = self.color - - let colorHeight = size.height - 66.0 - - let location = recognizer.location(in: recognizer.view) - let transition = recognizer.translation(in: recognizer.view) - if recognizer.state == .began { - let newHue = max(0.0, min(1.0, location.x / size.width)) - let newSaturation = max(0.0, min(1.0, (1.0 - location.y / colorHeight))) - self.colorHsb.0 = newHue - self.colorHsb.1 = newSaturation - } else { - let newHue = max(0.0, min(1.0, self.colorHsb.0 + transition.x / size.width)) - let newSaturation = max(0.0, min(1.0, self.colorHsb.1 - transition.y / (size.height - 66.0))) - self.colorHsb.0 = newHue - self.colorHsb.1 = newSaturation - } - - var ended = false - switch recognizer.state { - case .began: - self.updateKnobLayout(size: size, panningColor: true, transition: .immediate) - case .changed: - self.updateKnobLayout(size: size, panningColor: true, transition: .immediate) - recognizer.setTranslation(CGPoint(), in: recognizer.view) - case .ended: - self.updateKnobLayout(size: size, panningColor: false, transition: .animated(duration: 0.3, curve: .easeInOut)) - ended = true - default: - break - } - - if self.color != previousColor || ended { - self.update() - if ended { - self.colorChangeEnded?(self.color) - } else { - self.colorChanged?(self.color) - } - } - } - @objc private func brightnessPan(_ recognizer: UIPanGestureRecognizer) { guard let size = self.validLayout else { return @@ -382,9 +475,9 @@ final class WallpaperColorPickerNode: ASDisplayNode { let transition = recognizer.translation(in: recognizer.view) let brightnessWidth: CGFloat = size.width - 42.0 * 2.0 - let newValue = max(0.0, min(1.0, self.colorHsb.2 - transition.x / brightnessWidth)) - self.colorHsb.2 = newValue - + let newValue = max(0.0, min(1.0, self.color.brightness - transition.x / brightnessWidth)) + self.color = HSBColor(hue: self.color.hue, saturation: self.color.saturation, brightness: newValue) + var ended = false switch recognizer.state { case .changed: diff --git a/submodules/SettingsUI/Sources/Themes/WallpaperGalleryController.swift b/submodules/SettingsUI/Sources/Themes/WallpaperGalleryController.swift index d9e2e886ad..d95e1de199 100644 --- a/submodules/SettingsUI/Sources/Themes/WallpaperGalleryController.swift +++ b/submodules/SettingsUI/Sources/Themes/WallpaperGalleryController.swift @@ -631,11 +631,11 @@ public class WallpaperGalleryController: ViewController { strongSelf.patternInitialWallpaper = enabled ? initialWallpaper : nil switch initialWallpaper { case let .color(color): - strongSelf.patternPanelNode?.backgroundColors = ([color], nil, nil) + strongSelf.patternPanelNode?.backgroundColors = ([HSBColor(rgb: color)], nil, nil) case let .gradient(gradient): - strongSelf.patternPanelNode?.backgroundColors = (gradient.colors, gradient.settings.rotation, nil) + strongSelf.patternPanelNode?.backgroundColors = (gradient.colors.map { HSBColor(rgb: $0) }, gradient.settings.rotation, nil) case let .file(file) where file.isPattern: - strongSelf.patternPanelNode?.backgroundColors = (file.settings.colors, file.settings.rotation, file.settings.intensity) + strongSelf.patternPanelNode?.backgroundColors = (file.settings.colors.map { HSBColor(rgb: $0) }, file.settings.rotation, file.settings.intensity) default: break } @@ -678,7 +678,7 @@ public class WallpaperGalleryController: ViewController { strongSelf.colorsPanelNode?.updateState({ _ in return WallpaperColorPanelNodeState( selection: 0, - colors: colors.map(\.rgb), + colors: colors.map { HSBColor(color: $0) }, maximumNumberOfColors: 4, rotateAvailable: false, rotation: 0, @@ -863,7 +863,7 @@ public class WallpaperGalleryController: ViewController { break } - strongSelf.patternPanelNode?.backgroundColors = (colors, rotation, intensity) + strongSelf.patternPanelNode?.backgroundColors = (colors.map { HSBColor(rgb: $0) }, rotation, intensity) } } self.patternPanelNode = patternPanelNode @@ -888,10 +888,10 @@ public class WallpaperGalleryController: ViewController { return } - var wallpaper: TelegramWallpaper = .gradient(TelegramWallpaper.Gradient(id: nil, colors: colors, settings: WallpaperSettings(blur: false, motion: false, colors: [], intensity: nil, rotation: nil))) + var wallpaper: TelegramWallpaper = .gradient(TelegramWallpaper.Gradient(id: nil, colors: colors.map { $0.rgb }, settings: WallpaperSettings(blur: false, motion: false, colors: [], intensity: nil, rotation: nil))) if case let .file(file) = currentWallpaper { - wallpaper = currentWallpaper.withUpdatedSettings(WallpaperSettings(blur: false, motion: false, colors: colors, intensity: file.settings.intensity, rotation: file.settings.rotation)) + wallpaper = currentWallpaper.withUpdatedSettings(WallpaperSettings(blur: false, motion: false, colors: colors.map { $0.rgb }, intensity: file.settings.intensity, rotation: file.settings.rotation)) } strongSelf.updateEntries(wallpaper: wallpaper) diff --git a/submodules/SettingsUI/Sources/Themes/WallpaperPatternPanelNode.swift b/submodules/SettingsUI/Sources/Themes/WallpaperPatternPanelNode.swift index 40ef3d92ad..49f8145eda 100644 --- a/submodules/SettingsUI/Sources/Themes/WallpaperPatternPanelNode.swift +++ b/submodules/SettingsUI/Sources/Themes/WallpaperPatternPanelNode.swift @@ -200,7 +200,7 @@ final class WallpaperPatternPanelNode: ASDisplayNode { } } - var backgroundColors: ([UInt32], Int32?, Int32?)? = nil { + var backgroundColors: ([HSBColor], Int32?, Int32?)? = nil { didSet { var updated = false if oldValue?.0 != self.backgroundColors?.0 || oldValue?.1 != self.backgroundColors?.1 { @@ -329,7 +329,7 @@ final class WallpaperPatternPanelNode: ASDisplayNode { node.removeFromSupernode() } - let backgroundColors = self.backgroundColors ?? ([0xd6e2ee], nil, nil) + let backgroundColors = self.backgroundColors.flatMap { ($0.0.map({ $0.rgb }), $0.1, $0.2) } ?? ([0xd6e2ee], nil, nil) let intensity: Int32 = backgroundColors.2.flatMap { value in if value < 0 { return -80