diff --git a/submodules/GradientBackground/Sources/SoftwareGradientBackground.swift b/submodules/GradientBackground/Sources/SoftwareGradientBackground.swift index 3e3c30b51e..3dbbe47175 100644 --- a/submodules/GradientBackground/Sources/SoftwareGradientBackground.swift +++ b/submodules/GradientBackground/Sources/SoftwareGradientBackground.swift @@ -156,7 +156,7 @@ public final class GradientBackgroundNode: ASDisplayNode { private var phase: Int = 0 - private let contentView: UIImageView + public let contentView: UIImageView private var validPhase: Int? private var invalidated: Bool = false diff --git a/submodules/LegacyMediaPickerUI/Sources/LegacyMediaPickers.swift b/submodules/LegacyMediaPickerUI/Sources/LegacyMediaPickers.swift index b1a92b8663..9860b34a9f 100644 --- a/submodules/LegacyMediaPickerUI/Sources/LegacyMediaPickers.swift +++ b/submodules/LegacyMediaPickerUI/Sources/LegacyMediaPickers.swift @@ -20,8 +20,6 @@ public func guessMimeTypeByFileExtension(_ ext: String) -> String { } public func configureLegacyAssetPicker(_ controller: TGMediaAssetsController, context: AccountContext, peer: Peer, chatLocation: ChatLocation, captionsEnabled: Bool = true, storeCreatedAssets: Bool = true, showFileTooltip: Bool = false, initialCaption: String, hasSchedule: Bool, presentWebSearch: (() -> Void)?, presentSelectionLimitExceeded: @escaping () -> Void, presentSchedulePicker: @escaping (@escaping (Int32) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, presentStickers: @escaping (@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?) { - let isSecretChat = peer.id.namespace == Namespaces.Peer.SecretChat - let paintStickersContext = LegacyPaintStickersContext(context: context) paintStickersContext.presentStickersController = { completion in return presentStickers({ file, animated, view, rect in diff --git a/submodules/SettingsUI/Sources/Themes/SettingsThemeWallpaperNode.swift b/submodules/SettingsUI/Sources/Themes/SettingsThemeWallpaperNode.swift index 2168936c9b..b0cdfedae7 100644 --- a/submodules/SettingsUI/Sources/Themes/SettingsThemeWallpaperNode.swift +++ b/submodules/SettingsUI/Sources/Themes/SettingsThemeWallpaperNode.swift @@ -75,10 +75,12 @@ final class SettingsThemeWallpaperNode: ASDisplayNode { self.imageNode.frame = CGRect(origin: CGPoint(), size: size) var colors: [UInt32] = [] + var intensity: CGFloat = 0.5 if case let .gradient(value, _) = wallpaper { colors = value } else if case let .file(file) = wallpaper { colors = file.settings.colors + intensity = CGFloat(file.settings.intensity ?? 50) / 100.0 } else if case let .color(color) = wallpaper { colors = [color] } @@ -93,7 +95,11 @@ final class SettingsThemeWallpaperNode: ASDisplayNode { self.insertSubnode(gradientNode, belowSubnode: self.imageNode) } - self.imageNode.layer.compositingFilter = "softLightBlendMode" + if intensity < 0.0 { + self.imageNode.layer.compositingFilter = nil + } else { + self.imageNode.layer.compositingFilter = "softLightBlendMode" + } self.backgroundNode.image = nil } else { if let gradientNode = self.gradientNode { @@ -101,13 +107,17 @@ final class SettingsThemeWallpaperNode: ASDisplayNode { gradientNode.removeFromSupernode() } - if colors.count >= 2 { + if intensity < 0.0 { + self.imageNode.layer.compositingFilter = nil + } else { self.imageNode.layer.compositingFilter = "softLightBlendMode" + } + + if colors.count >= 2 { self.backgroundNode.image = generateGradientImage(size: CGSize(width: 80.0, height: 80.0), colors: colors.map(UIColor.init(rgb:)), locations: [0.0, 1.0], direction: .vertical) self.backgroundNode.backgroundColor = nil } else if colors.count >= 1 { self.backgroundNode.image = nil - self.imageNode.layer.compositingFilter = "softLightBlendMode" self.backgroundNode.backgroundColor = UIColor(rgb: colors[0]) } } @@ -147,24 +157,20 @@ final class SettingsThemeWallpaperNode: ASDisplayNode { let imageSignal: Signal<(TransformImageArguments) -> DrawingContext?, NoError> if wallpaper.isPattern { - var patternColors: [UIColor] = [] - var patternColor = UIColor(rgb: 0xd6e2ee, alpha: 0.5) var patternIntensity: CGFloat = 0.5 if !file.settings.colors.isEmpty { if let intensity = file.settings.intensity { patternIntensity = CGFloat(intensity) / 100.0 } - patternColor = UIColor(rgb: file.settings.colors[0], alpha: patternIntensity) - patternColors.append(patternColor) - - if file.settings.colors.count >= 2 { - patternColors.append(UIColor(rgb: file.settings.colors[1], alpha: patternIntensity)) - } } - self.imageNode.alpha = CGFloat(file.settings.intensity ?? 50) / 100.0 - - self.arguments = PatternWallpaperArguments(colors: [.clear], rotation: nil, customPatternColor: UIColor(white: 0.0, alpha: 1.0)) + if patternIntensity < 0.0 { + self.imageNode.alpha = 1.0 + self.arguments = PatternWallpaperArguments(colors: [.black], rotation: nil, customPatternColor: UIColor(white: 0.0, alpha: 1.0 + patternIntensity)) + } else { + self.imageNode.alpha = CGFloat(file.settings.intensity ?? 50) / 100.0 + self.arguments = PatternWallpaperArguments(colors: [.clear], rotation: nil, customPatternColor: UIColor(white: 0.0, alpha: 1.0)) + } imageSignal = patternWallpaperImage(account: context.account, accountManager: context.sharedContext.accountManager, representations: convertedRepresentations, mode: .thumbnail, autoFetchFullSize: true) } else { self.imageNode.alpha = 1.0 diff --git a/submodules/SettingsUI/Sources/Themes/ThemeAccentColorControllerNode.swift b/submodules/SettingsUI/Sources/Themes/ThemeAccentColorControllerNode.swift index fca2934f44..3eaebd90cd 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemeAccentColorControllerNode.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemeAccentColorControllerNode.swift @@ -246,7 +246,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate self.messagesContainerNode = ASDisplayNode() self.messagesContainerNode.clipsToBounds = true - self.messagesContainerNode.transform = CATransform3DMakeScale(1.0, -1.0, 1.0) + self.messagesContainerNode.transform = CATransform3DMakeScale(-1.0, -1.0, 1.0) self.colorPanelNode = WallpaperColorPanelNode(theme: self.theme, strings: self.presentationData.strings) self.patternPanelNode = WallpaperPatternPanelNode(context: self.context, theme: self.theme, strings: self.presentationData.strings) @@ -400,12 +400,15 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate } } + self.backgroundNode.update(wallpaper: self.wallpaper) + self.backgroundNode.updateBubbleTheme(bubbleTheme: self.theme, bubbleCorners: self.presentationData.chatBubbleCorners) + self.stateDisposable = (self.statePromise.get() |> deliverOn(self.queue) |> mapToThrottled { next -> Signal in return .single(next) |> then(.complete() |> delay(0.0166667, queue: self.queue)) } - |> map { [weak self] state -> (PresentationTheme?, TelegramWallpaper, UIColor, [UInt32], PatternWallpaperArguments, Bool) in + |> map { state -> (PresentationTheme?, TelegramWallpaper, UIColor, [UInt32], PatternWallpaperArguments, Bool) in let accentColor = state.accentColor var backgroundColors = state.backgroundColors let messagesColors = state.messagesColors @@ -494,6 +497,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate strongSelf.serviceBackgroundColorPromise.set(.single(serviceBackgroundColor)) strongSelf.backgroundNode.update(wallpaper: wallpaper) + strongSelf.backgroundNode.updateBubbleTheme(bubbleTheme: strongSelf.theme, bubbleCorners: strongSelf.presentationData.chatBubbleCorners) strongSelf.ready.set(.single(true)) @@ -871,7 +875,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate itemNode = node apply().1(ListViewItemApply(isOnScreen: true)) }) - itemNode!.subnodeTransform = CATransform3DMakeScale(-1.0, 1.0, 1.0) + //itemNode!.subnodeTransform = CATransform3DMakeScale(-1.0, 1.0, 1.0) messageNodes.append(itemNode!) self.messagesContainerNode.addSubnode(itemNode!) } @@ -881,9 +885,13 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate var bottomOffset: CGFloat = 9.0 + bottomInset if let messageNodes = self.messageNodes { for itemNode in messageNodes { + let previousFrame = itemNode.frame transition.updateFrame(node: itemNode, frame: CGRect(origin: CGPoint(x: 0.0, y: bottomOffset), size: itemNode.frame.size)) bottomOffset += itemNode.frame.height itemNode.updateFrame(itemNode.frame, within: layout.size) + if case let .animated(duration, curve) = transition { + itemNode.applyAbsoluteOffset(value: CGPoint(x: 0.0, y: -itemNode.frame.minY + previousFrame.minY), animationCurve: curve, duration: duration) + } } } @@ -893,7 +901,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate headerItem.updateNode(dateHeaderNode, previous: nil, next: headerItem) } else { dateHeaderNode = headerItem.node() - dateHeaderNode.subnodeTransform = CATransform3DMakeScale(-1.0, 1.0, 1.0) + //dateHeaderNode.subnodeTransform = CATransform3DMakeScale(-1.0, 1.0, 1.0) self.messagesContainerNode.addSubnode(dateHeaderNode) self.dateHeaderNode = dateHeaderNode } @@ -954,7 +962,8 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate self.chatListBackgroundNode.frame = CGRect(x: bounds.width, y: 0.0, width: bounds.width, height: bounds.height) - transition.updateFrame(node: self.messagesContainerNode, frame: CGRect(x: 0.0, y: navigationBarHeight, width: bounds.width, height: bounds.height - bottomInset - navigationBarHeight)) + transition.updateBounds(node: self.messagesContainerNode, bounds: CGRect(x: 0.0, y: 0.0, width: bounds.width, height: bounds.height)) + transition.updatePosition(node: self.messagesContainerNode, position: CGRect(x: 0.0, y: 0.0, width: bounds.width, height: bounds.height).center) let backgroundSize = CGSize(width: bounds.width, height: bounds.height - (colorPanelHeight - colorPanelOffset)) transition.updateFrame(node: self.backgroundContainerNode, frame: CGRect(origin: CGPoint(), size: backgroundSize)) @@ -967,12 +976,12 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate transition.updateBounds(node: self.backgroundWrapperNode, bounds: CGRect(origin: CGPoint(), size: layout.size)) let displayOptionButtons = self.state.section == .background - var messagesBottomInset: CGFloat = 0.0 + var messagesBottomInset: CGFloat = bottomInset if displayOptionButtons { - messagesBottomInset = 46.0 + messagesBottomInset += 46.0 } else if chatListPreviewAvailable { - messagesBottomInset = 37.0 + messagesBottomInset += 37.0 } self.updateChatsLayout(layout: layout, topInset: navigationBarHeight, transition: transition) self.updateMessagesLayout(layout: layout, bottomInset: messagesBottomInset, transition: messagesTransition) diff --git a/submodules/SettingsUI/Sources/Themes/ThemeGridController.swift b/submodules/SettingsUI/Sources/Themes/ThemeGridController.swift index d94433119f..589c7b1e4d 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemeGridController.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemeGridController.swift @@ -375,7 +375,9 @@ final class ThemeGridController: ViewController { self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Done, style: .done, target: self, action: #selector(self.donePressed)) self.searchContentNode?.setIsEnabled(false, animated: true) self.controllerNode.updateState { state in - return state.withUpdatedEditing(true) + var state = state + state.editing = true + return state } } @@ -384,7 +386,9 @@ final class ThemeGridController: ViewController { self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Edit, style: .plain, target: self, action: #selector(self.editPressed)) self.searchContentNode?.setIsEnabled(true, animated: true) self.controllerNode.updateState { state in - return state.withUpdatedEditing(false) + var state = state + state.editing = false + return state } } } diff --git a/submodules/SettingsUI/Sources/Themes/ThemeGridControllerItem.swift b/submodules/SettingsUI/Sources/Themes/ThemeGridControllerItem.swift index 5f38860949..bd2b3e5622 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemeGridControllerItem.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemeGridControllerItem.swift @@ -12,6 +12,7 @@ import GridMessageSelectionNode final class ThemeGridControllerItem: GridItem { let context: AccountContext let wallpaper: TelegramWallpaper + let wallpaperId: ThemeGridControllerEntry.StableId let index: Int let editable: Bool let selected: Bool @@ -19,9 +20,10 @@ final class ThemeGridControllerItem: GridItem { let section: GridSection? = nil - init(context: AccountContext, wallpaper: TelegramWallpaper, index: Int, editable: Bool, selected: Bool, interaction: ThemeGridControllerInteraction) { + init(context: AccountContext, wallpaper: TelegramWallpaper, wallpaperId: ThemeGridControllerEntry.StableId, index: Int, editable: Bool, selected: Bool, interaction: ThemeGridControllerInteraction) { self.context = context self.wallpaper = wallpaper + self.wallpaperId = wallpaperId self.index = index self.editable = editable self.selected = selected @@ -30,7 +32,7 @@ final class ThemeGridControllerItem: GridItem { func node(layout: GridNodeLayout, synchronousLoad: Bool) -> GridItemNode { let node = ThemeGridControllerItemNode() - node.setup(context: self.context, wallpaper: self.wallpaper, editable: self.editable, selected: self.selected, interaction: self.interaction, synchronousLoad: synchronousLoad) + node.setup(item: self, synchronousLoad: synchronousLoad) return node } @@ -39,7 +41,7 @@ final class ThemeGridControllerItem: GridItem { assertionFailure() return } - node.setup(context: self.context, wallpaper: self.wallpaper, editable: self.editable, selected: self.selected, interaction: self.interaction, synchronousLoad: false) + node.setup(item: self, synchronousLoad: false) } } @@ -47,11 +49,11 @@ final class ThemeGridControllerItemNode: GridItemNode { private let wallpaperNode: SettingsThemeWallpaperNode private var selectionNode: GridMessageSelectionNode? - private var currentState: (AccountContext, TelegramWallpaper, Bool, Bool, Bool)? - private var interaction: ThemeGridControllerInteraction? + private var item: ThemeGridControllerItem? override init() { self.wallpaperNode = SettingsThemeWallpaperNode() + super.init() self.addSubnode(self.wallpaperNode) @@ -64,50 +66,35 @@ final class ThemeGridControllerItemNode: GridItemNode { self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:)))) } - func setup(context: AccountContext, wallpaper: TelegramWallpaper, editable: Bool, selected: Bool, interaction: ThemeGridControllerInteraction, synchronousLoad: Bool) { - self.interaction = interaction - - if self.currentState == nil || self.currentState!.0 !== context || wallpaper != self.currentState!.1 || selected != self.currentState!.2 || synchronousLoad != self.currentState!.3 || editable != self.currentState!.4 { - self.currentState = (context, wallpaper, selected, synchronousLoad, editable) - self.updateSelectionState(animated: false) - self.setNeedsLayout() - } + func setup(item: ThemeGridControllerItem, synchronousLoad: Bool) { + self.item = item + self.updateSelectionState(animated: false) + self.setNeedsLayout() } @objc func tapGesture(_ recognizer: UITapGestureRecognizer) { if case .ended = recognizer.state { - if let (_, wallpaper, _, _, _) = self.currentState { - self.interaction?.openWallpaper(wallpaper) + if let item = self.item { + item.interaction.openWallpaper(item.wallpaper) } } } func updateSelectionState(animated: Bool) { - if let (context, wallpaper, _, _, editable) = self.currentState { - var editing = false - var id: Int64? - if case let .file(file) = wallpaper { - id = file.id - } else if case .image = wallpaper { - id = 0 - } - var selectedIndices = Set() - if let interaction = self.interaction { - let (active, indices) = interaction.selectionState - editing = active - selectedIndices = indices - } - if let id = id, editing && editable { - let selected = selectedIndices.contains(id) + if let item = self.item { + let (editing, selectedIds) = item.interaction.selectionState + + if editing && item.editable { + let selected = selectedIds.contains(item.wallpaperId) if let selectionNode = self.selectionNode { selectionNode.updateSelected(selected, animated: animated) selectionNode.frame = CGRect(origin: CGPoint(), size: self.bounds.size) } else { - let theme = context.sharedContext.currentPresentationData.with { $0 }.theme + let theme = item.context.sharedContext.currentPresentationData.with { $0 }.theme let selectionNode = GridMessageSelectionNode(theme: theme, toggle: { [weak self] value in if let strongSelf = self { - strongSelf.interaction?.toggleWallpaperSelection(id, value) + strongSelf.item?.interaction.toggleWallpaperSelection(item.wallpaperId, value) } }) @@ -139,8 +126,8 @@ final class ThemeGridControllerItemNode: GridItemNode { super.layout() let bounds = self.bounds - if let (context, wallpaper, selected, synchronousLoad, _) = self.currentState { - self.wallpaperNode.setWallpaper(context: context, wallpaper: wallpaper, selected: selected, size: bounds.size, synchronousLoad: synchronousLoad) + if let item = self.item { + self.wallpaperNode.setWallpaper(context: item.context, wallpaper: item.wallpaper, selected: item.selected, size: bounds.size, synchronousLoad: false) self.selectionNode?.frame = CGRect(origin: CGPoint(), size: bounds.size) } } diff --git a/submodules/SettingsUI/Sources/Themes/ThemeGridControllerNode.swift b/submodules/SettingsUI/Sources/Themes/ThemeGridControllerNode.swift index 8100db63b7..e5ff9d366b 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemeGridControllerNode.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemeGridControllerNode.swift @@ -18,36 +18,18 @@ import SearchUI import WallpaperResources struct ThemeGridControllerNodeState: Equatable { - let editing: Bool - var selectedIndices: Set - - func withUpdatedEditing(_ editing: Bool) -> ThemeGridControllerNodeState { - return ThemeGridControllerNodeState(editing: editing, selectedIndices: editing ? self.selectedIndices : Set()) - } - - func withUpdatedSelectedIndices(_ selectedIndices: Set) -> ThemeGridControllerNodeState { - return ThemeGridControllerNodeState(editing: self.editing, selectedIndices: selectedIndices) - } - - static func ==(lhs: ThemeGridControllerNodeState, rhs: ThemeGridControllerNodeState) -> Bool { - if lhs.editing != rhs.editing { - return false - } - if lhs.selectedIndices != rhs.selectedIndices { - return false - } - return true - } + var editing: Bool + var selectedIds: Set } final class ThemeGridControllerInteraction { let openWallpaper: (TelegramWallpaper) -> Void - let toggleWallpaperSelection: (Int64, Bool) -> Void + let toggleWallpaperSelection: (ThemeGridControllerEntry.StableId, Bool) -> Void let deleteSelectedWallpapers: () -> Void let shareSelectedWallpapers: () -> Void - var selectionState: (Bool, Set) = (false, Set()) + var selectionState: (Bool, Set) = (false, Set()) - init(openWallpaper: @escaping (TelegramWallpaper) -> Void, toggleWallpaperSelection: @escaping (Int64, Bool) -> Void, deleteSelectedWallpapers: @escaping () -> Void, shareSelectedWallpapers: @escaping () -> Void) { + init(openWallpaper: @escaping (TelegramWallpaper) -> Void, toggleWallpaperSelection: @escaping (ThemeGridControllerEntry.StableId, Bool) -> Void, deleteSelectedWallpapers: @escaping () -> Void, shareSelectedWallpapers: @escaping () -> Void) { self.openWallpaper = openWallpaper self.toggleWallpaperSelection = toggleWallpaperSelection self.deleteSelectedWallpapers = deleteSelectedWallpapers @@ -55,7 +37,7 @@ final class ThemeGridControllerInteraction { } } -private struct ThemeGridControllerEntry: Comparable, Identifiable { +struct ThemeGridControllerEntry: Comparable, Identifiable { enum StableId: Hashable { case builtin case color(UInt32) @@ -64,14 +46,10 @@ private struct ThemeGridControllerEntry: Comparable, Identifiable { case image(String) } - let index: Int - let wallpaper: TelegramWallpaper - let isEditable: Bool - let isSelected: Bool - - static func ==(lhs: ThemeGridControllerEntry, rhs: ThemeGridControllerEntry) -> Bool { - return lhs.index == rhs.index && lhs.wallpaper == rhs.wallpaper && lhs.isEditable == rhs.isEditable && lhs.isSelected == rhs.isSelected - } + var index: Int + var wallpaper: TelegramWallpaper + var isEditable: Bool + var isSelected: Bool static func <(lhs: ThemeGridControllerEntry, rhs: ThemeGridControllerEntry) -> Bool { return lhs.index < rhs.index @@ -79,25 +57,25 @@ private struct ThemeGridControllerEntry: Comparable, Identifiable { var stableId: StableId { switch self.wallpaper { - case .builtin: - return .builtin - case let .color(color): - return .color(color) - case let .gradient(colors, _): - return .gradient(colors) - case let .file(id, _, _, _, _, _, _, _, settings): - return .file(id, settings.colors, settings.intensity ?? 0) - case let .image(representations, _): - if let largest = largestImageRepresentation(representations) { - return .image(largest.resource.id.uniqueId) - } else { - return .image("") - } + case .builtin: + return .builtin + case let .color(color): + return .color(color) + case let .gradient(colors, _): + return .gradient(colors) + case let .file(id, _, _, _, _, _, _, _, settings): + return .file(id, settings.colors, settings.intensity ?? 0) + case let .image(representations, _): + if let largest = largestImageRepresentation(representations) { + return .image(largest.resource.id.uniqueId) + } else { + return .image("") + } } } func item(context: AccountContext, interaction: ThemeGridControllerInteraction) -> ThemeGridControllerItem { - return ThemeGridControllerItem(context: context, wallpaper: self.wallpaper, index: self.index, editable: self.isEditable, selected: self.isSelected, interaction: interaction) + return ThemeGridControllerItem(context: context, wallpaper: self.wallpaper, wallpaperId: self.stableId, index: self.index, editable: self.isEditable, selected: self.isSelected, interaction: interaction) } } @@ -149,20 +127,19 @@ private func selectedWallpapers(entries: [ThemeGridControllerEntry]?, state: The } var wallpapers: [TelegramWallpaper] = [] for entry in entries { - if case let .file(file) = entry.wallpaper { - if state.selectedIndices.contains(file.id) { - wallpapers.append(entry.wallpaper) - } - } else if case .image = entry.wallpaper { - if state.selectedIndices.contains(0) { - wallpapers.append(entry.wallpaper) - } + if state.selectedIds.contains(entry.stableId) { + wallpapers.append(entry.wallpaper) } } return wallpapers } final class ThemeGridControllerNode: ASDisplayNode { + private struct Wallpaper: Equatable { + var wallpaper: TelegramWallpaper + var isLocal: Bool + } + private let context: AccountContext private var presentationData: PresentationData private var controllerInteraction: ThemeGridControllerInteraction? @@ -176,7 +153,7 @@ final class ThemeGridControllerNode: ASDisplayNode { var requestDeactivateSearch: (() -> Void)? let ready = ValuePromise() - let wallpapersPromise: Promise<[TelegramWallpaper]> + private let wallpapersPromise: Promise<[Wallpaper]> private var backgroundNode: ASDisplayNode private var separatorNode: ASDisplayNode @@ -196,7 +173,7 @@ final class ThemeGridControllerNode: ASDisplayNode { private var selectionPanel: ThemeGridSelectionPanelNode? private var selectionPanelSeparatorNode: ASDisplayNode? - private var selectionPanelBackgroundNode: ASDisplayNode? + private var selectionPanelBackgroundNode: NavigationBackgroundNode? let gridNode: GridNode private let leftOverlayNode: ASDisplayNode @@ -261,22 +238,12 @@ final class ThemeGridControllerNode: ASDisplayNode { self.resetDescriptionItemNode = ItemListTextItemNode() self.resetDescriptionItem = ItemListTextItem(presentationData: ItemListPresentationData(presentationData), text: .plain(presentationData.strings.Wallpaper_ResetWallpapersInfo), sectionId: 0) - self.currentState = ThemeGridControllerNodeState(editing: false, selectedIndices: Set()) + self.currentState = ThemeGridControllerNodeState(editing: false, selectedIds: Set()) self.statePromise = ValuePromise(self.currentState, ignoreRepeated: true) let defaultWallpaper = presentationData.theme.chat.defaultWallpaper - let wallpapersPromise = Promise<[TelegramWallpaper]>() - wallpapersPromise.set(telegramWallpapers(postbox: context.account.postbox, network: context.account.network) - |> map { wallpapers in - var wallpapers = wallpapers - if !wallpapers.contains(where: { - $0.isBasicallyEqual(to: defaultWallpaper) - }) { - wallpapers.insert(defaultWallpaper, at: 0) - } - return wallpapers - }) + let wallpapersPromise = Promise<[Wallpaper]>() self.wallpapersPromise = wallpapersPromise let deletedWallpaperSlugsValue = Atomic>(value: Set()) @@ -322,31 +289,47 @@ final class ThemeGridControllerNode: ASDisplayNode { } }, toggleWallpaperSelection: { [weak self] id, value in if let strongSelf = self { - strongSelf.updateState { current in - var updated = current.selectedIndices + strongSelf.updateState { state in + var state = state if value { - updated.insert(id) + state.selectedIds.insert(id) } else { - updated.remove(id) + state.selectedIds.remove(id) } - return current.withUpdatedSelectedIndices(updated) + return state } } }, deleteSelectedWallpapers: { [weak self] in let entries = previousEntries.with { $0 } if let strongSelf = self, let entries = entries { - deleteWallpapers(selectedWallpapers(entries: entries, state: strongSelf.currentState), { [weak self] in + let wallpapers = selectedWallpapers(entries: entries, state: strongSelf.currentState) + + deleteWallpapers(wallpapers, { [weak self] in if let strongSelf = self { var updatedDeletedSlugs = deletedWallpaperSlugsValue.with { $0 } for entry in entries { - if case let .file(file) = entry.wallpaper, strongSelf.currentState.selectedIndices.contains(file.id) { + if case let .file(file) = entry.wallpaper, strongSelf.currentState.selectedIds.contains(entry.stableId) { updatedDeletedSlugs.insert(file.slug) } } let _ = deletedWallpaperSlugsValue.swap(updatedDeletedSlugs) deletedWallpaperSlugsPromise.set(updatedDeletedSlugs) + + let _ = (strongSelf.context.sharedContext.accountManager.transaction { transaction in + WallpapersState.update(transaction: transaction, { state in + var state = state + for wallpaper in wallpapers { + if let index = state.wallpapers.firstIndex(where: { + $0.isBasicallyEqual(to: wallpaper) + }) { + state.wallpapers.remove(at: index) + } + } + return state + }) + }).start() } }) } @@ -358,7 +341,7 @@ final class ThemeGridControllerNode: ASDisplayNode { }) self.controllerInteraction = interaction - let transition = combineLatest(wallpapersPromise.get(), deletedWallpaperSlugsPromise.get(), context.sharedContext.presentationData) + let transition = combineLatest(self.wallpapersPromise.get(), deletedWallpaperSlugsPromise.get(), context.sharedContext.presentationData) |> map { wallpapers, deletedWallpaperSlugs, presentationData -> (ThemeGridEntryTransition, Bool) in var entries: [ThemeGridControllerEntry] = [] var index = 1 @@ -369,7 +352,7 @@ final class ThemeGridControllerNode: ASDisplayNode { } else if presentationData.chatWallpaper.isBasicallyEqual(to: presentationData.theme.chat.defaultWallpaper) { isSelectedEditable = false } - entries.insert(ThemeGridControllerEntry(index: 0, wallpaper: presentationData.chatWallpaper, isEditable: isSelectedEditable, isSelected: true), at: 0) + entries.insert(ThemeGridControllerEntry(index: 0, wallpaper: presentationData.chatWallpaper, isEditable: false, isSelected: true), at: 0) var defaultWallpaper: TelegramWallpaper? if !presentationData.chatWallpaper.isBasicallyEqual(to: presentationData.theme.chat.defaultWallpaper) { @@ -397,17 +380,22 @@ final class ThemeGridControllerNode: ASDisplayNode { var sortedWallpapers: [TelegramWallpaper] = [] if presentationData.theme.overallDarkAppearance { + var localWallpapers: [TelegramWallpaper] = [] var darkWallpapers: [TelegramWallpaper] = [] for wallpaper in wallpapers { - if case let .file(file) = wallpaper, file.isDark { - darkWallpapers.append(wallpaper) + if wallpaper.isLocal { + localWallpapers.append(wallpaper.wallpaper) } else { - sortedWallpapers.append(wallpaper) + if case let .file(file) = wallpaper.wallpaper, file.isDark { + darkWallpapers.append(wallpaper.wallpaper) + } else { + sortedWallpapers.append(wallpaper.wallpaper) + } } } - sortedWallpapers = darkWallpapers + sortedWallpapers + sortedWallpapers = localWallpapers + darkWallpapers + sortedWallpapers } else { - sortedWallpapers = wallpapers + sortedWallpapers = wallpapers.map(\.wallpaper) } for wallpaper in sortedWallpapers { @@ -423,6 +411,9 @@ final class ThemeGridControllerNode: ASDisplayNode { if case .builtin = wallpaper { isEditable = false } + if isDefault || presentationData.chatWallpaper.isBasicallyEqual(to: wallpaper) { + isEditable = false + } if !selected && !isDefault { let entry = ThemeGridControllerEntry(index: index, wallpaper: wallpaper, isEditable: isEditable, isSelected: false) if !entries.contains(where: { $0.stableId == entry.stableId }) { @@ -440,6 +431,8 @@ final class ThemeGridControllerNode: ASDisplayNode { strongSelf.enqueueTransition(transition) } }) + + self.updateWallpapers() } deinit { @@ -522,7 +515,31 @@ final class ThemeGridControllerNode: ASDisplayNode { } func updateWallpapers() { - self.wallpapersPromise.set(telegramWallpapers(postbox: self.context.account.postbox, network: self.context.account.network)) + self.wallpapersPromise.set(combineLatest(queue: .mainQueue(), + telegramWallpapers(postbox: self.context.account.postbox, network: self.context.account.network), + self.context.sharedContext.accountManager.sharedData(keys: [SharedDataKeys.wallapersState]) + ) + |> map { remoteWallpapers, sharedData -> [Wallpaper] in + let localState = (sharedData.entries[SharedDataKeys.wallapersState] as? WallpapersState) ?? WallpapersState.default + + var wallpapers: [Wallpaper] = [] + for wallpaper in localState.wallpapers { + if !wallpapers.contains(where: { + $0.wallpaper.isBasicallyEqual(to: wallpaper) + }) { + wallpapers.append(Wallpaper(wallpaper: wallpaper, isLocal: true)) + } + } + for wallpaper in remoteWallpapers { + if !wallpapers.contains(where: { + $0.wallpaper.isBasicallyEqual(to: wallpaper) + }) { + wallpapers.append(Wallpaper(wallpaper: wallpaper, isLocal: false)) + } + } + + return wallpapers + }) } func updatePresentationData(_ presentationData: PresentationData) { @@ -562,7 +579,7 @@ final class ThemeGridControllerNode: ASDisplayNode { self.statePromise.set(state) } - let selectionState = (self.currentState.editing, self.currentState.selectedIndices) + let selectionState = (self.currentState.editing, self.currentState.selectedIds) if let interaction = self.controllerInteraction, interaction.selectionState != selectionState { let requestLayout = interaction.selectionState.0 != self.currentState.editing self.controllerInteraction?.selectionState = selectionState @@ -576,7 +593,7 @@ final class ThemeGridControllerNode: ASDisplayNode { if requestLayout, let (containerLayout, navigationBarHeight) = self.validLayout { self.containerLayoutUpdated(containerLayout, navigationBarHeight: navigationBarHeight, transition: .animated(duration: 0.4, curve: .spring)) } - self.selectionPanel?.selectedIndices = selectionState.1 + self.selectionPanel?.selectedIds = selectionState.1 } } @@ -678,7 +695,7 @@ final class ThemeGridControllerNode: ASDisplayNode { if self.currentState.editing { let panelHeight: CGFloat if let selectionPanel = self.selectionPanel { - selectionPanel.selectedIndices = self.currentState.selectedIndices + selectionPanel.selectedIds = self.currentState.selectedIds panelHeight = selectionPanel.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, maxHeight: 0.0, transition: transition, metrics: layout.metrics) transition.updateFrame(node: selectionPanel, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - insets.bottom - panelHeight), size: CGSize(width: layout.size.width, height: panelHeight))) if let selectionPanelSeparatorNode = self.selectionPanelSeparatorNode { @@ -686,24 +703,21 @@ final class ThemeGridControllerNode: ASDisplayNode { } if let selectionPanelBackgroundNode = self.selectionPanelBackgroundNode { transition.updateFrame(node: selectionPanelBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - insets.bottom - panelHeight), size: CGSize(width: layout.size.width, height: insets.bottom + panelHeight))) + selectionPanelBackgroundNode.update(size: selectionPanelBackgroundNode.bounds.size, transition: transition) } } else { - let selectionPanelBackgroundNode = ASDisplayNode() - selectionPanelBackgroundNode.isLayerBacked = true - selectionPanelBackgroundNode.backgroundColor = self.presentationData.theme.chat.inputPanel.panelBackgroundColor + let selectionPanelBackgroundNode = NavigationBackgroundNode(color: self.presentationData.theme.rootController.navigationBar.blurredBackgroundColor) self.addSubnode(selectionPanelBackgroundNode) self.selectionPanelBackgroundNode = selectionPanelBackgroundNode let selectionPanel = ThemeGridSelectionPanelNode(theme: self.presentationData.theme) - selectionPanel.backgroundColor = self.presentationData.theme.chat.inputPanel.panelBackgroundColor selectionPanel.controllerInteraction = self.controllerInteraction - selectionPanel.selectedIndices = self.currentState.selectedIndices + selectionPanel.selectedIds = self.currentState.selectedIds panelHeight = selectionPanel.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, maxHeight: 0.0, transition: .immediate, metrics: layout.metrics) self.selectionPanel = selectionPanel self.addSubnode(selectionPanel) let selectionPanelSeparatorNode = ASDisplayNode() - selectionPanelSeparatorNode.isLayerBacked = true selectionPanelSeparatorNode.backgroundColor = self.presentationData.theme.chat.inputPanel.panelSeparatorColor self.addSubnode(selectionPanelSeparatorNode) self.selectionPanelSeparatorNode = selectionPanelSeparatorNode @@ -713,6 +727,7 @@ final class ThemeGridControllerNode: ASDisplayNode { selectionPanelSeparatorNode.frame = CGRect(origin: CGPoint(x: 0.0, y: layout.size.height), size: CGSize(width: layout.size.width, height: UIScreenPixel)) transition.updateFrame(node: selectionPanel, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - insets.bottom - panelHeight), size: CGSize(width: layout.size.width, height: panelHeight))) transition.updateFrame(node: selectionPanelBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - insets.bottom - panelHeight), size: CGSize(width: layout.size.width, height: insets.bottom + panelHeight))) + selectionPanelBackgroundNode.update(size: selectionPanelBackgroundNode.bounds.size, transition: .immediate) transition.updateFrame(node: selectionPanelSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - insets.bottom - panelHeight), size: CGSize(width: layout.size.width, height: UIScreenPixel))) } @@ -732,6 +747,7 @@ final class ThemeGridControllerNode: ASDisplayNode { transition.updateFrame(node: selectionPanelBackgroundNode, frame: selectionPanelBackgroundNode.frame.offsetBy(dx: 0.0, dy: selectionPanel.bounds.size.height + insets.bottom), completion: { [weak selectionPanelSeparatorNode] _ in selectionPanelSeparatorNode?.removeFromSupernode() }) + selectionPanelBackgroundNode.update(size: selectionPanelBackgroundNode.bounds.size, transition: transition) } } diff --git a/submodules/SettingsUI/Sources/Themes/ThemeGridSelectionPanelNode.swift b/submodules/SettingsUI/Sources/Themes/ThemeGridSelectionPanelNode.swift index 78a1c64556..0d7500fbf6 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemeGridSelectionPanelNode.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemeGridSelectionPanelNode.swift @@ -17,11 +17,11 @@ final class ThemeGridSelectionPanelNode: ASDisplayNode { private var theme: PresentationTheme - var selectedIndices = Set() { + var selectedIds = Set() { didSet { - if oldValue != self.selectedIndices { - self.deleteButton.isEnabled = !self.selectedIndices.isEmpty - self.shareButton.isEnabled = !self.selectedIndices.isEmpty + if oldValue != self.selectedIds { + self.deleteButton.isEnabled = !self.selectedIds.isEmpty + self.shareButton.isEnabled = !self.selectedIds.isEmpty } } } diff --git a/submodules/SettingsUI/Sources/Themes/WallpaperGalleryController.swift b/submodules/SettingsUI/Sources/Themes/WallpaperGalleryController.swift index 4ad112d787..01d1e28c4c 100644 --- a/submodules/SettingsUI/Sources/Themes/WallpaperGalleryController.swift +++ b/submodules/SettingsUI/Sources/Themes/WallpaperGalleryController.swift @@ -475,6 +475,18 @@ public class WallpaperGalleryController: ViewController { break } let _ = installWallpaper(account: strongSelf.context.account, wallpaper: wallpaper).start() + let _ = (strongSelf.context.sharedContext.accountManager.transaction { transaction in + WallpapersState.update(transaction: transaction, { state in + var state = state + if let index = state.wallpapers.firstIndex(where: { + $0.isBasicallyEqual(to: wallpaper) + }) { + state.wallpapers.remove(at: index) + } + state.wallpapers.insert(wallpaper, at: 0) + return state + }) + }).start() } let applyWallpaper: (TelegramWallpaper) -> Void = { wallpaper in @@ -808,9 +820,24 @@ public class WallpaperGalleryController: ViewController { let patternPanelNode = WallpaperPatternPanelNode(context: self.context, theme: presentationData.theme, strings: presentationData.strings) patternPanelNode.patternChanged = { [weak self] pattern, intensity, preview in if let strongSelf = self, strongSelf.validLayout != nil, let patternInitialWallpaper = strongSelf.patternInitialWallpaper { + var colors: [UInt32] = [] + switch patternInitialWallpaper { + case let .color(color): + colors = [color] + case let .file(file): + colors = file.settings.colors + case let .gradient(colorsValue, _): + colors = colorsValue + default: + break + } switch patternInitialWallpaper { case .color, .file, .gradient: - strongSelf.updateEntries(pattern: pattern, intensity: intensity, preview: preview) + if let pattern = pattern, case let .file(file) = pattern { + let newSettings = WallpaperSettings(blur: file.settings.blur, motion: file.settings.motion, colors: colors, intensity: intensity) + let newWallpaper = TelegramWallpaper.file(id: file.id, accessHash: file.accessHash, isCreator: file.isCreator, isDefault: file.isDefault, isPattern: pattern.isPattern, isDark: file.isDark, slug: file.slug, file: file.file, settings: newSettings) + strongSelf.updateEntries(wallpaper: newWallpaper, preview: preview) + } default: break } @@ -841,8 +868,8 @@ public class WallpaperGalleryController: ViewController { var wallpaper: TelegramWallpaper = .gradient(colors, WallpaperSettings(blur: false, motion: false, colors: [], intensity: nil, rotation: nil)) - if case .file = currentWallpaper { - wallpaper = currentWallpaper.withUpdatedSettings(WallpaperSettings(blur: false, motion: false, colors: 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)) } strongSelf.updateEntries(wallpaper: wallpaper) diff --git a/submodules/SettingsUI/Sources/Themes/WallpaperGalleryItem.swift b/submodules/SettingsUI/Sources/Themes/WallpaperGalleryItem.swift index 1f643fd4e9..47eddf6d74 100644 --- a/submodules/SettingsUI/Sources/Themes/WallpaperGalleryItem.swift +++ b/submodules/SettingsUI/Sources/Themes/WallpaperGalleryItem.swift @@ -336,7 +336,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode { case let .color(color): displaySize = CGSize(width: 1.0, height: 1.0) contentSize = displaySize - signal = solidColorImage(UIColor(rgb: color)) + signal = .single({ _ in nil }) fetchSignal = .complete() statusSignal = .single(.Local) subtitleSignal = .single(nil) @@ -346,11 +346,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode { case let .gradient(colors, settings): displaySize = CGSize(width: 1.0, height: 1.0) contentSize = displaySize - if colors.count >= 2 { - signal = gradientImage([UIColor(rgb: colors[0]), UIColor(rgb: colors[1])], rotation: settings.rotation) - } else { - signal = solidColorImage(UIColor(rgb: colors[0])) - } + signal = .single({ _ in nil }) fetchSignal = .complete() statusSignal = .single(.Local) subtitleSignal = .single(nil) @@ -389,7 +385,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode { self.backgroundColor = patternColor.withAlphaComponent(1.0) - if let previousEntry = previousEntry, case let .wallpaper(wallpaper, _) = previousEntry, case let .file(previousFile) = wallpaper, file.id == previousFile.id && (file.settings.colors != previousFile.settings.colors || file.settings.intensity != previousFile.settings.intensity) && self.colorPreview == self.arguments.colorPreview { + /*if let previousEntry = previousEntry, case let .wallpaper(wallpaper, _) = previousEntry, case let .file(previousFile) = wallpaper, file.id == previousFile.id && (file.settings.colors != previousFile.settings.colors || file.settings.intensity != previousFile.settings.intensity) && self.colorPreview == self.arguments.colorPreview { let makeImageLayout = self.imageNode.asyncLayout() Queue.concurrentDefaultQueue().async { @@ -405,15 +401,16 @@ final class WallpaperGalleryItemNode: GalleryItemNode { return } else { patternArguments = PatternWallpaperArguments(colors: patternColors, rotation: file.settings.rotation) - } + }*/ self.colorPreview = self.arguments.colorPreview - if file.settings.colors.count >= 3 { + signal = .single({ _ in nil }) + /*if file.settings.colors.count >= 3 { signal = .single({ _ in nil }) } else { signal = patternWallpaperImage(account: self.context.account, accountManager: self.context.sharedContext.accountManager, representations: convertedRepresentations, mode: .screen, autoFetchFullSize: true) - } + }*/ colorSignal = chatServiceBackgroundColor(wallpaper: wallpaper, mediaBox: self.context.account.postbox.mediaBox) isBlurrable = false diff --git a/submodules/SettingsUI/Sources/Themes/WallpaperPatternPanelNode.swift b/submodules/SettingsUI/Sources/Themes/WallpaperPatternPanelNode.swift index bd7c071a3d..6536649a55 100644 --- a/submodules/SettingsUI/Sources/Themes/WallpaperPatternPanelNode.swift +++ b/submodules/SettingsUI/Sources/Themes/WallpaperPatternPanelNode.swift @@ -263,8 +263,8 @@ final class WallpaperPatternPanelNode: ASDisplayNode { sliderView.lineSize = 2.0 sliderView.minimumValue = 0.0 sliderView.startValue = 0.0 - sliderView.maximumValue = 100.0 - sliderView.value = 40.0 + sliderView.maximumValue = 200.0 + sliderView.value = 150.0 sliderView.disablesInteractiveTransitionGestureRecognizer = true sliderView.backgroundColor = .clear sliderView.backColor = self.theme.list.disclosureArrowColor @@ -312,7 +312,7 @@ final class WallpaperPatternPanelNode: ASDisplayNode { if let strongSelf = self { strongSelf.currentWallpaper = updatedWallpaper if let sliderView = strongSelf.sliderView { - strongSelf.patternChanged?(updatedWallpaper, Int32(sliderView.value), false) + strongSelf.patternChanged?(updatedWallpaper, Int32(sliderView.value - 100.0), false) } if let subnodes = strongSelf.scrollNode.subnodes { for case let subnode as SettingsThemeWallpaperNode in subnodes { @@ -354,7 +354,7 @@ final class WallpaperPatternPanelNode: ASDisplayNode { } if let wallpaper = self.currentWallpaper { - self.patternChanged?(wallpaper, Int32(sliderView.value), sliderView.isTracking) + self.patternChanged?(wallpaper, Int32(sliderView.value - 100.0), sliderView.isTracking) } } @@ -368,7 +368,7 @@ final class WallpaperPatternPanelNode: ASDisplayNode { } self.currentWallpaper = wallpaper - self.sliderView?.value = CGFloat(intensity ?? 50) + self.sliderView?.value = CGFloat(intensity.flatMap { $0 + 100 } ?? 150) self.scrollNode.view.contentOffset = CGPoint() @@ -385,7 +385,7 @@ final class WallpaperPatternPanelNode: ASDisplayNode { } if initialWallpaper == nil, let wallpaper = self.currentWallpaper, let sliderView = self.sliderView { - self.patternChanged?(wallpaper, Int32(sliderView.value), false) + self.patternChanged?(wallpaper, Int32(sliderView.value - 100.0), false) } if let selectedNode = selectedNode { diff --git a/submodules/SyncCore/Sources/Namespaces.swift b/submodules/SyncCore/Sources/Namespaces.swift index d7bf972845..61cde874e7 100644 --- a/submodules/SyncCore/Sources/Namespaces.swift +++ b/submodules/SyncCore/Sources/Namespaces.swift @@ -349,6 +349,7 @@ private enum SharedDataKeyValues: Int32 { case autodownloadSettings = 5 case themeSettings = 6 case countriesList = 7 + case wallapersState = 8 } public struct SharedDataKeys { @@ -393,6 +394,12 @@ public struct SharedDataKeys { key.setInt32(0, value: SharedDataKeyValues.countriesList.rawValue) return key }() + + public static let wallapersState: ValueBoxKey = { + let key = ValueBoxKey(length: 4) + key.setInt32(0, value: SharedDataKeyValues.wallapersState.rawValue) + return key + }() } public func applicationSpecificItemCacheCollectionId(_ value: Int8) -> Int8 { diff --git a/submodules/SyncCore/Sources/wallapersState.swift b/submodules/SyncCore/Sources/wallapersState.swift new file mode 100644 index 0000000000..b3117097fa --- /dev/null +++ b/submodules/SyncCore/Sources/wallapersState.swift @@ -0,0 +1,35 @@ +import Postbox +import SwiftSignalKit + +public struct WallpapersState: PreferencesEntry, Equatable { + public var wallpapers: [TelegramWallpaper] + + public static var `default`: WallpapersState { + return WallpapersState(wallpapers: []) + } + + public init(wallpapers: [TelegramWallpaper]) { + self.wallpapers = wallpapers + } + + public init(decoder: PostboxDecoder) { + self.wallpapers = decoder.decodeObjectArrayWithDecoderForKey("wallpapers") + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeObjectArray(self.wallpapers, forKey: "wallpapers") + } + + public func isEqual(to: PreferencesEntry) -> Bool { + return self == (to as? WallpapersState) + } +} + +public extension WallpapersState { + static func update(transaction: AccountManagerModifier, _ f: (WallpapersState) -> WallpapersState) { + transaction.updateSharedData(SharedDataKeys.wallapersState, { current in + let item = (transaction.getSharedData(SharedDataKeys.wallapersState) as? WallpapersState) ?? WallpapersState(wallpapers: []) + return f(item) + }) + } +} diff --git a/submodules/TelegramCore/Sources/AccountManager.swift b/submodules/TelegramCore/Sources/AccountManager.swift index 69ed985493..d4b987894b 100644 --- a/submodules/TelegramCore/Sources/AccountManager.swift +++ b/submodules/TelegramCore/Sources/AccountManager.swift @@ -174,6 +174,7 @@ private var declaredEncodables: Void = { declareEncodable(CachedPeerExportedInvitations.self, f: { CachedPeerExportedInvitations(decoder: $0) }) declareEncodable(ExportedInvitation.self, f: { ExportedInvitation(decoder: $0) }) declareEncodable(CachedDisplayAsPeers.self, f: { CachedDisplayAsPeers(decoder: $0) }) + declareEncodable(WallpapersState.self, f: { WallpapersState(decoder: $0) }) return }() diff --git a/submodules/TelegramPresentationData/Sources/PresentationThemeEssentialGraphics.swift b/submodules/TelegramPresentationData/Sources/PresentationThemeEssentialGraphics.swift index 78a554dfaf..3a26a65157 100644 --- a/submodules/TelegramPresentationData/Sources/PresentationThemeEssentialGraphics.swift +++ b/submodules/TelegramPresentationData/Sources/PresentationThemeEssentialGraphics.swift @@ -246,7 +246,7 @@ public final class PrincipalThemeEssentialGraphics { let emptyImage = UIImage() if preview { - self.chatMessageBackgroundIncomingMaskImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: UIColor.black, strokeColor: UIColor.clear, neighbors: .none, theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true) + self.chatMessageBackgroundIncomingMaskImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: .black, strokeColor: .clear, neighbors: .none, theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true) self.chatMessageBackgroundIncomingExtractedMaskImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: UIColor.black, strokeColor: UIColor.clear, neighbors: .extracted, theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true) self.chatMessageBackgroundIncomingImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .none, theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true) self.chatMessageBackgroundIncomingExtractedImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .extracted, theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true) @@ -263,30 +263,33 @@ public final class PrincipalThemeEssentialGraphics { self.checkBubbleFullImage = generateCheckImage(partial: false, color: theme.message.outgoingCheckColor, width: 11.0)! self.checkBubblePartialImage = generateCheckImage(partial: true, color: theme.message.outgoingCheckColor, width: 11.0)! self.chatMessageBackgroundIncomingHighlightedImage = emptyImage - self.chatMessageBackgroundIncomingMergedTopMaskImage = emptyImage + self.chatMessageBackgroundIncomingMergedTopMaskImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: .black, strokeColor: .clear, neighbors: .top(side: false), theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true) self.chatMessageBackgroundIncomingMergedTopImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .top(side: false), theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true) self.chatMessageBackgroundIncomingMergedTopOutlineImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .top(side: false), theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true, onlyOutline: true) self.chatMessageBackgroundIncomingMergedTopShadowImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .top(side: false), theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true, onlyShadow: true) self.chatMessageBackgroundIncomingMergedTopHighlightedImage = emptyImage - self.chatMessageBackgroundIncomingMergedTopSideMaskImage = emptyImage - self.chatMessageBackgroundIncomingMergedTopSideImage = emptyImage - self.chatMessageBackgroundIncomingMergedTopSideOutlineImage = emptyImage - self.chatMessageBackgroundIncomingMergedTopSideShadowImage = emptyImage + self.chatMessageBackgroundIncomingMergedTopSideMaskImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: .black, strokeColor: .clear, neighbors: .top(side: true), theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true) + self.chatMessageBackgroundIncomingMergedTopSideImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .top(side: true), theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true) + self.chatMessageBackgroundIncomingMergedTopSideOutlineImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .top(side: true), theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true, onlyOutline: true) + self.chatMessageBackgroundIncomingMergedTopSideShadowImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .top(side: true), theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true, onlyShadow: true) self.chatMessageBackgroundIncomingMergedTopSideHighlightedImage = emptyImage - self.chatMessageBackgroundIncomingMergedBottomMaskImage = emptyImage + self.chatMessageBackgroundIncomingMergedBottomMaskImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: .black, strokeColor: .clear, neighbors: .bottom, theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true) self.chatMessageBackgroundIncomingMergedBottomImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .bottom, theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true) self.chatMessageBackgroundIncomingMergedBottomOutlineImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .bottom, theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true, onlyOutline: true) self.chatMessageBackgroundIncomingMergedBottomShadowImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .bottom, theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true, onlyShadow: true) self.chatMessageBackgroundIncomingMergedBottomHighlightedImage = emptyImage - self.chatMessageBackgroundIncomingMergedBothMaskImage = emptyImage - self.chatMessageBackgroundIncomingMergedBothImage = emptyImage - self.chatMessageBackgroundIncomingMergedBothOutlineImage = emptyImage - self.chatMessageBackgroundIncomingMergedBothShadowImage = emptyImage + self.chatMessageBackgroundIncomingMergedBothMaskImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: .black, strokeColor: .clear, neighbors: .both, theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true) + + self.chatMessageBackgroundIncomingMergedBothImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .both, theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true) + self.chatMessageBackgroundIncomingMergedBothOutlineImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .both, theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true, onlyOutline: true) + self.chatMessageBackgroundIncomingMergedBothShadowImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .both, theme: theme, wallpaper: wallpaper, knockout: incomingKnockout, extendedEdges: true, onlyShadow: true) self.chatMessageBackgroundIncomingMergedBothHighlightedImage = emptyImage - self.chatMessageBackgroundIncomingMergedSideMaskImage = emptyImage - self.chatMessageBackgroundIncomingMergedSideImage = emptyImage - self.chatMessageBackgroundIncomingMergedSideOutlineImage = emptyImage - self.chatMessageBackgroundIncomingMergedSideShadowImage = emptyImage + self.chatMessageBackgroundIncomingMergedSideMaskImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: .black, strokeColor: .clear, neighbors: .side, theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true) + self.chatMessageBackgroundIncomingMergedSideImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .side, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true) + + self.chatMessageBackgroundIncomingMergedSideOutlineImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .side, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true, onlyOutline: true) + self.chatMessageBackgroundIncomingMergedSideShadowImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: true, fillColor: incoming.fill, strokeColor: incoming.stroke, neighbors: .side, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true, onlyShadow: true) + self.chatMessageBackgroundOutgoingMergedSideMaskImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: .black, strokeColor: .clear, neighbors: .side, theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true) self.chatMessageBackgroundIncomingMergedSideHighlightedImage = emptyImage self.chatMessageBackgroundOutgoingHighlightedImage = emptyImage self.chatMessageBackgroundOutgoingMergedTopMaskImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: .black, strokeColor: .clear, neighbors: .top(side: false), theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true) @@ -294,10 +297,10 @@ public final class PrincipalThemeEssentialGraphics { self.chatMessageBackgroundOutgoingMergedTopOutlineImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .top(side: false), theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true, onlyOutline: true) self.chatMessageBackgroundOutgoingMergedTopShadowImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .top(side: false), theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true, onlyShadow: true) self.chatMessageBackgroundOutgoingMergedTopHighlightedImage = emptyImage - self.chatMessageBackgroundOutgoingMergedTopSideMaskImage = emptyImage - self.chatMessageBackgroundOutgoingMergedTopSideImage = emptyImage - self.chatMessageBackgroundOutgoingMergedTopSideOutlineImage = emptyImage - self.chatMessageBackgroundOutgoingMergedTopSideShadowImage = emptyImage + self.chatMessageBackgroundOutgoingMergedTopSideMaskImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: .black, strokeColor: .clear, neighbors: .top(side: true), theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true) + self.chatMessageBackgroundOutgoingMergedTopSideImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .top(side: true), theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true) + self.chatMessageBackgroundOutgoingMergedTopSideOutlineImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .top(side: true), theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true, onlyOutline: true) + self.chatMessageBackgroundOutgoingMergedTopSideShadowImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .top(side: true), theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true, onlyShadow: true) self.chatMessageBackgroundOutgoingMergedTopSideHighlightedImage = emptyImage self.chatMessageBackgroundOutgoingMergedBottomMaskImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: .black, strokeColor: .clear, neighbors: .bottom, theme: theme, wallpaper: .color(0xffffff), knockout: true, mask: true, extendedEdges: true) self.chatMessageBackgroundOutgoingMergedBottomImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .bottom, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true) @@ -309,10 +312,9 @@ public final class PrincipalThemeEssentialGraphics { self.chatMessageBackgroundOutgoingMergedBothOutlineImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .both, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true, onlyOutline: true) self.chatMessageBackgroundOutgoingMergedBothShadowImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .both, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true, onlyShadow: true) self.chatMessageBackgroundOutgoingMergedBothHighlightedImage = emptyImage - self.chatMessageBackgroundOutgoingMergedSideMaskImage = emptyImage - self.chatMessageBackgroundOutgoingMergedSideImage = emptyImage - self.chatMessageBackgroundOutgoingMergedSideOutlineImage = emptyImage - self.chatMessageBackgroundOutgoingMergedSideShadowImage = emptyImage + self.chatMessageBackgroundOutgoingMergedSideImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .side, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true) + self.chatMessageBackgroundOutgoingMergedSideOutlineImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .side, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true, onlyOutline: true) + self.chatMessageBackgroundOutgoingMergedSideShadowImage = messageBubbleImage(maxCornerRadius: maxCornerRadius, minCornerRadius: minCornerRadius, incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .side, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout, extendedEdges: true, onlyShadow: true) self.chatMessageBackgroundOutgoingMergedSideHighlightedImage = emptyImage self.checkMediaFullImage = emptyImage self.checkMediaPartialImage = emptyImage diff --git a/submodules/TelegramUI/Sources/ChatMessageBubbleBackdrop.swift b/submodules/TelegramUI/Sources/ChatMessageBubbleBackdrop.swift index a5760aa555..fb5b2a3923 100644 --- a/submodules/TelegramUI/Sources/ChatMessageBubbleBackdrop.swift +++ b/submodules/TelegramUI/Sources/ChatMessageBubbleBackdrop.swift @@ -64,8 +64,9 @@ final class ChatMessageBubbleBackdrop: ASDisplayNode { private weak var backgroundNode: WallpaperBackgroundNode? private var maskView: UIImageView? - private var fixedMaskMode: Bool? + + private var absolutePosition: (CGRect, CGSize)? var hasImage: Bool { return self.backgroundContent != nil @@ -145,12 +146,18 @@ final class ChatMessageBubbleBackdrop: ASDisplayNode { case .incoming: if let backgroundContent = backgroundNode?.makeBubbleBackground(for: .incoming) { backgroundContent.frame = self.bounds + if let (rect, containerSize) = self.absolutePosition { + backgroundContent.update(rect: rect, within: containerSize) + } self.backgroundContent = backgroundContent self.insertSubnode(backgroundContent, at: 0) } case .outgoing: if let backgroundContent = backgroundNode?.makeBubbleBackground(for: .outgoing) { backgroundContent.frame = self.bounds + if let (rect, containerSize) = self.absolutePosition { + backgroundContent.update(rect: rect, within: containerSize) + } self.backgroundContent = backgroundContent self.insertSubnode(backgroundContent, at: 0) } @@ -164,18 +171,15 @@ final class ChatMessageBubbleBackdrop: ASDisplayNode { } func update(rect: CGRect, within containerSize: CGSize) { - //self.backgroundContent.frame = CGRect(origin: CGPoint(x: -rect.minX, y: -rect.minY), size: containerSize) + self.absolutePosition = (rect, containerSize) self.backgroundContent?.update(rect: rect, within: containerSize) } func offset(value: CGPoint, animationCurve: ContainedViewLayoutTransitionCurve, duration: Double) { - //let transition: ContainedViewLayoutTransition = .animated(duration: duration, curve: animationCurve) - //transition.animatePositionAdditive(node: self.backgroundContent, offset: CGPoint(x: -value.x, y: -value.y)) self.backgroundContent?.offset(value: value, animationCurve: animationCurve, duration: duration) } func offsetSpring(value: CGFloat, duration: Double, damping: CGFloat) { - //self.backgroundContent.layer.animateSpring(from: NSValue(cgPoint: CGPoint(x: 0.0, y: value)), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: duration, initialVelocity: 0.0, damping: damping, additive: true) self.backgroundContent?.offsetSpring(value: value, duration: duration, damping: damping) } diff --git a/submodules/WallpaperBackgroundNode/Sources/WallpaperBackgroundNode.swift b/submodules/WallpaperBackgroundNode/Sources/WallpaperBackgroundNode.swift index a245616ccc..fccdbe94e0 100644 --- a/submodules/WallpaperBackgroundNode/Sources/WallpaperBackgroundNode.swift +++ b/submodules/WallpaperBackgroundNode/Sources/WallpaperBackgroundNode.swift @@ -28,6 +28,8 @@ public final class WallpaperBackgroundNode: ASDisplayNode { private weak var backgroundNode: WallpaperBackgroundNode? private var index: SparseBag.Index? + private var currentLayout: (rect: CGRect, containerSize: CGSize)? + init(backgroundNode: WallpaperBackgroundNode, bubbleType: BubbleType) { self.backgroundNode = backgroundNode self.bubbleType = bubbleType @@ -135,9 +137,15 @@ public final class WallpaperBackgroundNode: ASDisplayNode { cleanWallpaperNode.removeFromSupernode() } } + + if let (rect, containerSize) = self.currentLayout { + self.update(rect: rect, within: containerSize) + } } public func update(rect: CGRect, within containerSize: CGSize) { + self.currentLayout = (rect, containerSize) + self.contentNode.frame = CGRect(origin: CGPoint(x: -rect.minX, y: -rect.minY), size: containerSize) if let cleanWallpaperNode = self.cleanWallpaperNode { cleanWallpaperNode.frame = CGRect(origin: CGPoint(x: -rect.minX, y: -rect.minY), size: containerSize) @@ -183,6 +191,7 @@ public final class WallpaperBackgroundNode: ASDisplayNode { private let contentNode: ASDisplayNode private var gradientBackgroundNode: GradientBackgroundNode? private let patternImageNode: TransformImageNode + private var invertPattern: Bool = false private var validLayout: CGSize? private var wallpaper: TelegramWallpaper? @@ -255,7 +264,6 @@ public final class WallpaperBackgroundNode: ASDisplayNode { self.contentNode.contentMode = self.imageContentMode self.patternImageNode = TransformImageNode() - self.patternImageNode.layer.compositingFilter = "softLightBlendMode" super.init() @@ -369,10 +377,31 @@ public final class WallpaperBackgroundNode: ASDisplayNode { let signal = patternWallpaperImage(account: self.context.account, accountManager: self.context.sharedContext.accountManager, representations: convertedRepresentations, mode: .screen, autoFetchFullSize: true) self.patternImageNode.setSignal(signal) } - self.patternImageNode.alpha = CGFloat(settings.intensity ?? 50) / 100.0 + let intensity = CGFloat(settings.intensity ?? 50) / 100.0 + if intensity < 0 { + self.patternImageNode.alpha = 1.0 + self.patternImageNode.layer.compositingFilter = nil + } else { + self.patternImageNode.alpha = intensity + self.patternImageNode.layer.compositingFilter = "softLightBlendMode" + } self.patternImageNode.isHidden = false + self.invertPattern = intensity < 0 + if self.invertPattern { + self.backgroundColor = .black + let contentAlpha = abs(intensity) + self.gradientBackgroundNode?.contentView.alpha = contentAlpha + self.contentNode.alpha = contentAlpha + } else { + self.backgroundColor = nil + self.gradientBackgroundNode?.contentView.alpha = 1.0 + self.contentNode.alpha = 1.0 + } default: self.patternImageNode.isHidden = true + self.backgroundColor = nil + self.gradientBackgroundNode?.contentView.alpha = 1.0 + self.contentNode.alpha = 1.0 } self.updateBubbles() @@ -395,7 +424,16 @@ public final class WallpaperBackgroundNode: ASDisplayNode { } let makeImageLayout = self.patternImageNode.asyncLayout() - let applyImage = makeImageLayout(TransformImageArguments(corners: ImageCorners(), imageSize: size, boundingSize: size, intrinsicInsets: UIEdgeInsets(), custom: PatternWallpaperArguments(colors: [.clear], rotation: nil, customPatternColor: .black, preview: false))) + let patternBackgroundColor: UIColor + let patternColor: UIColor + if self.invertPattern { + patternColor = .clear + patternBackgroundColor = .black + } else { + patternColor = .black + patternBackgroundColor = .clear + } + let applyImage = makeImageLayout(TransformImageArguments(corners: ImageCorners(), imageSize: size, boundingSize: size, intrinsicInsets: UIEdgeInsets(), custom: PatternWallpaperArguments(colors: [patternBackgroundColor], rotation: nil, customPatternColor: patternColor, preview: false))) applyImage() transition.updateFrame(node: self.patternImageNode, frame: CGRect(origin: CGPoint(), size: size)) diff --git a/submodules/WallpaperResources/Sources/WallpaperResources.swift b/submodules/WallpaperResources/Sources/WallpaperResources.swift index 143fc34be6..05e56f29e2 100644 --- a/submodules/WallpaperResources/Sources/WallpaperResources.swift +++ b/submodules/WallpaperResources/Sources/WallpaperResources.swift @@ -314,6 +314,9 @@ public struct PatternWallpaperArguments: TransformImageCustomArguments { let array = NSMutableArray() array.addObjects(from: self.colors) array.add(NSNumber(value: self.rotation ?? 0)) + if let customPatternColor = customPatternColor { + array.add(NSNumber(value: customPatternColor.argb)) + } array.add(NSNumber(value: self.preview)) return array } @@ -500,7 +503,11 @@ public func patternWallpaperImageInternal(thumbnailData: Data?, fullSizeData: Da c.interpolationQuality = customArguments.preview ? .low : .medium c.clip(to: fittedRect, mask: image) - c.setBlendMode(.normal) + if let customPatternColor = customArguments.customPatternColor, customPatternColor.alpha < 1.0 { + c.setBlendMode(.copy) + } else { + c.setBlendMode(.normal) + } if colors.count >= 3 && customArguments.customPatternColor == nil { c.setBlendMode(.softLight)