Theme updates

This commit is contained in:
Ali 2021-05-31 01:23:08 +04:00
parent 648f2e50c2
commit 6428ae2754
18 changed files with 348 additions and 210 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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<ThemeColorState, NoError> 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)

View File

@ -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
}
}
}

View File

@ -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<Int64>()
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)
}
}

View File

@ -18,36 +18,18 @@ import SearchUI
import WallpaperResources
struct ThemeGridControllerNodeState: Equatable {
let editing: Bool
var selectedIndices: Set<Int64>
func withUpdatedEditing(_ editing: Bool) -> ThemeGridControllerNodeState {
return ThemeGridControllerNodeState(editing: editing, selectedIndices: editing ? self.selectedIndices : Set())
}
func withUpdatedSelectedIndices(_ selectedIndices: Set<Int64>) -> 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<ThemeGridControllerEntry.StableId>
}
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<Int64>) = (false, Set())
var selectionState: (Bool, Set<ThemeGridControllerEntry.StableId>) = (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<Bool>()
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<Set<String>>(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)
}
}

View File

@ -17,11 +17,11 @@ final class ThemeGridSelectionPanelNode: ASDisplayNode {
private var theme: PresentationTheme
var selectedIndices = Set<Int64>() {
var selectedIds = Set<ThemeGridControllerEntry.StableId>() {
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
}
}
}

View File

@ -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)

View File

@ -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

View File

@ -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 {

View File

@ -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 {

View File

@ -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)
})
}
}

View File

@ -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
}()

View File

@ -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

View File

@ -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)
}

View File

@ -28,6 +28,8 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
private weak var backgroundNode: WallpaperBackgroundNode?
private var index: SparseBag<BubbleBackgroundNode>.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))

View File

@ -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)