Chat wallpaper improvements

This commit is contained in:
Ilya Laktyushin 2023-04-05 16:07:16 +04:00
parent b3ed634db7
commit 05a3fa5bad
27 changed files with 283 additions and 119 deletions

View File

@ -255,6 +255,8 @@
"PUSH_MESSAGE_SUGGEST_USERPIC" = "%1$@|suggested you new profile photo"; "PUSH_MESSAGE_SUGGEST_USERPIC" = "%1$@|suggested you new profile photo";
"PUSH_MESSAGE_WALLPAPER" = "%1$@ set a new background for the chat with you";
"PUSH_MESSAGE_SAME_WALLPAPER" = "%1$@ set the same background for the chat with you";
"PUSH_REMINDER_TITLE" = "🗓 Reminder"; "PUSH_REMINDER_TITLE" = "🗓 Reminder";
"PUSH_SENDER_YOU" = "📅 You"; "PUSH_SENDER_YOU" = "📅 You";

View File

@ -3349,7 +3349,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
if let currentMutedIconImage = currentMutedIconImage { if let currentMutedIconImage = currentMutedIconImage {
strongSelf.mutedIconNode.image = currentMutedIconImage strongSelf.mutedIconNode.image = currentMutedIconImage
strongSelf.mutedIconNode.isHidden = false strongSelf.mutedIconNode.isHidden = false
transition.updateFrame(node: strongSelf.mutedIconNode, frame: CGRect(origin: CGPoint(x: nextTitleIconOrigin - 5.0, y: titleFrame.maxY - currentMutedIconImage.size.height + 0.0 + UIScreenPixel), size: currentMutedIconImage.size)) transition.updateFrame(node: strongSelf.mutedIconNode, frame: CGRect(origin: CGPoint(x: nextTitleIconOrigin - 5.0, y: floorToScreenPixels(titleFrame.midY - currentMutedIconImage.size.height / 2.0)), size: currentMutedIconImage.size))
nextTitleIconOrigin += currentMutedIconImage.size.width + 1.0 nextTitleIconOrigin += currentMutedIconImage.size.width + 1.0
} else { } else {
strongSelf.mutedIconNode.image = nil strongSelf.mutedIconNode.image = nil

View File

@ -225,7 +225,7 @@ open class ViewControllerComponentContainer: ViewController {
|> deliverOnMainQueue).start(next: { [weak self] presentationData in |> deliverOnMainQueue).start(next: { [weak self] presentationData in
if let strongSelf = self { if let strongSelf = self {
var theme = presentationData.theme var theme = presentationData.theme
if case .modal = presentationMode, theme.list.blocksBackgroundColor.rgb == theme.list.plainBackgroundColor.rgb { if case .modal = presentationMode {
theme = theme.withModalBlocksBackground() theme = theme.withModalBlocksBackground()
} }

View File

@ -870,10 +870,9 @@ public func createPollController(context: AccountContext, updatedPresentationDat
) )
|> map { presentationData, state, limitsConfiguration -> (ItemListControllerState, (ItemListNodeState, Any)) in |> map { presentationData, state, limitsConfiguration -> (ItemListControllerState, (ItemListNodeState, Any)) in
var presentationData = presentationData var presentationData = presentationData
if presentationData.theme.list.blocksBackgroundColor.rgb == presentationData.theme.list.plainBackgroundColor.rgb {
let updatedTheme = presentationData.theme.withModalBlocksBackground() let updatedTheme = presentationData.theme.withModalBlocksBackground()
presentationData = presentationData.withUpdated(theme: updatedTheme) presentationData = presentationData.withUpdated(theme: updatedTheme)
}
var enabled = true var enabled = true
if processPollText(state.text).isEmpty { if processPollText(state.text).isEmpty {

View File

@ -114,7 +114,7 @@ final class ContactsControllerNode: ASDisplayNode {
strongSelf.presentationData = presentationData strongSelf.presentationData = presentationData
if previousStrings !== presentationData.strings { if previousStrings.baseLanguageCode != presentationData.strings.baseLanguageCode {
strongSelf.stringsPromise.set(.single(presentationData.strings)) strongSelf.stringsPromise.set(.single(presentationData.strings))
} }

View File

@ -80,7 +80,7 @@ UIImage *TGPaintCombineCroppedImages(UIImage *background, UIImage *foreground, b
CGFloat pRatio = foreground.size.width / originalSize.width; CGFloat pRatio = foreground.size.width / originalSize.width;
CGSize rotatedContentSize = TGRotatedContentSize(foreground.size, cropRotation); CGSize rotatedContentSize = TGRotatedContentSize(foreground.size, cropRotation);
UIGraphicsBeginImageContextWithOptions(background.size, opaque, 0.0); UIGraphicsBeginImageContextWithOptions(background.size, opaque, 1.0);
CGContextRef context = UIGraphicsGetCurrentContext(); CGContextRef context = UIGraphicsGetCurrentContext();
CGRect backgroundRect = CGRectMake(0, 0, background.size.width, background.size.height); CGRect backgroundRect = CGRectMake(0, 0, background.size.width, background.size.height);

View File

@ -1317,7 +1317,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
self.navigationItem.titleView = self.titleView self.navigationItem.titleView = self.titleView
if case let .assets(_, isStandalone) = self.subject, isStandalone { if case let .assets(_, isStandalone) = self.subject, isStandalone {
self.navigationItem.leftBarButtonItem = UIBarButtonItem(backButtonAppearanceWithTitle: self.presentationData.strings.Common_Back, target: self, action: #selector(self.backPressed)) self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Cancel, style: .plain, target: self, action: #selector(self.cancelPressed))
} else { } else {
if case let .assets(collection, _) = self.subject, collection != nil { if case let .assets(collection, _) = self.subject, collection != nil {
self.navigationItem.leftBarButtonItem = UIBarButtonItem(backButtonAppearanceWithTitle: self.presentationData.strings.Common_Back, target: self, action: #selector(self.backPressed)) self.navigationItem.leftBarButtonItem = UIBarButtonItem(backButtonAppearanceWithTitle: self.presentationData.strings.Common_Back, target: self, action: #selector(self.backPressed))

View File

@ -1063,6 +1063,10 @@ public func deviceContactInfoController(context: AccountContext, updatedPresenta
let previousEditingPhoneIds = Atomic<Set<Int64>?>(value: nil) let previousEditingPhoneIds = Atomic<Set<Int64>?>(value: nil)
let signal = combineLatest(presentationData, statePromise.get(), contactData, hiddenAvatarPromise.get()) let signal = combineLatest(presentationData, statePromise.get(), contactData, hiddenAvatarPromise.get())
|> map { presentationData, state, peerAndContactData, hiddenAvatar -> (ItemListControllerState, (ItemListNodeState, Any)) in |> map { presentationData, state, peerAndContactData, hiddenAvatar -> (ItemListControllerState, (ItemListNodeState, Any)) in
var presentationData = presentationData
let updatedTheme = presentationData.theme.withModalBlocksBackground()
presentationData = presentationData.withUpdated(theme: updatedTheme)
var leftNavigationButton: ItemListNavigationButton? var leftNavigationButton: ItemListNavigationButton?
switch subject { switch subject {
case .vcard: case .vcard:

View File

@ -196,7 +196,7 @@ func uploadCustomWallpaper(context: AccountContext, wallpaper: WallpaperGalleryE
}).start() }).start()
} }
func uploadCustomPeerWallpaper(context: AccountContext, wallpaper: WallpaperGalleryEntry, mode: WallpaperPresentationOptions, cropRect: CGRect?, peerId: PeerId, completion: @escaping () -> Void) { public func uploadCustomPeerWallpaper(context: AccountContext, wallpaper: WallpaperGalleryEntry, mode: WallpaperPresentationOptions, cropRect: CGRect?, peerId: PeerId, completion: @escaping () -> Void) {
let imageSignal: Signal<UIImage, NoError> let imageSignal: Signal<UIImage, NoError>
switch wallpaper { switch wallpaper {
case let .wallpaper(wallpaper, _): case let .wallpaper(wallpaper, _):
@ -276,7 +276,7 @@ func uploadCustomPeerWallpaper(context: AccountContext, wallpaper: WallpaperGall
croppedImage = TGPhotoEditorCrop(image, nil, .up, 0.0, finalCropRect, false, CGSize(width: 1440.0, height: 2960.0), image.size, true) croppedImage = TGPhotoEditorCrop(image, nil, .up, 0.0, finalCropRect, false, CGSize(width: 1440.0, height: 2960.0), image.size, true)
if mode.contains(.blur) { if mode.contains(.blur) {
croppedImage = blurredImage(croppedImage, radius: 45.0)! croppedImage = blurredImage(croppedImage, radius: 30.0)!
} }
let thumbnailDimensions = finalCropRect.size.fitted(CGSize(width: 320.0, height: 320.0)) let thumbnailDimensions = finalCropRect.size.fitted(CGSize(width: 320.0, height: 320.0))

View File

@ -37,6 +37,7 @@ enum ThemeAccentColorControllerMode {
final class ThemeAccentColorController: ViewController { final class ThemeAccentColorController: ViewController {
private let context: AccountContext private let context: AccountContext
private let mode: ThemeAccentColorControllerMode private let mode: ThemeAccentColorControllerMode
private let forChat: Bool
private let section: ThemeColorSection private let section: ThemeColorSection
private let initialBackgroundColor: UIColor? private let initialBackgroundColor: UIColor?
private var presentationData: PresentationData private var presentationData: PresentationData
@ -57,9 +58,10 @@ final class ThemeAccentColorController: ViewController {
var completion: (() -> Void)? var completion: (() -> Void)?
init(context: AccountContext, mode: ThemeAccentColorControllerMode) { init(context: AccountContext, mode: ThemeAccentColorControllerMode, forChat: Bool = false) {
self.context = context self.context = context
self.mode = mode self.mode = mode
self.forChat = forChat
self.presentationData = context.sharedContext.currentPresentationData.with { $0 } self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
let section: ThemeColorSection = .background let section: ThemeColorSection = .background
@ -143,7 +145,7 @@ final class ThemeAccentColorController: ViewController {
initialWallpaper = self.presentationData.chatWallpaper initialWallpaper = self.presentationData.chatWallpaper
} }
self.displayNode = ThemeAccentColorControllerNode(context: self.context, mode: self.mode, theme: theme, wallpaper: initialWallpaper, dismiss: { [weak self] in self.displayNode = ThemeAccentColorControllerNode(context: self.context, mode: self.mode, forChat: self.forChat, theme: theme, wallpaper: initialWallpaper, dismiss: { [weak self] in
if let strongSelf = self { if let strongSelf = self {
strongSelf.dismiss() strongSelf.dismiss()
} }

View File

@ -224,7 +224,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
} }
} }
init(context: AccountContext, mode: ThemeAccentColorControllerMode, theme: PresentationTheme, wallpaper: TelegramWallpaper, dismiss: @escaping () -> Void, apply: @escaping (ThemeColorState, UIColor?) -> Void, ready: Promise<Bool>) { init(context: AccountContext, mode: ThemeAccentColorControllerMode, forChat: Bool, theme: PresentationTheme, wallpaper: TelegramWallpaper, dismiss: @escaping () -> Void, apply: @escaping (ThemeColorState, UIColor?) -> Void, ready: Promise<Bool>) {
self.context = context self.context = context
self.mode = mode self.mode = mode
self.state = ThemeColorState() self.state = ThemeColorState()
@ -306,9 +306,10 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
if case .edit(_, _, _, _, _, true, _) = self.mode { if case .edit(_, _, _, _, _, true, _) = self.mode {
doneButtonType = .proceed doneButtonType = .proceed
} else { } else {
doneButtonType = .set doneButtonType = forChat ? .setPeer : .set
} }
self.toolbarNode = WallpaperGalleryToolbarNode(theme: self.theme, strings: self.presentationData.strings, doneButtonType: doneButtonType) self.toolbarNode = WallpaperGalleryToolbarNode(theme: self.theme, strings: self.presentationData.strings, doneButtonType: doneButtonType)
self.toolbarNode.setDoneIsSolid(true, transition: .immediate)
self.maskNode = ASImageNode() self.maskNode = ASImageNode()
self.maskNode.displaysAsynchronously = false self.maskNode.displaysAsynchronously = false

View File

@ -102,17 +102,18 @@ private func availableColors(theme: PresentationTheme) -> [UInt32] {
} }
} }
final class ThemeColorsGridController: ViewController { public final class ThemeColorsGridController: ViewController {
private var controllerNode: ThemeColorsGridControllerNode { private var controllerNode: ThemeColorsGridControllerNode {
return self.displayNode as! ThemeColorsGridControllerNode return self.displayNode as! ThemeColorsGridControllerNode
} }
private let _ready = Promise<Bool>() private let _ready = Promise<Bool>()
override var ready: Promise<Bool> { public override var ready: Promise<Bool> {
return self._ready return self._ready
} }
private let context: AccountContext private let context: AccountContext
private let peerId: PeerId?
private var presentationData: PresentationData private var presentationData: PresentationData
private var presentationDataDisposable: Disposable? private var presentationDataDisposable: Disposable?
@ -121,8 +122,9 @@ final class ThemeColorsGridController: ViewController {
private var previousContentOffset: GridNodeVisibleContentOffset? private var previousContentOffset: GridNodeVisibleContentOffset?
init(context: AccountContext) { public init(context: AccountContext, peerId: PeerId? = nil) {
self.context = context self.context = context
self.peerId = peerId
self.presentationData = context.sharedContext.currentPresentationData.with { $0 } self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData)) super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData))
@ -169,9 +171,9 @@ final class ThemeColorsGridController: ViewController {
} }
} }
override func loadDisplayNode() { public override func loadDisplayNode() {
self.displayNode = ThemeColorsGridControllerNode(context: self.context, presentationData: self.presentationData, gradients: availableGradients(theme: self.presentationData.theme), colors: availableColors(theme: self.presentationData.theme), present: { [weak self] controller, arguments in self.displayNode = ThemeColorsGridControllerNode(context: self.context, presentationData: self.presentationData, peerId: self.peerId, gradients: availableGradients(theme: self.presentationData.theme), colors: availableColors(theme: self.presentationData.theme), push: { [weak self] controller in
self?.present(controller, in: .window(.root), with: arguments, blockInteraction: true) self?.push(controller)
}, pop: { [weak self] in }, pop: { [weak self] in
if let strongSelf = self, let navigationController = strongSelf.navigationController as? NavigationController { if let strongSelf = self, let navigationController = strongSelf.navigationController as? NavigationController {
let _ = navigationController.popViewController(animated: true) let _ = navigationController.popViewController(animated: true)
@ -194,7 +196,7 @@ final class ThemeColorsGridController: ViewController {
themeReference = settings.theme themeReference = settings.theme
} }
let controller = ThemeAccentColorController(context: strongSelf.context, mode: .background(themeReference: themeReference)) let controller = ThemeAccentColorController(context: strongSelf.context, mode: .background(themeReference: themeReference), forChat: strongSelf.peerId != nil)
controller.completion = { [weak self] in controller.completion = { [weak self] in
if let strongSelf = self, let navigationController = strongSelf.navigationController as? NavigationController { if let strongSelf = self, let navigationController = strongSelf.navigationController as? NavigationController {
var controllers = navigationController.viewControllers var controllers = navigationController.viewControllers
@ -249,7 +251,7 @@ final class ThemeColorsGridController: ViewController {
self.displayNodeDidLoad() self.displayNodeDidLoad()
} }
override func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { public override func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
super.containerLayoutUpdated(layout, transition: transition) super.containerLayoutUpdated(layout, transition: transition)
self.controllerNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationLayout(layout: layout).navigationFrame.maxY, transition: transition) self.controllerNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationLayout(layout: layout).navigationFrame.maxY, transition: transition)

View File

@ -66,8 +66,9 @@ private func preparedThemeColorsGridEntryTransition(context: AccountContext, fro
final class ThemeColorsGridControllerNode: ASDisplayNode { final class ThemeColorsGridControllerNode: ASDisplayNode {
private let context: AccountContext private let context: AccountContext
private var presentationData: PresentationData private var presentationData: PresentationData
private let peerId: PeerId?
private var controllerInteraction: ThemeColorsGridControllerInteraction? private var controllerInteraction: ThemeColorsGridControllerInteraction?
private let present: (ViewController, Any?) -> Void private let push: (ViewController) -> Void
private let presentColorPicker: () -> Void private let presentColorPicker: () -> Void
let ready = ValuePromise<Bool>() let ready = ValuePromise<Bool>()
@ -87,10 +88,11 @@ final class ThemeColorsGridControllerNode: ASDisplayNode {
private var disposable: Disposable? private var disposable: Disposable?
init(context: AccountContext, presentationData: PresentationData, gradients: [[UInt32]], colors: [UInt32], present: @escaping (ViewController, Any?) -> Void, pop: @escaping () -> Void, presentColorPicker: @escaping () -> Void) { init(context: AccountContext, presentationData: PresentationData, peerId: PeerId?, gradients: [[UInt32]], colors: [UInt32], push: @escaping (ViewController) -> Void, pop: @escaping () -> Void, presentColorPicker: @escaping () -> Void) {
self.context = context self.context = context
self.peerId = peerId
self.presentationData = presentationData self.presentationData = presentationData
self.present = present self.push = push
self.presentColorPicker = presentColorPicker self.presentColorPicker = presentColorPicker
self.gridNode = GridNode() self.gridNode = GridNode()
@ -131,11 +133,12 @@ final class ThemeColorsGridControllerNode: ASDisplayNode {
let entries = previousEntries.with { $0 } let entries = previousEntries.with { $0 }
if let entries = entries, !entries.isEmpty { if let entries = entries, !entries.isEmpty {
let wallpapers = entries.map { $0.wallpaper } let wallpapers = entries.map { $0.wallpaper }
let controller = WallpaperGalleryController(context: context, source: .list(wallpapers: wallpapers, central: wallpaper, type: .colors)) let controller = WallpaperGalleryController(context: context, source: .list(wallpapers: wallpapers, central: wallpaper, type: .colors), mode: strongSelf.peerId.flatMap { .peer($0) } ?? .default)
controller.apply = { _, _, _ in controller.navigationPresentation = .modal
controller.apply = { _, _, _ in
pop() pop()
} }
strongSelf.present(controller, nil) strongSelf.push(controller)
} }
} }
}) })

View File

@ -115,7 +115,7 @@ public final class ThemeGridController: ViewController {
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil) self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil)
if let isEmpty = self.isEmpty, isEmpty { if let isEmpty = self.isEmpty, isEmpty {
} else { } else if case .default = mode {
if self.editingMode { if self.editingMode {
self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Done, style: .done, target: self, action: #selector(self.donePressed)) self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Done, style: .done, target: self, action: #selector(self.donePressed))
} else { } else {
@ -215,7 +215,7 @@ public final class ThemeGridController: ViewController {
if empty { if empty {
strongSelf.navigationItem.setRightBarButton(nil, animated: true) strongSelf.navigationItem.setRightBarButton(nil, animated: true)
} else { } else if case .default = strongSelf.mode {
if strongSelf.editingMode { if strongSelf.editingMode {
strongSelf.navigationItem.rightBarButtonItem = UIBarButtonItem(title: strongSelf.presentationData.strings.Common_Done, style: .done, target: strongSelf, action: #selector(strongSelf.donePressed)) strongSelf.navigationItem.rightBarButtonItem = UIBarButtonItem(title: strongSelf.presentationData.strings.Common_Done, style: .done, target: strongSelf, action: #selector(strongSelf.donePressed))
} else { } else {

View File

@ -263,8 +263,10 @@ final class ThemeGridControllerNode: ASDisplayNode {
self.gridNode.addSubnode(self.colorItemNode) self.gridNode.addSubnode(self.colorItemNode)
self.gridNode.addSubnode(self.galleryItemNode) self.gridNode.addSubnode(self.galleryItemNode)
self.gridNode.addSubnode(self.descriptionItemNode) self.gridNode.addSubnode(self.descriptionItemNode)
self.gridNode.addSubnode(self.resetItemNode) if case .default = self.mode {
self.gridNode.addSubnode(self.resetDescriptionItemNode) self.gridNode.addSubnode(self.resetItemNode)
self.gridNode.addSubnode(self.resetDescriptionItemNode)
}
self.addSubnode(self.gridNode) self.addSubnode(self.gridNode)
let previousEntries = Atomic<[ThemeGridControllerEntry]?>(value: nil) let previousEntries = Atomic<[ThemeGridControllerEntry]?>(value: nil)
@ -348,10 +350,11 @@ final class ThemeGridControllerNode: ASDisplayNode {
let transition = combineLatest(self.wallpapersPromise.get(), deletedWallpaperIdsPromise.get(), context.sharedContext.presentationData) let transition = combineLatest(self.wallpapersPromise.get(), deletedWallpaperIdsPromise.get(), context.sharedContext.presentationData)
|> map { wallpapers, deletedWallpaperIds, presentationData -> (ThemeGridEntryTransition, Bool) in |> map { wallpapers, deletedWallpaperIds, presentationData -> (ThemeGridEntryTransition, Bool) in
var entries: [ThemeGridControllerEntry] = [] var entries: [ThemeGridControllerEntry] = []
var index = 1 var index: Int = 0
if selectFirst { if selectFirst {
entries.insert(ThemeGridControllerEntry(index: 0, wallpaper: presentationData.chatWallpaper, isEditable: false, isSelected: true), at: 0) entries.insert(ThemeGridControllerEntry(index: 0, wallpaper: presentationData.chatWallpaper, isEditable: false, isSelected: true), at: 0)
index += 1
} }
var defaultWallpaper: TelegramWallpaper? var defaultWallpaper: TelegramWallpaper?
@ -422,10 +425,6 @@ final class ThemeGridControllerNode: ASDisplayNode {
} }
} }
/*if !entries.isEmpty {
entries = [entries[0]]
}*/
let previous = previousEntries.swap(entries) let previous = previousEntries.swap(entries)
return (preparedThemeGridEntryTransition(context: context, from: previous ?? [], to: entries, interaction: interaction), previous == nil) return (preparedThemeGridEntryTransition(context: context, from: previous ?? [], to: entries, interaction: interaction), previous == nil)
} }
@ -757,7 +756,9 @@ final class ThemeGridControllerNode: ASDisplayNode {
let makeResetDescriptionLayout = self.resetDescriptionItemNode.asyncLayout() let makeResetDescriptionLayout = self.resetDescriptionItemNode.asyncLayout()
let (resetDescriptionLayout, _) = makeResetDescriptionLayout(self.resetDescriptionItem, params, ItemListNeighbors(top: .none, bottom: .none)) let (resetDescriptionLayout, _) = makeResetDescriptionLayout(self.resetDescriptionItem, params, ItemListNeighbors(top: .none, bottom: .none))
insets.bottom += buttonHeight + 35.0 + resetDescriptionLayout.contentSize.height + 32.0 if case .default = self.mode {
insets.bottom += buttonHeight + 35.0 + resetDescriptionLayout.contentSize.height + 32.0
}
self.gridNode.frame = CGRect(x: 0.0, y: 0.0, width: layout.size.width, height: layout.size.height) self.gridNode.frame = CGRect(x: 0.0, y: 0.0, width: layout.size.width, height: layout.size.height)
self.gridNode.transaction(GridNodeTransaction(deleteItems: [], insertItems: [], updateItems: [], scrollToItem: nil, updateLayout: GridNodeUpdateLayout(layout: GridNodeLayout(size: layout.size, insets: insets, scrollIndicatorInsets: scrollIndicatorInsets, preloadSize: 300.0, type: .fixed(itemSize: imageSize, fillWidth: nil, lineSpacing: spacing, itemSpacing: nil)), transition: transition), itemTransition: .immediate, stationaryItems: .none, updateFirstIndexInSectionOffset: nil), completion: { _ in }) self.gridNode.transaction(GridNodeTransaction(deleteItems: [], insertItems: [], updateItems: [], scrollToItem: nil, updateLayout: GridNodeUpdateLayout(layout: GridNodeLayout(size: layout.size, insets: insets, scrollIndicatorInsets: scrollIndicatorInsets, preloadSize: 300.0, type: .fixed(itemSize: imageSize, fillWidth: nil, lineSpacing: spacing, itemSpacing: nil)), transition: transition), itemTransition: .immediate, stationaryItems: .none, updateFirstIndexInSectionOffset: nil), completion: { _ in })

View File

@ -457,7 +457,6 @@ public class WallpaperGalleryController: ViewController {
return return
} }
switch entry { switch entry {
case let .wallpaper(wallpaper, _): case let .wallpaper(wallpaper, _):
var resource: MediaResource? var resource: MediaResource?

View File

@ -111,7 +111,7 @@ func telegramMediaActionFromApiAction(_ action: Api.MessageAction) -> TelegramMe
case let .messageActionSetChatWallPaper(wallpaper): case let .messageActionSetChatWallPaper(wallpaper):
return TelegramMediaAction(action: .setChatWallpaper(wallpaper: TelegramWallpaper(apiWallpaper: wallpaper))) return TelegramMediaAction(action: .setChatWallpaper(wallpaper: TelegramWallpaper(apiWallpaper: wallpaper)))
case .messageActionSetSameChatWallPaper: case .messageActionSetSameChatWallPaper:
return nil return TelegramMediaAction(action: .setSameChatWallpaper)
} }
} }

View File

@ -141,7 +141,8 @@ func _internal_setChatWallpaper(account: Account, peerId: PeerId, wallpaper: Tel
inputSettings = inputWallpaperAndInputSettings.1 inputSettings = inputWallpaperAndInputSettings.1
} }
return account.network.request(Api.functions.messages.setChatWallPaper(flags: 0, peer: inputPeer, wallpaper: inputWallpaper ?? .inputWallPaperNoFile(id: 0), settings: inputSettings ?? apiWallpaperSettings(WallpaperSettings()), id: nil)) let flags: Int32 = 1 << 0
return account.network.request(Api.functions.messages.setChatWallPaper(flags: flags, peer: inputPeer, wallpaper: inputWallpaper ?? .inputWallPaperNoFile(id: 0), settings: inputSettings ?? apiWallpaperSettings(WallpaperSettings()), id: nil))
|> `catch` { error in |> `catch` { error in
return .complete() return .complete()
} }
@ -159,7 +160,20 @@ public enum SetExistingChatWallpaperError {
func _internal_setExistingChatWallpaper(account: Account, messageId: MessageId) -> Signal<Void, SetExistingChatWallpaperError> { func _internal_setExistingChatWallpaper(account: Account, messageId: MessageId) -> Signal<Void, SetExistingChatWallpaperError> {
return account.postbox.transaction { transaction -> Peer? in return account.postbox.transaction { transaction -> Peer? in
return transaction.getPeer(messageId.peerId) if let peer = transaction.getPeer(messageId.peerId), let message = transaction.getMessage(messageId) {
if let action = message.media.first(where: { $0 is TelegramMediaAction }) as? TelegramMediaAction, case let .setChatWallpaper(wallpaper) = action.action {
transaction.updatePeerCachedData(peerIds: Set([peer.id]), update: { _, current in
if let current = current as? CachedUserData {
return current.withUpdatedWallpaper(wallpaper)
} else {
return current
}
})
}
return peer
} else {
return nil
}
} }
|> castError(SetExistingChatWallpaperError.self) |> castError(SetExistingChatWallpaperError.self)
|> mapToSignal { peer -> Signal<Void, SetExistingChatWallpaperError> in |> mapToSignal { peer -> Signal<Void, SetExistingChatWallpaperError> in

View File

@ -1603,7 +1603,11 @@ public final class PresentationTheme: Equatable {
} }
public func withModalBlocksBackground() -> PresentationTheme { public func withModalBlocksBackground() -> PresentationTheme {
let list = self.list.withUpdated(blocksBackgroundColor: self.list.modalBlocksBackgroundColor, itemBlocksBackgroundColor: self.list.itemModalBlocksBackgroundColor) if self.list.blocksBackgroundColor.rgb == self.list.plainBackgroundColor.rgb {
return PresentationTheme(name: self.name, index: self.index, referenceTheme: self.referenceTheme, overallDarkAppearance: self.overallDarkAppearance, intro: self.intro, passcode: self.passcode, rootController: self.rootController, list: list, chatList: self.chatList, chat: self.chat, actionSheet: self.actionSheet, contextMenu: self.contextMenu, inAppNotification: self.inAppNotification, chart: self.chart, preview: self.preview) let list = self.list.withUpdated(blocksBackgroundColor: self.list.modalBlocksBackgroundColor, itemBlocksBackgroundColor: self.list.itemModalBlocksBackgroundColor)
return PresentationTheme(name: self.name, index: self.index, referenceTheme: self.referenceTheme, overallDarkAppearance: self.overallDarkAppearance, intro: self.intro, passcode: self.passcode, rootController: self.rootController, list: list, chatList: self.chatList, chat: self.chat, actionSheet: self.actionSheet, contextMenu: self.contextMenu, inAppNotification: self.inAppNotification, chart: self.chart, preview: self.preview)
} else {
return self
}
} }
} }

View File

@ -1029,25 +1029,52 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
} }
|> distinctUntilChanged |> distinctUntilChanged
let resultSignal = signal let resultSignal = combineLatest(
|> mapToSignal { keywords -> Signal<[EmojiPagerContentComponent.ItemGroup], NoError> in signal,
hasPremium
)
|> mapToSignal { keywords, hasPremium -> Signal<[EmojiPagerContentComponent.ItemGroup], NoError> in
var allEmoticons: [String: String] = [:] var allEmoticons: [String: String] = [:]
for keyword in keywords { for keyword in keywords {
for emoticon in keyword.emoticons { for emoticon in keyword.emoticons {
allEmoticons[emoticon] = keyword.keyword allEmoticons[emoticon] = keyword.keyword
} }
} }
let remoteSignal: Signal<(items: [TelegramMediaFile], isFinalResult: Bool), NoError>
return combineLatest( if hasPremium {
hasPremium, remoteSignal = context.engine.stickers.searchEmoji(emojiString: Array(allEmoticons.keys))
context.engine.stickers.searchEmoji(emojiString: Array(allEmoticons.keys)) } else {
) remoteSignal = .single(([], true))
|> mapToSignal { hasPremium, foundEmoji -> Signal<[EmojiPagerContentComponent.ItemGroup], NoError> in }
return remoteSignal
|> mapToSignal { foundEmoji -> Signal<[EmojiPagerContentComponent.ItemGroup], NoError> in
if foundEmoji.items.isEmpty && !foundEmoji.isFinalResult { if foundEmoji.items.isEmpty && !foundEmoji.isFinalResult {
return .complete() return .complete()
} }
var items: [EmojiPagerContentComponent.Item] = [] var items: [EmojiPagerContentComponent.Item] = []
let appendUnicodeEmoji = {
for (_, list) in EmojiPagerContentComponent.staticEmojiMapping {
for emojiString in list {
if allEmoticons[emojiString] != nil {
let item = EmojiPagerContentComponent.Item(
animationData: nil,
content: .staticEmoji(emojiString),
itemFile: nil,
subgroupId: nil,
icon: .none,
tintMode: .none
)
items.append(item)
}
}
}
}
if !hasPremium {
appendUnicodeEmoji()
}
var existingIds = Set<MediaId>() var existingIds = Set<MediaId>()
for itemFile in foundEmoji.items { for itemFile in foundEmoji.items {
if existingIds.contains(itemFile.fileId) { if existingIds.contains(itemFile.fileId) {
@ -1061,12 +1088,17 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
let item = EmojiPagerContentComponent.Item( let item = EmojiPagerContentComponent.Item(
animationData: animationData, animationData: animationData,
content: .animation(animationData), content: .animation(animationData),
itemFile: itemFile, subgroupId: nil, itemFile: itemFile,
subgroupId: nil,
icon: .none, icon: .none,
tintMode: animationData.isTemplate ? .primary : .none tintMode: animationData.isTemplate ? .primary : .none
) )
items.append(item) items.append(item)
} }
if hasPremium {
appendUnicodeEmoji()
}
return .single([EmojiPagerContentComponent.ItemGroup( return .single([EmojiPagerContentComponent.ItemGroup(
supergroupId: "search", supergroupId: "search",

View File

@ -29,26 +29,6 @@ private let premiumBadgeIcon: UIImage? = generateTintedImage(image: UIImage(bund
private let featuredBadgeIcon: UIImage? = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Media/PanelBadgeAdd"), color: .white) private let featuredBadgeIcon: UIImage? = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Media/PanelBadgeAdd"), color: .white)
private let lockedBadgeIcon: UIImage? = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Media/PanelBadgeLock"), color: .white) private let lockedBadgeIcon: UIImage? = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Media/PanelBadgeLock"), color: .white)
private let staticEmojiMapping: [(EmojiPagerContentComponent.StaticEmojiSegment, [String])] = {
guard let path = getAppBundle().path(forResource: "emoji1016", ofType: "txt") else {
return []
}
guard let string = try? String(contentsOf: URL(fileURLWithPath: path)) else {
return []
}
var result: [(EmojiPagerContentComponent.StaticEmojiSegment, [String])] = []
let orderedSegments = EmojiPagerContentComponent.StaticEmojiSegment.allCases
let segments = string.components(separatedBy: "\n\n")
for i in 0 ..< min(segments.count, orderedSegments.count) {
let list = segments[i].components(separatedBy: " ")
result.append((orderedSegments[i], list))
}
return result
}()
private final class WarpView: UIView { private final class WarpView: UIView {
private final class WarpPartView: UIView { private final class WarpPartView: UIView {
@ -2226,6 +2206,27 @@ public protocol EmojiContentPeekBehavior: AnyObject {
} }
public final class EmojiPagerContentComponent: Component { public final class EmojiPagerContentComponent: Component {
public static let staticEmojiMapping: [(EmojiPagerContentComponent.StaticEmojiSegment, [String])] = {
guard let path = getAppBundle().path(forResource: "emoji1016", ofType: "txt") else {
return []
}
guard let string = try? String(contentsOf: URL(fileURLWithPath: path)) else {
return []
}
var result: [(EmojiPagerContentComponent.StaticEmojiSegment, [String])] = []
let orderedSegments = EmojiPagerContentComponent.StaticEmojiSegment.allCases
let segments = string.components(separatedBy: "\n\n")
for i in 0 ..< min(segments.count, orderedSegments.count) {
let list = segments[i].components(separatedBy: " ")
result.append((orderedSegments[i], list))
}
return result
}()
public typealias EnvironmentType = (EntityKeyboardChildEnvironment, PagerComponentChildEnvironment) public typealias EnvironmentType = (EntityKeyboardChildEnvironment, PagerComponentChildEnvironment)
public final class ContentAnimation { public final class ContentAnimation {

View File

@ -273,10 +273,9 @@ func attachmentFileController(context: AccountContext, updatedPresentationData:
) )
|> map { presentationData, recentDocuments, state -> (ItemListControllerState, (ItemListNodeState, Any)) in |> map { presentationData, recentDocuments, state -> (ItemListControllerState, (ItemListNodeState, Any)) in
var presentationData = presentationData var presentationData = presentationData
if presentationData.theme.list.blocksBackgroundColor.rgb == presentationData.theme.list.plainBackgroundColor.rgb {
let updatedTheme = presentationData.theme.withModalBlocksBackground() let updatedTheme = presentationData.theme.withModalBlocksBackground()
presentationData = presentationData.withUpdated(theme: updatedTheme) presentationData = presentationData.withUpdated(theme: updatedTheme)
}
let previousRecentDocuments = previousRecentDocuments.swap(recentDocuments) let previousRecentDocuments = previousRecentDocuments.swap(recentDocuments)
let crossfade = previousRecentDocuments == nil && recentDocuments != nil let crossfade = previousRecentDocuments == nil && recentDocuments != nil

View File

@ -839,10 +839,26 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
strongSelf.presentThemeSelection() strongSelf.presentThemeSelection()
return true return true
case let .setChatWallpaper(wallpaper): case let .setChatWallpaper(wallpaper):
guard message.effectivelyIncoming(strongSelf.context.account.peerId) else {
return true
}
strongSelf.chatDisplayNode.dismissInput() strongSelf.chatDisplayNode.dismissInput()
let wallpaperPreviewController = WallpaperGalleryController(context: strongSelf.context, source: .wallpaper(wallpaper, nil, [], nil, nil, nil)) let wallpaperPreviewController = WallpaperGalleryController(context: strongSelf.context, source: .wallpaper(wallpaper, nil, [], nil, nil, nil), mode: .peer(message.id.peerId))
wallpaperPreviewController.apply = { wallpaper, options, _ in
let _ = (strongSelf.context.engine.themes.setExistingChatWallpaper(messageId: message.id)
|> deliverOnMainQueue).start(completed: { [weak wallpaperPreviewController] in
wallpaperPreviewController?.dismiss()
})
}
strongSelf.push(wallpaperPreviewController) strongSelf.push(wallpaperPreviewController)
return true return true
case .setSameChatWallpaper:
for attribute in message.attributes {
if let attribute = attribute as? ReplyMessageAttribute {
strongSelf.controllerInteraction?.navigateToMessage(message.id, attribute.messageId)
return true
}
}
case let .giftPremium(_, _, duration, _, _): case let .giftPremium(_, _, duration, _, _):
strongSelf.chatDisplayNode.dismissInput() strongSelf.chatDisplayNode.dismissInput()
let fromPeerId: PeerId = message.author?.id == strongSelf.context.account.peerId ? strongSelf.context.account.peerId : message.id.peerId let fromPeerId: PeerId = message.author?.id == strongSelf.context.account.peerId ? strongSelf.context.account.peerId : message.id.peerId
@ -16928,7 +16944,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
Queue.mainQueue().async { Queue.mainQueue().async {
unblockingPeer.set(false) unblockingPeer.set(false)
if let strongSelf = self, restartBot { if let strongSelf = self, restartBot {
let _ = enqueueMessages(account: strongSelf.context.account, peerId: peerId, messages: [.message(text: "/start", attributes: [], inlineStickers: [:], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: [])]).start() strongSelf.startBot(strongSelf.presentationInterfaceState.botStartPayload)
} }
} }
})).start()) })).start())
@ -18489,8 +18505,47 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if let themeController = strongSelf.themeScreen { if let themeController = strongSelf.themeScreen {
strongSelf.themeScreen = nil strongSelf.themeScreen = nil
themeController.dimTapped() themeController.dimTapped()
}
let dismissControllers = { [weak self] in
if let self, let navigationController = self.navigationController as? NavigationController {
let controllers = navigationController.viewControllers.filter({ controller in
if controller is WallpaperGalleryController || controller is MediaPickerScreen {
return false
}
return true
})
navigationController.setViewControllers(controllers, animated: true)
}
} }
let controller = ThemeGridController(context: strongSelf.context, mode: .peer(peerId, strongSelf.presentationData.chatWallpaper))
let controller = MediaPickerScreen(context: strongSelf.context, peer: nil, threadTitle: nil, chatLocation: nil, bannedSendPhotos: nil, bannedSendVideos: nil, subject: .assets(nil, true))
controller.navigationPresentation = .modal
controller.customSelection = { [weak self] asset in
guard let strongSelf = self else {
return
}
let controller = WallpaperGalleryController(context: strongSelf.context, source: .asset(asset), mode: .peer(peerId))
controller.navigationPresentation = .modal
controller.apply = { [weak self] wallpaper, options, cropRect in
if let strongSelf = self {
uploadCustomPeerWallpaper(context: strongSelf.context, wallpaper: wallpaper, mode: options, cropRect: cropRect, peerId: peerId, completion: {
dismissControllers()
})
}
}
strongSelf.push(controller)
}
strongSelf.push(controller)
},
changeColor: {
guard let strongSelf = self, let peerId else {
return
}
if let themeController = strongSelf.themeScreen {
strongSelf.themeScreen = nil
themeController.dimTapped()
}
let controller = ThemeColorsGridController(context: context, peerId: peerId)
controller.navigationPresentation = .modal controller.navigationPresentation = .modal
strongSelf.push(controller) strongSelf.push(controller)
}, },

View File

@ -1394,8 +1394,10 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
if case .scheduledMessages = interfaceState.subject { if case .scheduledMessages = interfaceState.subject {
} else { } else {
if let chatHistoryState = interfaceState.chatHistoryState, case .loaded(true) = chatHistoryState { if let user = interfaceState.renderedPeer?.peer as? TelegramUser, user.botInfo != nil {
if let user = interfaceState.renderedPeer?.peer as? TelegramUser, user.botInfo != nil { if let chatHistoryState = interfaceState.chatHistoryState, case .loaded(true) = chatHistoryState {
displayBotStartButton = true
} else if interfaceState.peerIsBlocked {
displayBotStartButton = true displayBotStartButton = true
} }
} }

View File

@ -556,6 +556,7 @@ final class ChatThemeScreen: ViewController {
private let peerName: String private let peerName: String
private let previewTheme: (String?, Bool?) -> Void private let previewTheme: (String?, Bool?) -> Void
fileprivate let changeWallpaper: () -> Void fileprivate let changeWallpaper: () -> Void
fileprivate let changeColor: () -> Void
private let completion: (String?) -> Void private let completion: (String?) -> Void
private var presentationData: PresentationData private var presentationData: PresentationData
@ -579,6 +580,7 @@ final class ChatThemeScreen: ViewController {
peerName: String, peerName: String,
previewTheme: @escaping (String?, Bool?) -> Void, previewTheme: @escaping (String?, Bool?) -> Void,
changeWallpaper: @escaping () -> Void, changeWallpaper: @escaping () -> Void,
changeColor: @escaping () -> Void,
completion: @escaping (String?) -> Void completion: @escaping (String?) -> Void
) { ) {
self.context = context self.context = context
@ -588,6 +590,7 @@ final class ChatThemeScreen: ViewController {
self.peerName = peerName self.peerName = peerName
self.previewTheme = previewTheme self.previewTheme = previewTheme
self.changeWallpaper = changeWallpaper self.changeWallpaper = changeWallpaper
self.changeColor = changeColor
self.completion = completion self.completion = completion
super.init(navigationBarPresentationData: nil) super.init(navigationBarPresentationData: nil)
@ -724,7 +727,9 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
private let animationContainerNode: ASDisplayNode private let animationContainerNode: ASDisplayNode
private var animationNode: AnimationNode private var animationNode: AnimationNode
private let doneButton: SolidRoundedButtonNode private let doneButton: SolidRoundedButtonNode
private let wallpaperButton: HighlightableButtonNode private let galleryButton: HighlightableButtonNode
private let colorButton: HighlightableButtonNode
private let optionsButton: HighlightableButtonNode
private let listNode: ListView private let listNode: ListView
private var entries: [ThemeSettingsThemeEntry]? private var entries: [ThemeSettingsThemeEntry]?
@ -818,9 +823,17 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
self.doneButton = SolidRoundedButtonNode(theme: SolidRoundedButtonTheme(theme: self.presentationData.theme), height: 52.0, cornerRadius: 11.0, gloss: false) self.doneButton = SolidRoundedButtonNode(theme: SolidRoundedButtonTheme(theme: self.presentationData.theme), height: 52.0, cornerRadius: 11.0, gloss: false)
self.doneButton.title = initiallySelectedEmoticon == nil ? self.presentationData.strings.Conversation_Theme_DontSetTheme : self.presentationData.strings.Conversation_Theme_Apply self.doneButton.title = initiallySelectedEmoticon == nil ? self.presentationData.strings.Conversation_Theme_DontSetTheme : self.presentationData.strings.Conversation_Theme_Apply
self.doneButton.isHidden = true
self.wallpaperButton = HighlightableButtonNode() self.galleryButton = HighlightableButtonNode()
self.wallpaperButton.setTitle("Set Background from Gallery", with: Font.regular(17.0), with: self.presentationData.theme.actionSheet.controlAccentColor, for: .normal) self.galleryButton.setTitle("Choose Background From Photos", with: Font.regular(17.0), with: self.presentationData.theme.actionSheet.controlAccentColor, for: .normal)
self.colorButton = HighlightableButtonNode()
self.colorButton.setTitle("Choose Color as a Background", with: Font.regular(17.0), with: self.presentationData.theme.actionSheet.controlAccentColor, for: .normal)
self.optionsButton = HighlightableButtonNode()
self.optionsButton.setTitle("Other Options...", with: Font.regular(17.0), with: self.presentationData.theme.actionSheet.controlAccentColor, for: .normal)
self.optionsButton.isHidden = true
self.listNode = ListView() self.listNode = ListView()
self.listNode.transform = CATransform3DMakeRotation(-CGFloat.pi / 2.0, 0.0, 0.0, 1.0) self.listNode.transform = CATransform3DMakeRotation(-CGFloat.pi / 2.0, 0.0, 0.0, 1.0)
@ -844,7 +857,9 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
self.contentContainerNode.addSubnode(self.titleNode) self.contentContainerNode.addSubnode(self.titleNode)
self.contentContainerNode.addSubnode(self.textNode) self.contentContainerNode.addSubnode(self.textNode)
self.contentContainerNode.addSubnode(self.doneButton) self.contentContainerNode.addSubnode(self.doneButton)
self.contentContainerNode.addSubnode(self.wallpaperButton) self.contentContainerNode.addSubnode(self.galleryButton)
self.contentContainerNode.addSubnode(self.colorButton)
self.contentContainerNode.addSubnode(self.optionsButton)
self.topContentContainerNode.addSubnode(self.animationContainerNode) self.topContentContainerNode.addSubnode(self.animationContainerNode)
self.animationContainerNode.addSubnode(self.animationNode) self.animationContainerNode.addSubnode(self.animationNode)
@ -860,7 +875,9 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
strongSelf.completion?(strongSelf.selectedEmoticon) strongSelf.completion?(strongSelf.selectedEmoticon)
} }
} }
self.wallpaperButton.addTarget(self, action: #selector(self.wallpaperButtonPressed), forControlEvents: .touchUpInside) self.galleryButton.addTarget(self, action: #selector(self.galleryButtonPressed), forControlEvents: .touchUpInside)
self.colorButton.addTarget(self, action: #selector(self.colorButtonPressed), forControlEvents: .touchUpInside)
self.optionsButton.addTarget(self, action: #selector(self.optionsButtonPressed), forControlEvents: .touchUpInside)
self.disposable.set(combineLatest(queue: Queue.mainQueue(), self.context.engine.themes.getChatThemes(accountManager: self.context.sharedContext.accountManager), self.selectedEmoticonPromise.get(), self.isDarkAppearancePromise.get()).start(next: { [weak self] themes, selectedEmoticon, isDarkAppearance in self.disposable.set(combineLatest(queue: Queue.mainQueue(), self.context.engine.themes.getChatThemes(accountManager: self.context.sharedContext.accountManager), self.selectedEmoticonPromise.get(), self.isDarkAppearancePromise.get()).start(next: { [weak self] themes, selectedEmoticon, isDarkAppearance in
guard let strongSelf = self else { guard let strongSelf = self else {
@ -881,24 +898,7 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
let action: (String?) -> Void = { [weak self] emoticon in let action: (String?) -> Void = { [weak self] emoticon in
if let strongSelf = self, strongSelf.selectedEmoticon != emoticon { if let strongSelf = self, strongSelf.selectedEmoticon != emoticon {
strongSelf.animateCrossfade(animateIcon: true) strongSelf.setEmoticon(emoticon)
strongSelf.previewTheme?(emoticon, strongSelf.isDarkAppearance)
strongSelf.selectedEmoticon = emoticon
let _ = ensureThemeVisible(listNode: strongSelf.listNode, emoticon: emoticon, animated: true)
let doneButtonTitle: String
if emoticon == nil {
doneButtonTitle = strongSelf.initiallySelectedEmoticon == nil ? strongSelf.presentationData.strings.Conversation_Theme_DontSetTheme : strongSelf.presentationData.strings.Conversation_Theme_Reset
} else {
doneButtonTitle = strongSelf.presentationData.strings.Conversation_Theme_Apply
}
strongSelf.doneButton.title = doneButtonTitle
strongSelf.themeSelectionsCount += 1
if strongSelf.themeSelectionsCount == 2 {
strongSelf.maybePresentPreviewTooltip()
}
} }
} }
let previousEntries = strongSelf.entries ?? [] let previousEntries = strongSelf.entries ?? []
@ -987,6 +987,35 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
}) })
} }
private func setEmoticon(_ emoticon: String?) {
self.animateCrossfade(animateIcon: true)
self.previewTheme?(emoticon, self.isDarkAppearance)
self.selectedEmoticon = emoticon
let _ = ensureThemeVisible(listNode: self.listNode, emoticon: emoticon, animated: true)
let doneButtonTitle: String
if emoticon == nil {
self.doneButton.isHidden = true
self.galleryButton.isHidden = false
self.colorButton.isHidden = false
self.optionsButton.isHidden = true
doneButtonTitle = self.initiallySelectedEmoticon == nil ? self.presentationData.strings.Conversation_Theme_DontSetTheme : self.presentationData.strings.Conversation_Theme_Reset
} else {
self.doneButton.isHidden = false
self.galleryButton.isHidden = true
self.colorButton.isHidden = true
self.optionsButton.isHidden = false
doneButtonTitle = self.presentationData.strings.Conversation_Theme_Apply
}
self.doneButton.title = doneButtonTitle
self.themeSelectionsCount += 1
if self.themeSelectionsCount == 2 {
self.maybePresentPreviewTooltip()
}
}
func updatePresentationData(_ presentationData: PresentationData) { func updatePresentationData(_ presentationData: PresentationData) {
guard !self.animatedOut else { guard !self.animatedOut else {
return return
@ -1037,10 +1066,18 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
self.cancel?() self.cancel?()
} }
@objc func wallpaperButtonPressed() { @objc func galleryButtonPressed() {
self.controller?.changeWallpaper() self.controller?.changeWallpaper()
} }
@objc func colorButtonPressed() {
self.controller?.changeColor()
}
@objc func optionsButtonPressed() {
self.setEmoticon(nil)
}
func dimTapped() { func dimTapped() {
if self.selectedEmoticon == self.initiallySelectedEmoticon { if self.selectedEmoticon == self.initiallySelectedEmoticon {
self.cancelButtonPressed() self.cancelButtonPressed()
@ -1098,14 +1135,14 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
self.contentBackgroundNode.layer.animate(from: previousColor.cgColor, to: (self.contentBackgroundNode.backgroundColor ?? .clear).cgColor, keyPath: "backgroundColor", timingFunction: CAMediaTimingFunctionName.linear.rawValue, duration: ChatThemeScreen.themeCrossfadeDuration) self.contentBackgroundNode.layer.animate(from: previousColor.cgColor, to: (self.contentBackgroundNode.backgroundColor ?? .clear).cgColor, keyPath: "backgroundColor", timingFunction: CAMediaTimingFunctionName.linear.rawValue, duration: ChatThemeScreen.themeCrossfadeDuration)
} }
if let snapshotView = self.contentContainerNode.view.snapshotView(afterScreenUpdates: false) { // if let snapshotView = self.contentContainerNode.view.snapshotView(afterScreenUpdates: false) {
snapshotView.frame = self.contentContainerNode.frame // snapshotView.frame = self.contentContainerNode.frame
self.contentContainerNode.view.superview?.insertSubview(snapshotView, aboveSubview: self.contentContainerNode.view) // self.contentContainerNode.view.superview?.insertSubview(snapshotView, aboveSubview: self.contentContainerNode.view)
//
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: ChatThemeScreen.themeCrossfadeDuration, delay: ChatThemeScreen.themeCrossfadeDelay, timingFunction: CAMediaTimingFunctionName.linear.rawValue, removeOnCompletion: false, completion: { [weak snapshotView] _ in // snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: ChatThemeScreen.themeCrossfadeDuration, delay: ChatThemeScreen.themeCrossfadeDelay, timingFunction: CAMediaTimingFunctionName.linear.rawValue, removeOnCompletion: false, completion: { [weak snapshotView] _ in
snapshotView?.removeFromSuperview() // snapshotView?.removeFromSuperview()
}) // })
} // }
self.listNode.forEachVisibleItemNode { node in self.listNode.forEachVisibleItemNode { node in
if let node = node as? ThemeSettingsThemeItemIconNode { if let node = node as? ThemeSettingsThemeItemIconNode {
@ -1258,8 +1295,14 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
let doneButtonHeight = self.doneButton.updateLayout(width: contentFrame.width - buttonInset * 2.0, transition: transition) let doneButtonHeight = self.doneButton.updateLayout(width: contentFrame.width - buttonInset * 2.0, transition: transition)
transition.updateFrame(node: self.doneButton, frame: CGRect(x: buttonInset, y: contentHeight - doneButtonHeight - 50.0 - insets.bottom - 6.0, width: contentFrame.width, height: doneButtonHeight)) transition.updateFrame(node: self.doneButton, frame: CGRect(x: buttonInset, y: contentHeight - doneButtonHeight - 50.0 - insets.bottom - 6.0, width: contentFrame.width, height: doneButtonHeight))
let wallpaperButtonSize = self.wallpaperButton.measure(CGSize(width: contentFrame.width - buttonInset * 2.0, height: .greatestFiniteMagnitude)) let wallpaperButtonSize = self.galleryButton.measure(CGSize(width: contentFrame.width - buttonInset * 2.0, height: .greatestFiniteMagnitude))
transition.updateFrame(node: self.wallpaperButton, frame: CGRect(origin: CGPoint(x: floor((contentFrame.width - wallpaperButtonSize.width) / 2.0), y: contentHeight - wallpaperButtonSize.height - insets.bottom - 6.0 - 9.0), size: wallpaperButtonSize)) transition.updateFrame(node: self.galleryButton, frame: CGRect(origin: CGPoint(x: floor((contentFrame.width - wallpaperButtonSize.width) / 2.0), y: contentHeight - doneButtonHeight / 2.0 - wallpaperButtonSize.height / 2.0 - 50.0 - insets.bottom - 6.0), size: wallpaperButtonSize))
let colorButtonSize = self.galleryButton.measure(CGSize(width: contentFrame.width - buttonInset * 2.0, height: .greatestFiniteMagnitude))
transition.updateFrame(node: self.colorButton, frame: CGRect(origin: CGPoint(x: floor((contentFrame.width - colorButtonSize.width) / 2.0), y: contentHeight - colorButtonSize.height - insets.bottom - 6.0 - 9.0), size: colorButtonSize))
let optionsButtonSize = self.galleryButton.measure(CGSize(width: contentFrame.width - buttonInset * 2.0, height: .greatestFiniteMagnitude))
transition.updateFrame(node: self.optionsButton, frame: CGRect(origin: CGPoint(x: floor((contentFrame.width - optionsButtonSize.width) / 2.0), y: contentHeight - optionsButtonSize.height - insets.bottom - 6.0 - 9.0), size: optionsButtonSize))
transition.updateFrame(node: self.contentContainerNode, frame: contentContainerFrame) transition.updateFrame(node: self.contentContainerNode, frame: contentContainerFrame)
transition.updateFrame(node: self.topContentContainerNode, frame: contentContainerFrame) transition.updateFrame(node: self.topContentContainerNode, frame: contentContainerFrame)

View File

@ -398,7 +398,7 @@ private func fetchCachedBlurredWallpaperRepresentation(resource: MediaResource,
let path = NSTemporaryDirectory() + "\(Int64.random(in: Int64.min ... Int64.max))" let path = NSTemporaryDirectory() + "\(Int64.random(in: Int64.min ... Int64.max))"
let url = URL(fileURLWithPath: path) let url = URL(fileURLWithPath: path)
if let colorImage = blurredImage(image, radius: 45.0), let colorDestination = CGImageDestinationCreateWithURL(url as CFURL, kUTTypeJPEG, 1, nil) { if let colorImage = blurredImage(image, radius: 30.0), let colorDestination = CGImageDestinationCreateWithURL(url as CFURL, kUTTypeJPEG, 1, nil) {
CGImageDestinationSetProperties(colorDestination, [:] as CFDictionary) CGImageDestinationSetProperties(colorDestination, [:] as CFDictionary)
let colorQuality: Float = 0.5 let colorQuality: Float = 0.5
@ -447,7 +447,7 @@ private func fetchCachedBlurredWallpaperRepresentation(account: Account, resourc
let path = NSTemporaryDirectory() + "\(Int64.random(in: Int64.min ... Int64.max))" let path = NSTemporaryDirectory() + "\(Int64.random(in: Int64.min ... Int64.max))"
let url = URL(fileURLWithPath: path) let url = URL(fileURLWithPath: path)
if let colorImage = blurredImage(image, radius: 45.0), let colorDestination = CGImageDestinationCreateWithURL(url as CFURL, kUTTypeJPEG, 1, nil) { if let colorImage = blurredImage(image, radius: 30.0), let colorDestination = CGImageDestinationCreateWithURL(url as CFURL, kUTTypeJPEG, 1, nil) {
CGImageDestinationSetProperties(colorDestination, [:] as CFDictionary) CGImageDestinationSetProperties(colorDestination, [:] as CFDictionary)
let colorQuality: Float = 0.5 let colorQuality: Float = 0.5

View File

@ -300,6 +300,7 @@ public func wallpaperImage(account: Account, accountManager: AccountManager<Tele
c.setBlendMode(.normal) c.setBlendMode(.normal)
} }
} }
addCorners(context, arguments: arguments)
return context return context
} }