From 1e2ed2d2f4e3b0d66884ce5f412a4ee0bd43adff Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Sat, 8 Apr 2023 20:10:49 +0400 Subject: [PATCH] Chat wallpaper improvements --- .../Telegram-iOS/en.lproj/Localizable.strings | 7 +- .../Sources/CalendarMessageScreen.swift | 2 +- .../Sources/ChatListController.swift | 2 +- .../Sources/LocationViewControllerNode.swift | 2 +- .../Sources/MediaPickerScreen.swift | 10 +- .../SelectivePrivacySettingsController.swift | 8 +- .../Themes/CustomWallpaperPicker.swift | 29 +-- .../Themes/ThemeColorsGridController.swift | 36 ++-- .../Sources/Themes/WallpaperGalleryItem.swift | 195 +++++++++++++++--- .../Themes/WallpaperOptionButtonNode.swift | 80 ++++++- .../MediaNavigationAccessoryHeaderNode.swift | 2 +- .../Sources/CallControllerNode.swift | 4 +- .../Sources/VoiceChatController.swift | 6 +- .../TelegramNotices/Sources/Notices.swift | 64 ++++++ .../Sources/ChatBotStartInputPanelNode.swift | 2 +- .../TelegramUI/Sources/ChatController.swift | 152 ++++++++------ .../Sources/ChatTextInputPanelNode.swift | 2 +- .../TelegramUI/Sources/ChatThemeScreen.swift | 24 ++- .../Sources/PeerInfo/PeerInfoScreen.swift | 2 +- .../TooltipUI/Sources/TooltipScreen.swift | 57 +++-- .../Sources/WallpaperBackgroundNode.swift | 26 ++- 21 files changed, 518 insertions(+), 194 deletions(-) diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 5d55c6e923..0f35cb28f3 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -9149,7 +9149,7 @@ Sorry for the inconvenience."; "WallpaperPreview.ChatBottomText" = "Enjoy the view."; "Conversation.Theme.SetPhotoWallpaper" = "Choose Background from Photos"; -"Conversation.Theme.SetColorWallpaper" = "Choose Color as a Background"; +"Conversation.Theme.SetColorWallpaper" = "Set a Color as a Background"; "Conversation.Theme.OtherOptions" = "Other Options..."; "Conversation.Theme.ChooseWallpaperTitle" = "Choose Background"; @@ -9161,3 +9161,8 @@ Sorry for the inconvenience."; "WebApp.LaunchMoreInfo" = "More about this bot"; "WebApp.LaunchConfirmation" = "To launch this web app, you will connect to its website."; + +"WallpaperPreview.PreviewInNightMode" = "Preview this background in night mode."; +"WallpaperPreview.PreviewInDayMode" = "Preview this background in day mode."; + +"Conversation.Theme.ApplyBackground" = "Set as Background"; diff --git a/submodules/CalendarMessageScreen/Sources/CalendarMessageScreen.swift b/submodules/CalendarMessageScreen/Sources/CalendarMessageScreen.swift index a4f1b421d6..c293f8802c 100644 --- a/submodules/CalendarMessageScreen/Sources/CalendarMessageScreen.swift +++ b/submodules/CalendarMessageScreen/Sources/CalendarMessageScreen.swift @@ -1370,7 +1370,7 @@ public final class CalendarMessageScreen: ViewController { if self.selectionState?.dayRange == nil { if let selectionToolbarNode = self.selectionToolbarNode { let toolbarFrame = selectionToolbarNode.view.convert(selectionToolbarNode.bounds, to: self.view) - self.controller?.present(TooltipScreen(account: self.context.account, text: self.presentationData.strings.MessageCalendar_EmptySelectionTooltip, style: .default, icon: .none, location: .point(toolbarFrame.insetBy(dx: 0.0, dy: 10.0), .bottom), shouldDismissOnTouch: { point in + self.controller?.present(TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: self.presentationData.strings.MessageCalendar_EmptySelectionTooltip, style: .default, icon: .none, location: .point(toolbarFrame.insetBy(dx: 0.0, dy: 10.0), .bottom), shouldDismissOnTouch: { point in return .dismiss(consume: false) }), in: .current) } diff --git a/submodules/ChatListUI/Sources/ChatListController.swift b/submodules/ChatListUI/Sources/ChatListController.swift index 33c098db5c..5bba1511fe 100644 --- a/submodules/ChatListUI/Sources/ChatListController.swift +++ b/submodules/ChatListUI/Sources/ChatListController.swift @@ -2079,7 +2079,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController let location = CGRect(origin: CGPoint(x: absoluteFrame.midX, y: absoluteFrame.minY - 8.0), size: CGSize()) - parentController.present(TooltipScreen(account: strongSelf.context.account, text: text, icon: .chatListPress, location: .point(location, .bottom), shouldDismissOnTouch: { point in + parentController.present(TooltipScreen(account: strongSelf.context.account, sharedContext: strongSelf.context.sharedContext, text: text, icon: .chatListPress, location: .point(location, .bottom), shouldDismissOnTouch: { point in guard let strongSelf = self, let parentController = strongSelf.parent as? TabBarController else { return .dismiss(consume: false) } diff --git a/submodules/LocationUI/Sources/LocationViewControllerNode.swift b/submodules/LocationUI/Sources/LocationViewControllerNode.swift index 879371f8bc..2a70da2a89 100644 --- a/submodules/LocationUI/Sources/LocationViewControllerNode.swift +++ b/submodules/LocationUI/Sources/LocationViewControllerNode.swift @@ -829,7 +829,7 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan text = strongSelf.presentationData.strings.Location_ProximityTip(EnginePeer(peer).compactDisplayTitle).string } - strongSelf.interaction.present(TooltipScreen(account: strongSelf.context.account, text: text, icon: nil, location: .point(location.offsetBy(dx: -9.0, dy: 0.0), .right), displayDuration: .custom(3.0), shouldDismissOnTouch: { _ in + strongSelf.interaction.present(TooltipScreen(account: strongSelf.context.account, sharedContext: strongSelf.context.sharedContext, text: text, icon: nil, location: .point(location.offsetBy(dx: -9.0, dy: 0.0), .right), displayDuration: .custom(3.0), shouldDismissOnTouch: { _ in return .dismiss(consume: false) })) }) diff --git a/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift b/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift index c06f852960..304251b50f 100644 --- a/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift +++ b/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift @@ -2010,18 +2010,18 @@ public func wallpaperMediaPickerController( context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)? = nil, peer: EnginePeer, - canDelete: Bool, - completion: @escaping (PHAsset) -> Void = { _ in } + completion: @escaping (PHAsset) -> Void = { _ in }, + openColors: @escaping () -> Void ) -> ViewController { let controller = AttachmentController(context: context, updatedPresentationData: updatedPresentationData, chatLocation: nil, buttons: [.standalone], initialButton: .standalone, fromMenu: false, hasTextInput: false, makeEntityInputView: { return nil }) controller.requestController = { [weak controller] _, present in let presentationData = context.sharedContext.currentPresentationData.with { $0 } - let mediaPickerController = MediaPickerScreen(context: context, peer: nil, threadTitle: nil, chatLocation: nil, bannedSendPhotos: nil, bannedSendVideos: nil, subject: .assets(nil, .wallpaper), mainButtonState: canDelete ? AttachmentMainButtonState(text: presentationData.strings.Conversation_Theme_ResetWallpaper, font: .regular, background: .color(.clear), textColor: presentationData.theme.actionSheet.destructiveActionTextColor, isVisible: true, progress: .none, isEnabled: true) : nil, mainButtonAction: canDelete ? { - let _ = context.engine.themes.setChatWallpaper(peerId: peer.id, wallpaper: nil).start() + let mediaPickerController = MediaPickerScreen(context: context, peer: nil, threadTitle: nil, chatLocation: nil, bannedSendPhotos: nil, bannedSendVideos: nil, subject: .assets(nil, .wallpaper), mainButtonState: AttachmentMainButtonState(text: presentationData.strings.Conversation_Theme_SetColorWallpaper, font: .regular, background: .color(.clear), textColor: presentationData.theme.actionSheet.controlAccentColor, isVisible: true, progress: .none, isEnabled: true), mainButtonAction: { controller?.dismiss(animated: true) - } : nil) + openColors() + }) mediaPickerController.customSelection = completion present(mediaPickerController, mediaPickerController.mediaPickerContext) } diff --git a/submodules/SettingsUI/Sources/Privacy and Security/SelectivePrivacySettingsController.swift b/submodules/SettingsUI/Sources/Privacy and Security/SelectivePrivacySettingsController.swift index 1e06aaf916..b5a667f6c0 100644 --- a/submodules/SettingsUI/Sources/Privacy and Security/SelectivePrivacySettingsController.swift +++ b/submodules/SettingsUI/Sources/Privacy and Security/SelectivePrivacySettingsController.swift @@ -669,12 +669,8 @@ private func selectivePrivacySettingsControllerEntries(presentationData: Present entries.append(.everybody(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenEverybody, state.setting == .everybody)) entries.append(.contacts(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenContacts, state.setting == .contacts)) - switch kind { - case .presence, .voiceCalls, .forwards, .phoneNumber, .voiceMessages, .profilePhoto: - entries.append(.nobody(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenNobody, state.setting == .nobody)) - case .groupInvitations: - break - } + entries.append(.nobody(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenNobody, state.setting == .nobody)) + let phoneLink = "https://t.me/+\(phoneNumber)" if let settingInfoText = settingInfoText { entries.append(.settingInfo(presentationData.theme, settingInfoText, phoneLink)) diff --git a/submodules/SettingsUI/Sources/Themes/CustomWallpaperPicker.swift b/submodules/SettingsUI/Sources/Themes/CustomWallpaperPicker.swift index 2edaaea2d2..454225d3d7 100644 --- a/submodules/SettingsUI/Sources/Themes/CustomWallpaperPicker.swift +++ b/submodules/SettingsUI/Sources/Themes/CustomWallpaperPicker.swift @@ -196,7 +196,7 @@ func uploadCustomWallpaper(context: AccountContext, wallpaper: WallpaperGalleryE }).start() } -public func uploadCustomPeerWallpaper(context: AccountContext, wallpaper: WallpaperGalleryEntry, mode: WallpaperPresentationOptions, cropRect: CGRect?, brightness: CGFloat?, peerId: PeerId, completion: @escaping () -> Void) { +public func uploadCustomPeerWallpaper(context: AccountContext, wallpaper: WallpaperGalleryEntry, mode: WallpaperPresentationOptions, cropRect: CGRect?, brightness: CGFloat?, peerId: PeerId, completion: @escaping () -> Void) { let imageSignal: Signal switch wallpaper { case let .wallpaper(wallpaper, _): @@ -279,24 +279,6 @@ public func uploadCustomPeerWallpaper(context: AccountContext, wallpaper: Wallpa croppedImage = blurredImage(croppedImage, radius: 30.0)! } - if let brightness, abs(brightness) > 0.01 { - if let updatedImage = generateImage(croppedImage.size, contextGenerator: { size, context in - let bounds = CGRect(origin: .zero, size: size) - if let cgImage = croppedImage.cgImage { - context.draw(cgImage, in: bounds) - } - if brightness > 0.0 { - context.setFillColor(UIColor(rgb: 0xffffff, alpha: brightness).cgColor) - context.setBlendMode(.overlay) - } else { - context.setFillColor(UIColor(rgb: 0x000000, alpha: brightness * -1.0).cgColor) - } - context.fill(bounds) - }) { - croppedImage = updatedImage - } - } - let thumbnailDimensions = finalCropRect.size.fitted(CGSize(width: 320.0, height: 320.0)) let thumbnailImage = generateScaledImage(image: croppedImage, size: thumbnailDimensions, scale: 1.0) @@ -309,7 +291,12 @@ public func uploadCustomPeerWallpaper(context: AccountContext, wallpaper: Wallpa context.sharedContext.accountManager.mediaBox.storeResourceData(resource.id, data: data, synchronous: true) context.account.postbox.mediaBox.storeResourceData(resource.id, data: data, synchronous: true) - let settings = WallpaperSettings(blur: mode.contains(.blur), motion: mode.contains(.motion), colors: [], intensity: nil) + var intensity: Int32? + if let brightness { + intensity = Int32(brightness * 100.0) + } + + let settings = WallpaperSettings(blur: mode.contains(.blur), motion: mode.contains(.motion), colors: [], intensity: intensity) let temporaryWallpaper: TelegramWallpaper = .image([TelegramMediaImageRepresentation(dimensions: PixelDimensions(thumbnailDimensions), resource: thumbnailResource, progressiveSizes: [], immediateThumbnailData: nil, hasVideo: false, isPersonal: false), TelegramMediaImageRepresentation(dimensions: PixelDimensions(croppedImage.size), resource: resource, progressiveSizes: [], immediateThumbnailData: nil, hasVideo: false, isPersonal: false)], settings) let _ = context.account.postbox.transaction({ transaction in @@ -326,7 +313,7 @@ public func uploadCustomPeerWallpaper(context: AccountContext, wallpaper: Wallpa completion() } - let _ = uploadWallpaper(account: context.account, resource: resource, settings: WallpaperSettings(blur: false, motion: mode.contains(.motion), colors: [], intensity: nil), forChat: true).start(next: { status in + let _ = uploadWallpaper(account: context.account, resource: resource, settings: WallpaperSettings(blur: false, motion: mode.contains(.motion), colors: [], intensity: intensity), forChat: true).start(next: { status in if case let .complete(wallpaper) = status { if case let .file(file) = wallpaper { context.account.postbox.mediaBox.copyResourceData(from: resource.id, to: file.file.resource.id, synchronous: true) diff --git a/submodules/SettingsUI/Sources/Themes/ThemeColorsGridController.swift b/submodules/SettingsUI/Sources/Themes/ThemeColorsGridController.swift index 90848d1c20..963e1244c2 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemeColorsGridController.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemeColorsGridController.swift @@ -11,8 +11,8 @@ import TelegramUIPreferences import AccountContext import AttachmentUI -private func availableGradients(theme: PresentationTheme) -> [[UInt32]] { - if theme.overallDarkAppearance { +private func availableGradients(dark: Bool) -> [[UInt32]] { + if dark { return [ [0x1e3557, 0x151a36, 0x1c4352, 0x2a4541] as [UInt32], [0x1d223f, 0x1d1832, 0x1b2943, 0x141631] as [UInt32], @@ -39,8 +39,8 @@ private func availableGradients(theme: PresentationTheme) -> [[UInt32]] { } } -private func availableColors(theme: PresentationTheme) -> [UInt32] { - if theme.overallDarkAppearance { +private func availableColors(dark: Bool) -> [UInt32] { + if dark { return [ 0x1D2D3C, 0x111B26, @@ -150,6 +150,7 @@ public final class ThemeColorsGridController: ViewController, AttachmentContaina var pushController: (ViewController) -> Void = { _ in } var dismissControllers: (() -> Void)? + var openGallery: (() -> Void)? public init(context: AccountContext, mode: Mode = .default, canDelete: Bool = false) { self.context = context @@ -192,9 +193,7 @@ public final class ThemeColorsGridController: ViewController, AttachmentContaina self?.push(controller) } - if canDelete { - self.mainButtonStatePromise.set(.single(AttachmentMainButtonState(text: self.presentationData.strings.Conversation_Theme_ResetWallpaper, font: .regular, background: .color(.clear), textColor: self.presentationData.theme.actionSheet.destructiveActionTextColor, isVisible: true, progress: .none, isEnabled: true))) - } + self.mainButtonStatePromise.set(.single(AttachmentMainButtonState(text: self.presentationData.strings.Conversation_Theme_SetPhotoWallpaper, font: .regular, background: .color(.clear), textColor: self.presentationData.theme.actionSheet.controlAccentColor, isVisible: true, progress: .none, isEnabled: true))) } required public init(coder aDecoder: NSCoder) { @@ -270,7 +269,11 @@ public final class ThemeColorsGridController: ViewController, AttachmentContaina } public override func loadDisplayNode() { - self.displayNode = ThemeColorsGridControllerNode(context: self.context, presentationData: self.presentationData, controller: self, gradients: availableGradients(theme: self.presentationData.theme), colors: availableColors(theme: self.presentationData.theme), push: { [weak self] controller in + var dark = false + if case .default = self.mode { + dark = self.presentationData.theme.overallDarkAppearance + } + self.displayNode = ThemeColorsGridControllerNode(context: self.context, presentationData: self.presentationData, controller: self, gradients: availableGradients(dark: dark), colors: availableColors(dark: dark), push: { [weak self] controller in self?.pushController(controller) }, pop: { [weak self] in if let strongSelf = self, let navigationController = strongSelf.navigationController as? NavigationController { @@ -327,12 +330,8 @@ public final class ThemeColorsGridController: ViewController, AttachmentContaina } @objc fileprivate func mainButtonPressed() { - guard case let .peer(peer) = self.mode else { - return - } - - let _ = self.context.engine.themes.setChatWallpaper(peerId: peer.id, wallpaper: nil).start() self.dismiss(animated: true) + self.openGallery?() } public var requestAttachmentMenuExpansion: () -> Void = {} @@ -385,18 +384,25 @@ private final class ThemeColorsGridContext: AttachmentMediaPickerContext { } -public func standaloneColorPickerController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)? = nil, peer: EnginePeer, canDelete: Bool, push: @escaping (ViewController) -> Void) -> ViewController { +public func standaloneColorPickerController( + context: AccountContext, + updatedPresentationData: (initial: PresentationData, signal: Signal)? = nil, + peer: EnginePeer, + push: @escaping (ViewController) -> Void, + openGallery: @escaping () -> Void +) -> ViewController { let controller = AttachmentController(context: context, updatedPresentationData: updatedPresentationData, chatLocation: nil, buttons: [.standalone], initialButton: .standalone, fromMenu: false, hasTextInput: false, makeEntityInputView: { return nil }) controller.requestController = { _, present in - let colorPickerController = ThemeColorsGridController(context: context, mode: .peer(peer), canDelete: canDelete) + let colorPickerController = ThemeColorsGridController(context: context, mode: .peer(peer)) colorPickerController.pushController = { controller in push(controller) } colorPickerController.dismissControllers = { [weak controller] in controller?.dismiss(animated: true) } + colorPickerController.openGallery = openGallery present(colorPickerController, colorPickerController.mediaPickerContext) } return controller diff --git a/submodules/SettingsUI/Sources/Themes/WallpaperGalleryItem.swift b/submodules/SettingsUI/Sources/Themes/WallpaperGalleryItem.swift index 6d68563aca..378b2b380a 100644 --- a/submodules/SettingsUI/Sources/Themes/WallpaperGalleryItem.swift +++ b/submodules/SettingsUI/Sources/Themes/WallpaperGalleryItem.swift @@ -19,6 +19,8 @@ import WallpaperResources import AppBundle import WallpaperBackgroundNode import TextFormat +import TooltipUI +import TelegramNotices struct WallpaperGalleryItemArguments { let colorPreview: Bool @@ -83,7 +85,7 @@ private func reference(for resource: MediaResource, media: Media, message: Messa final class WallpaperGalleryItemNode: GalleryItemNode { private let context: AccountContext - private let presentationData: PresentationData + private var presentationData: PresentationData var entry: WallpaperGalleryEntry? var source: WallpaperListSource? @@ -102,6 +104,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode { private let cancelButtonNode: WallpaperNavigationButtonNode private let shareButtonNode: WallpaperNavigationButtonNode + private let dayNightButtonNode: WallpaperNavigationButtonNode private let blurButtonNode: WallpaperOptionButtonNode private let motionButtonNode: WallpaperOptionButtonNode @@ -139,10 +142,16 @@ final class WallpaperGalleryItemNode: GalleryItemNode { private var isReadyDisposable: Disposable? + private var isDarkAppearance: Bool = false + private var didChangeAppearance: Bool = false + private var darkAppearanceIntensity: CGFloat = 0.8 + init(context: AccountContext) { self.context = context self.presentationData = context.sharedContext.currentPresentationData.with { $0 } + self.isDarkAppearance = self.presentationData.theme.overallDarkAppearance + self.wrapperNode = ASDisplayNode() self.imageNode = TransformImageNode() self.imageNode.contentAnimations = .subsequentUpdates @@ -154,6 +163,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode { self.blurredNode = BlurredImageNode() self.brightnessNode = ASDisplayNode() + self.brightnessNode.alpha = 0.0 self.messagesContainerNode = ASDisplayNode() self.messagesContainerNode.transform = CATransform3DMakeScale(1.0, -1.0, 1.0) @@ -169,16 +179,18 @@ final class WallpaperGalleryItemNode: GalleryItemNode { self.serviceBackgroundNode = NavigationBackgroundNode(color: UIColor(rgb: 0x333333, alpha: 0.33)) var sliderValueChangedImpl: ((CGFloat) -> Void)? - self.sliderNode = WallpaperSliderNode(minValue: 0.0, maxValue: 1.0, value: 0.5, valueChanged: { value, _ in + self.sliderNode = WallpaperSliderNode(minValue: 0.0, maxValue: 1.0, value: 0.7, valueChanged: { value, _ in sliderValueChangedImpl?(value) }) self.colorsButtonNode = WallpaperOptionButtonNode(title: self.presentationData.strings.WallpaperPreview_WallpaperColors, value: .colors(false, [.clear])) - self.cancelButtonNode = WallpaperNavigationButtonNode(content: .text(self.presentationData.strings.Common_Cancel), dark: false) + self.cancelButtonNode = WallpaperNavigationButtonNode(content: .text(self.presentationData.strings.Common_Cancel), dark: true) self.cancelButtonNode.enableSaturation = true - self.shareButtonNode = WallpaperNavigationButtonNode(content: .icon(image: UIImage(bundleImageName: "Chat/Links/Share"), size: CGSize(width: 28.0, height: 28.0)), dark: false) + self.shareButtonNode = WallpaperNavigationButtonNode(content: .icon(image: UIImage(bundleImageName: "Chat/Links/Share"), size: CGSize(width: 28.0, height: 28.0)), dark: true) self.shareButtonNode.enableSaturation = true + self.dayNightButtonNode = WallpaperNavigationButtonNode(content: .dayNight(isNight: self.isDarkAppearance), dark: true) + self.dayNightButtonNode.enableSaturation = true self.playButtonPlayImage = generateImage(CGSize(width: 48.0, height: 48.0), rotatedContext: { size, context in context.clear(CGRect(origin: CGPoint(), size: size)) @@ -242,6 +254,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode { self.addSubnode(self.sliderNode) self.addSubnode(self.cancelButtonNode) self.addSubnode(self.shareButtonNode) + self.addSubnode(self.dayNightButtonNode) self.imageNode.addSubnode(self.brightnessNode) @@ -252,22 +265,11 @@ final class WallpaperGalleryItemNode: GalleryItemNode { self.playButtonNode.addTarget(self, action: #selector(self.togglePlay), forControlEvents: .touchUpInside) self.cancelButtonNode.addTarget(self, action: #selector(self.cancelPressed), forControlEvents: .touchUpInside) self.shareButtonNode.addTarget(self, action: #selector(self.actionPressed), forControlEvents: .touchUpInside) + self.dayNightButtonNode.addTarget(self, action: #selector(self.dayNightPressed), forControlEvents: .touchUpInside) sliderValueChangedImpl = { [weak self] value in if let self { - let value = (value - 0.5) * 2.0 - if value < 0.0 { - self.brightnessNode.backgroundColor = UIColor(rgb: 0x000000) - self.brightnessNode.layer.compositingFilter = nil - self.brightnessNode.alpha = value * -1.0 - } else if value > 0.0 { - self.brightnessNode.backgroundColor = UIColor(rgb: 0xffffff) - self.brightnessNode.layer.compositingFilter = "overlayBlendMode" - self.brightnessNode.alpha = value - } else { - self.brightnessNode.layer.compositingFilter = nil - self.brightnessNode.alpha = 0.0 - } + self.updateIntensity(transition: .immediate) } } } @@ -297,7 +299,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode { } switch entry { case .asset, .contextResult: - return (self.sliderNode.value - 0.5) * 2.0 + return self.sliderNode.value default: return nil } @@ -311,6 +313,53 @@ final class WallpaperGalleryItemNode: GalleryItemNode { self.action?() } + + @objc private func dayNightPressed() { + self.isDarkAppearance = !self.isDarkAppearance + self.dayNightButtonNode.setIsNight(self.isDarkAppearance) + + if let layout = self.validLayout?.0 { + let offset = CGPoint(x: self.validOffset ?? 0.0, y: 0.0) + let transition: ContainedViewLayoutTransition = .animated(duration: 0.4, curve: .spring) + self.updateButtonsLayout(layout: layout, offset: offset, transition: transition) + self.updateMessagesLayout(layout: layout, offset: offset, transition: transition) + + if !self.didChangeAppearance { + self.didChangeAppearance = true + self.animateIntensityChange(delay: 0.15) + } else { + self.updateIntensity(transition: .animated(duration: 0.3, curve: .easeInOut)) + } + } + } + + private func animateIntensityChange(delay: Double) { + let targetValue: CGFloat = self.sliderNode.value + self.sliderNode.internalUpdateLayout(size: self.sliderNode.frame.size, value: 1.0) + self.sliderNode.ignoreUpdates = true + Queue.mainQueue().after(delay, { + self.brightnessNode.backgroundColor = UIColor(rgb: 0x000000) + self.brightnessNode.layer.compositingFilter = nil + + self.sliderNode.ignoreUpdates = false + let transition: ContainedViewLayoutTransition = .animated(duration: 0.35, curve: .easeInOut) + self.sliderNode.animateValue(from: 1.0, to: targetValue, transition: transition) + self.updateIntensity(transition: transition) + }) + } + + private func updateIntensity(transition: ContainedViewLayoutTransition) { + let value = self.isDarkAppearance ? self.sliderNode.value : 1.0 + if value < 1.0 { + self.brightnessNode.backgroundColor = UIColor(rgb: 0x000000) + self.brightnessNode.layer.compositingFilter = nil + transition.updateAlpha(node: self.brightnessNode, alpha: 1.0 - value) + } else { + self.brightnessNode.layer.compositingFilter = nil + transition.updateAlpha(node: self.brightnessNode, alpha: 0.0) + } + } + @objc private func cancelPressed() { self.dismiss() } @@ -329,6 +378,8 @@ final class WallpaperGalleryItemNode: GalleryItemNode { } } + var showPreviewTooltip = false + if self.entry != entry || self.arguments.colorPreview != previousArguments.colorPreview { let previousEntry = self.entry self.entry = entry @@ -357,8 +408,6 @@ final class WallpaperGalleryItemNode: GalleryItemNode { var isBlurrable = true - self.nativeNode.updateBubbleTheme(bubbleTheme: presentationData.theme, bubbleCorners: presentationData.chatBubbleCorners) - switch entry { case let .wallpaper(wallpaper, _): self.nativeNode.update(wallpaper: wallpaper) @@ -393,6 +442,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode { } case .asset: self.nativeNode._internalUpdateIsSettingUpWallpaper() + //self.nativeNode.update(wallpaper: self.presentationData.chatWallpaper) self.nativeNode.isHidden = true self.patternButtonNode.isSelected = false self.playButtonNode.setIcon(self.playButtonRotateImage) @@ -402,7 +452,8 @@ final class WallpaperGalleryItemNode: GalleryItemNode { self.playButtonNode.setIcon(self.playButtonRotateImage) } - var isEditable = false + self.nativeNode.updateBubbleTheme(bubbleTheme: presentationData.theme, bubbleCorners: presentationData.chatBubbleCorners) + var canShare = false switch entry { case let .wallpaper(wallpaper, message): @@ -566,7 +617,6 @@ final class WallpaperGalleryItemNode: GalleryItemNode { } self.cropNode.removeFromSupernode() case let .asset(asset): - isEditable = true let dimensions = CGSize(width: asset.pixelWidth, height: asset.pixelHeight) contentSize = dimensions displaySize = dimensions.dividedByScreenScale().integralFloor @@ -576,8 +626,8 @@ final class WallpaperGalleryItemNode: GalleryItemNode { subtitleSignal = .single(nil) colorSignal = .single(UIColor(rgb: 0x000000, alpha: 0.3)) self.wrapperNode.addSubnode(self.cropNode) + showPreviewTooltip = true case let .contextResult(result): - isEditable = true var imageDimensions: CGSize? var imageResource: TelegramMediaResource? var thumbnailDimensions: CGSize? @@ -631,11 +681,12 @@ final class WallpaperGalleryItemNode: GalleryItemNode { colorSignal = .single(UIColor(rgb: 0x000000, alpha: 0.3)) subtitleSignal = .single(nil) self.wrapperNode.addSubnode(self.cropNode) + showPreviewTooltip = true } self.contentSize = contentSize - self.cancelButtonNode.dark = !isEditable - self.shareButtonNode.dark = !isEditable + //self.cancelButtonNode.dark = !isEditable + //self.shareButtonNode.dark = !isEditable self.shareButtonNode.isHidden = !canShare if self.cropNode.supernode == nil { @@ -713,6 +764,18 @@ final class WallpaperGalleryItemNode: GalleryItemNode { self.updateButtonsLayout(layout: layout, offset: CGPoint(), transition: .immediate) self.updateMessagesLayout(layout: layout, offset: CGPoint(), transition: .immediate) } + + if showPreviewTooltip { + Queue.mainQueue().after(0.35) { + self.maybePresentPreviewTooltip() + } + if self.isDarkAppearance && !self.didChangeAppearance { + Queue.mainQueue().justDispatch { + self.didChangeAppearance = true + self.animateIntensityChange(delay: 0.35) + } + } + } } override func screenFrameUpdated(_ frame: CGRect) { @@ -966,7 +1029,9 @@ final class WallpaperGalleryItemNode: GalleryItemNode { if let source = self.source { switch source { case .asset, .contextResult: - additionalYOffset -= 44.0 + if self.isDarkAppearance { + additionalYOffset -= 44.0 + } default: break } @@ -996,8 +1061,17 @@ final class WallpaperGalleryItemNode: GalleryItemNode { var playAlpha: CGFloat = 0.0 let sliderSize = CGSize(width: 268.0, height: 30.0) - let sliderFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - sliderSize.width) / 2.0) + offset.x, y: layout.size.height - toolbarHeight - layout.intrinsicInsets.bottom - 52.0 + offset.y), size: sliderSize) - var sliderIsHidden = true + var sliderFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - sliderSize.width) / 2.0) + offset.x, y: layout.size.height - toolbarHeight - layout.intrinsicInsets.bottom - 52.0 + offset.y), size: sliderSize) + var sliderAlpha: CGFloat = 0.0 + var sliderScale: CGFloat = 0.2 + if !additionalYOffset.isZero { + sliderAlpha = 1.0 + sliderScale = 1.0 + } else { + sliderFrame = sliderFrame.offsetBy(dx: 0.0, dy: 22.0) + } + + var dayNightHidden = true let cancelSize = self.cancelButtonNode.measure(layout.size) let cancelFrame = CGRect(origin: CGPoint(x: 16.0 + offset.x, y: 16.0), size: cancelSize) @@ -1013,13 +1087,13 @@ final class WallpaperGalleryItemNode: GalleryItemNode { blurFrame = leftButtonFrame motionAlpha = 1.0 motionFrame = rightButtonFrame - sliderIsHidden = false + dayNightHidden = false case .contextResult: blurAlpha = 1.0 blurFrame = leftButtonFrame motionAlpha = 1.0 motionFrame = rightButtonFrame - sliderIsHidden = false + dayNightHidden = false case let .wallpaper(wallpaper, _): switch wallpaper { case .builtin: @@ -1104,12 +1178,16 @@ final class WallpaperGalleryItemNode: GalleryItemNode { transition.updateAlpha(node: self.playButtonNode, alpha: playAlpha * alpha) transition.updateSublayerTransformScale(node: self.playButtonNode, scale: max(0.1, playAlpha)) - transition.updateFrame(node: self.sliderNode, frame: sliderFrame) + transition.updateFrameAsPositionAndBounds(node: self.sliderNode, frame: sliderFrame) + transition.updateAlpha(node: self.sliderNode, alpha: sliderAlpha * alpha) + transition.updateTransformScale(node: self.sliderNode, scale: sliderScale) self.sliderNode.updateLayout(size: sliderFrame.size) - self.sliderNode.isHidden = sliderIsHidden transition.updateFrame(node: self.cancelButtonNode, frame: cancelFrame) transition.updateFrame(node: self.shareButtonNode, frame: shareFrame) + transition.updateFrame(node: self.dayNightButtonNode, frame: shareFrame) + + self.dayNightButtonNode.isHidden = dayNightHidden } private func updateMessagesLayout(layout: ContainerViewLayout, offset: CGPoint, transition: ContainedViewLayoutTransition) { @@ -1182,7 +1260,9 @@ final class WallpaperGalleryItemNode: GalleryItemNode { case .asset, .contextResult: topMessageText = presentationData.strings.WallpaperPreview_CropTopText bottomMessageText = presentationData.strings.WallpaperPreview_CropBottomText - bottomInset += 44.0 + if self.isDarkAppearance { + bottomInset += 44.0 + } case .customColor: topMessageText = presentationData.strings.WallpaperPreview_CustomColorTopText bottomMessageText = presentationData.strings.WallpaperPreview_CustomColorBottomText @@ -1197,7 +1277,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode { } } - let theme = self.presentationData.theme.withUpdated(preview: true) + let theme = self.presentationData.theme.withUpdated(preview: false) let message1 = Message(stableId: 2, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 2), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66001, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: bottomMessageText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil) items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message1], theme: theme, strings: self.presentationData.strings, wallpaper: currentWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.nativeNode, availableReactions: nil, isCentered: false)) @@ -1302,6 +1382,16 @@ final class WallpaperGalleryItemNode: GalleryItemNode { self.cropNode.zoom(to: CGRect(x: (contentSize.width - fittedSize.width) / 2.0, y: (contentSize.height - fittedSize.height) / 2.0, width: fittedSize.width, height: fittedSize.height)) } self.blurredNode.frame = self.imageNode.bounds + + let displayMode: WallpaperDisplayMode + if case .regular = layout.metrics.widthClass { + displayMode = .aspectFit + } else { + displayMode = .aspectFill + } + + self.nativeNode.frame = self.wrapperNode.bounds + self.nativeNode.updateLayout(size: self.nativeNode.bounds.size, displayMode: displayMode, transition: .immediate) } self.brightnessNode.frame = self.imageNode.bounds @@ -1322,4 +1412,41 @@ final class WallpaperGalleryItemNode: GalleryItemNode { func animateWallpaperAppeared() { self.nativeNode.animateEvent(transition: .animated(duration: 2.0, curve: .spring), extendAnimation: true) } + + private var displayedPreviewTooltip = false + private func maybePresentPreviewTooltip() { + guard !self.displayedPreviewTooltip else { + return + } + + let frame = self.dayNightButtonNode.view.convert(self.dayNightButtonNode.bounds, to: self.view) + let currentTimestamp = Int32(Date().timeIntervalSince1970) + + let isDark = self.isDarkAppearance + + let signal: Signal<(Int32, Int32), NoError> + if isDark { + signal = ApplicationSpecificNotice.getChatWallpaperLightPreviewTip(accountManager: self.context.sharedContext.accountManager) + } else { + signal = ApplicationSpecificNotice.getChatWallpaperDarkPreviewTip(accountManager: self.context.sharedContext.accountManager) + } + + let _ = (signal + |> deliverOnMainQueue).start(next: { [weak self] count, timestamp in + if let strongSelf = self, (count < 2 && currentTimestamp > timestamp + 24 * 60 * 60) || "".isEmpty { + strongSelf.displayedPreviewTooltip = true + + let controller = TooltipScreen(account: strongSelf.context.account, sharedContext: strongSelf.context.sharedContext, text: isDark ? strongSelf.presentationData.strings.WallpaperPreview_PreviewInDayMode : strongSelf.presentationData.strings.WallpaperPreview_PreviewInNightMode, style: .customBlur(UIColor(rgb: 0x333333, alpha: 0.33)), icon: nil, location: .point(frame.offsetBy(dx: 1.0, dy: 6.0), .bottom), displayDuration: .custom(3.0), inset: 3.0, shouldDismissOnTouch: { _ in + return .dismiss(consume: false) + }) + strongSelf.galleryController()?.present(controller, in: .current) + + if isDark { + let _ = ApplicationSpecificNotice.incrementChatWallpaperLightPreviewTip(accountManager: strongSelf.context.sharedContext.accountManager, timestamp: currentTimestamp).start() + } else { + let _ = ApplicationSpecificNotice.incrementChatWallpaperDarkPreviewTip(accountManager: strongSelf.context.sharedContext.accountManager, timestamp: currentTimestamp).start() + } + } + }) + } } diff --git a/submodules/SettingsUI/Sources/Themes/WallpaperOptionButtonNode.swift b/submodules/SettingsUI/Sources/Themes/WallpaperOptionButtonNode.swift index 5e328f8604..300b6d147d 100644 --- a/submodules/SettingsUI/Sources/Themes/WallpaperOptionButtonNode.swift +++ b/submodules/SettingsUI/Sources/Themes/WallpaperOptionButtonNode.swift @@ -5,6 +5,7 @@ import AsyncDisplayKit import SwiftSignalKit import Postbox import CheckNode +import AnimationUI enum WallpaperOptionButtonValue { case check(Bool) @@ -93,6 +94,7 @@ final class WallpaperNavigationButtonNode: HighlightTrackingButtonNode { enum Content { case icon(image: UIImage?, size: CGSize) case text(String) + case dayNight(isNight: Bool) } var enableSaturation: Bool = false @@ -115,6 +117,7 @@ final class WallpaperNavigationButtonNode: HighlightTrackingButtonNode { private var backgroundNode: ASDisplayNode private let iconNode: ASImageNode private let textNode: ImmediateTextNode + private var animationNode: AnimationNode? func setIcon(_ image: UIImage?) { self.iconNode.image = generateTintedImage(image: image, color: .white) @@ -141,6 +144,12 @@ final class WallpaperNavigationButtonNode: HighlightTrackingButtonNode { case let .icon(icon, _): title = "" self.iconNode.image = generateTintedImage(image: icon, color: .white) + case let .dayNight(isNight): + title = "" + let animationNode = AnimationNode(animation: isNight ? "anim_sun_reverse" : "anim_sun", colors: [:], scale: 1.0) + animationNode.speed = 1.5 + animationNode.isUserInteractionEnabled = false + self.animationNode = animationNode } self.textNode = ImmediateTextNode() @@ -152,19 +161,53 @@ final class WallpaperNavigationButtonNode: HighlightTrackingButtonNode { self.addSubnode(self.iconNode) self.addSubnode(self.textNode) + if let animationNode = self.animationNode { + self.addSubnode(animationNode) + } + self.highligthedChanged = { [weak self] highlighted in if let strongSelf = self { if highlighted { strongSelf.backgroundNode.layer.removeAnimation(forKey: "opacity") strongSelf.backgroundNode.alpha = 0.4 + + strongSelf.iconNode.layer.removeAnimation(forKey: "opacity") + strongSelf.iconNode.alpha = 0.4 + + strongSelf.textNode.layer.removeAnimation(forKey: "opacity") + strongSelf.textNode.alpha = 0.4 + +// if let animationNode = strongSelf.animationNode { +// animationNode.layer.removeAnimation(forKey: "opacity") +// animationNode.alpha = 0.4 +// } } else { strongSelf.backgroundNode.alpha = 1.0 strongSelf.backgroundNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2) + + strongSelf.iconNode.alpha = 1.0 + strongSelf.iconNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2) + + strongSelf.textNode.alpha = 1.0 + strongSelf.textNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2) + +// if let animationNode = strongSelf.animationNode { +// animationNode.alpha = 1.0 +// animationNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2) +// } } } } } + func setIsNight(_ isNight: Bool) { + self.animationNode?.setAnimation(name: !isNight ? "anim_sun_reverse" : "anim_sun", colors: [:]) + self.animationNode?.speed = 1.5 + Queue.mainQueue().after(0.01) { + self.animationNode?.playOnce() + } + } + var buttonColor: UIColor = UIColor(rgb: 0x000000, alpha: 0.3) { didSet { } @@ -179,6 +222,8 @@ final class WallpaperNavigationButtonNode: HighlightTrackingButtonNode { return CGSize(width: ceil(size.width) + 16.0, height: 28.0) case let .icon(_, size): return size + case .dayNight: + return CGSize(width: 28.0, height: 28.0) } } @@ -199,6 +244,11 @@ final class WallpaperNavigationButtonNode: HighlightTrackingButtonNode { if let textSize = self.textSize { self.textNode.frame = CGRect(x: floorToScreenPixels((size.width - textSize.width) / 2.0), y: floorToScreenPixels((size.height - textSize.height) / 2.0), width: textSize.width, height: textSize.height) } + + if let animationNode = self.animationNode { + animationNode.bounds = CGRect(origin: .zero, size: CGSize(width: 24.0, height: 24.0)) + animationNode.position = CGPoint(x: 14.0, y: 14.0) + } } } @@ -491,7 +541,16 @@ final class WallpaperSliderNode: ASDisplayNode { self.view.addGestureRecognizer(tapGestureRecognizer) } - func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition = .immediate) { + var ignoreUpdates = false + func animateValue(from: CGFloat, to: CGFloat, transition: ContainedViewLayoutTransition = .immediate) { + guard let size = self.validLayout else { + return + } + self.internalUpdateLayout(size: size, value: from) + self.internalUpdateLayout(size: size, value: to, transition: transition) + } + + func internalUpdateLayout(size: CGSize, value: CGFloat, transition: ContainedViewLayoutTransition = .immediate) { self.validLayout = size transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: .zero, size: size)) @@ -506,10 +565,17 @@ final class WallpaperSliderNode: ASDisplayNode { } let range = self.maxValue - self.minValue - let value = (self.value - self.minValue) / range + let value = (value - self.minValue) / range let foregroundFrame = CGRect(origin: CGPoint(), size: CGSize(width: value * size.width, height: size.height)) - transition.updateFrameAdditive(node: self.foregroundNode, frame: foregroundFrame) - transition.updateFrameAdditive(node: self.foregroundLightNode, frame: foregroundFrame) + transition.updateFrame(node: self.foregroundNode, frame: foregroundFrame) + transition.updateFrame(node: self.foregroundLightNode, frame: foregroundFrame) + } + + func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition = .immediate) { + guard !self.ignoreUpdates else { + return + } + self.internalUpdateLayout(size: size, value: self.value, transition: transition) } @objc private func panGesture(_ gestureRecognizer: UIPanGestureRecognizer) { @@ -525,14 +591,10 @@ final class WallpaperSliderNode: ASDisplayNode { self.value = max(self.minValue, min(self.maxValue, self.value + delta)) gestureRecognizer.setTranslation(CGPoint(), in: gestureRecognizer.view) - if self.value == 2.0 && previousValue != 2.0 { + if self.value == 0.0 && previousValue != 0.0 { self.hapticFeedback.impact(.soft) } else if self.value == 1.0 && previousValue != 1.0 { self.hapticFeedback.impact(.soft) - } else if self.value == 2.5 && previousValue != 2.5 { - self.hapticFeedback.impact(.soft) - } else if self.value == 0.05 && previousValue != 0.05 { - self.hapticFeedback.impact(.soft) } if abs(previousValue - self.value) >= 0.001 { self.valueChanged(self.value, false) diff --git a/submodules/TelegramBaseController/Sources/MediaNavigationAccessoryHeaderNode.swift b/submodules/TelegramBaseController/Sources/MediaNavigationAccessoryHeaderNode.swift index 87222f20e4..de6f7c7965 100644 --- a/submodules/TelegramBaseController/Sources/MediaNavigationAccessoryHeaderNode.swift +++ b/submodules/TelegramBaseController/Sources/MediaNavigationAccessoryHeaderNode.swift @@ -526,7 +526,7 @@ public final class MediaNavigationAccessoryHeaderNode: ASDisplayNode, UIScrollVi let _ = (ApplicationSpecificNotice.incrementAudioRateOptionsTip(accountManager: self.context.sharedContext.accountManager) |> deliverOnMainQueue).start(next: { [weak self] value in if let strongSelf = self, let controller = strongSelf.getController?(), value == 2 { - let tooltipController = TooltipScreen(account: strongSelf.context.account, text: strongSelf.strings.Conversation_AudioRateOptionsTooltip, style: .default, icon: nil, location: .point(frame.offsetBy(dx: 0.0, dy: 4.0), .bottom), displayDuration: .custom(3.0), inset: 3.0, shouldDismissOnTouch: { _ in + let tooltipController = TooltipScreen(account: strongSelf.context.account, sharedContext: strongSelf.context.sharedContext, text: strongSelf.strings.Conversation_AudioRateOptionsTooltip, style: .default, icon: nil, location: .point(frame.offsetBy(dx: 0.0, dy: 4.0), .bottom), displayDuration: .custom(3.0), inset: 3.0, shouldDismissOnTouch: { _ in return .dismiss(consume: false) }) controller.present(tooltipController, in: .window(.root)) diff --git a/submodules/TelegramCallsUI/Sources/CallControllerNode.swift b/submodules/TelegramCallsUI/Sources/CallControllerNode.swift index f1d8d74b9c..25cc58eee2 100644 --- a/submodules/TelegramCallsUI/Sources/CallControllerNode.swift +++ b/submodules/TelegramCallsUI/Sources/CallControllerNode.swift @@ -760,8 +760,8 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro }) else { return } - - self.present?(TooltipScreen(account: self.account, text: self.presentationData.strings.Call_CameraOrScreenTooltip, style: .light, icon: nil, location: .point(location.offsetBy(dx: 0.0, dy: -14.0), .bottom), displayDuration: .custom(5.0), shouldDismissOnTouch: { _ in + + self.present?(TooltipScreen(account: self.account, sharedContext: self.sharedContext, text: self.presentationData.strings.Call_CameraOrScreenTooltip, style: .light, icon: nil, location: .point(location.offsetBy(dx: 0.0, dy: -14.0), .bottom), displayDuration: .custom(5.0), shouldDismissOnTouch: { _ in return .dismiss(consume: false) })) } diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift index ccd9a5bfee..b6020e48de 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift @@ -2310,7 +2310,7 @@ public final class VoiceChatControllerImpl: ViewController, VoiceChatController } else { text = presentationData.strings.VoiceChat_RecordingInProgress } - strongSelf.controller?.present(TooltipScreen(account: strongSelf.context.account, text: text, icon: nil, location: .point(location.offsetBy(dx: 1.0, dy: 0.0), .top), displayDuration: .custom(3.0), shouldDismissOnTouch: { _ in + strongSelf.controller?.present(TooltipScreen(account: strongSelf.context.account, sharedContext: strongSelf.context.sharedContext, text: text, icon: nil, location: .point(location.offsetBy(dx: 1.0, dy: 0.0), .top), displayDuration: .custom(3.0), shouldDismissOnTouch: { _ in return .dismiss(consume: true) }), in: .window(.root)) } @@ -3507,7 +3507,7 @@ public final class VoiceChatControllerImpl: ViewController, VoiceChatController if !callState.subscribedToScheduled { let location = self.actionButton.view.convert(self.actionButton.bounds, to: self.view).center let point = CGRect(origin: CGPoint(x: location.x - 5.0, y: location.y - 5.0 - 68.0), size: CGSize(width: 10.0, height: 10.0)) - self.controller?.present(TooltipScreen(account: self.context.account, text: self.presentationData.strings.VoiceChat_ReminderNotify, style: .gradient(UIColor(rgb: 0x262c5a), UIColor(rgb: 0x5d2835)), icon: nil, location: .point(point, .bottom), displayDuration: .custom(3.0), shouldDismissOnTouch: { _ in + self.controller?.present(TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: self.presentationData.strings.VoiceChat_ReminderNotify, style: .gradient(UIColor(rgb: 0x262c5a), UIColor(rgb: 0x5d2835)), icon: nil, location: .point(point, .bottom), displayDuration: .custom(3.0), shouldDismissOnTouch: { _ in return .dismiss(consume: false) }), in: .window(.root)) } @@ -6411,7 +6411,7 @@ public final class VoiceChatControllerImpl: ViewController, VoiceChatController point.origin.y += 32.0 } } - self.controller?.present(TooltipScreen(account: self.context.account, text: self.presentationData.strings.VoiceChat_UnmuteSuggestion, style: .gradient(UIColor(rgb: 0x1d446c), UIColor(rgb: 0x193e63)), icon: nil, location: .point(point, position), displayDuration: .custom(8.0), shouldDismissOnTouch: { _ in + self.controller?.present(TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: self.presentationData.strings.VoiceChat_UnmuteSuggestion, style: .gradient(UIColor(rgb: 0x1d446c), UIColor(rgb: 0x193e63)), icon: nil, location: .point(point, position), displayDuration: .custom(8.0), shouldDismissOnTouch: { _ in return .dismiss(consume: false) }), in: .window(.root)) } diff --git a/submodules/TelegramNotices/Sources/Notices.swift b/submodules/TelegramNotices/Sources/Notices.swift index b5e2bb1294..8995477dff 100644 --- a/submodules/TelegramNotices/Sources/Notices.swift +++ b/submodules/TelegramNotices/Sources/Notices.swift @@ -170,6 +170,8 @@ private enum ApplicationSpecificGlobalNotice: Int32 { case audioRateOptionsTip = 36 case translationSuggestion = 37 case sendWhenOnlineTip = 38 + case chatWallpaperLightPreviewTip = 39 + case chatWallpaperDarkPreviewTip = 40 var key: ValueBoxKey { let v = ValueBoxKey(length: 4) @@ -332,6 +334,14 @@ private struct ApplicationSpecificNoticeKeys { return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.chatSpecificThemeDarkPreviewTip.key) } + static func chatWallpaperLightPreviewTip() -> NoticeEntryKey { + return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.chatWallpaperLightPreviewTip.key) + } + + static func chatWallpaperDarkPreviewTip() -> NoticeEntryKey { + return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.chatWallpaperDarkPreviewTip.key) + } + static func chatForwardOptionsTip() -> NoticeEntryKey { return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.chatForwardOptionsTip.key) } @@ -1109,6 +1119,60 @@ public struct ApplicationSpecificNotice { } } + public static func getChatWallpaperLightPreviewTip(accountManager: AccountManager) -> Signal<(Int32, Int32), NoError> { + return accountManager.transaction { transaction -> (Int32, Int32) in + if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatWallpaperLightPreviewTip())?.get(ApplicationSpecificTimestampAndCounterNotice.self) { + return (value.counter, value.timestamp) + } else { + return (0, 0) + } + } + } + + public static func incrementChatWallpaperLightPreviewTip(accountManager: AccountManager, count: Int = 1, timestamp: Int32) -> Signal { + return accountManager.transaction { transaction -> Int in + var currentValue: Int32 = 0 + if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatWallpaperLightPreviewTip())?.get(ApplicationSpecificTimestampAndCounterNotice.self) { + currentValue = value.counter + } + let previousValue = currentValue + currentValue += Int32(count) + + if let entry = CodableEntry(ApplicationSpecificTimestampAndCounterNotice(counter: currentValue, timestamp: timestamp)) { + transaction.setNotice(ApplicationSpecificNoticeKeys.chatWallpaperLightPreviewTip(), entry) + } + + return Int(previousValue) + } + } + + public static func getChatWallpaperDarkPreviewTip(accountManager: AccountManager) -> Signal<(Int32, Int32), NoError> { + return accountManager.transaction { transaction -> (Int32, Int32) in + if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatWallpaperDarkPreviewTip())?.get(ApplicationSpecificTimestampAndCounterNotice.self) { + return (value.counter, value.timestamp) + } else { + return (0, 0) + } + } + } + + public static func incrementChatWallpaperDarkPreviewTip(accountManager: AccountManager, count: Int = 1, timestamp: Int32) -> Signal { + return accountManager.transaction { transaction -> Int in + var currentValue: Int32 = 0 + if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatWallpaperDarkPreviewTip())?.get(ApplicationSpecificTimestampAndCounterNotice.self) { + currentValue = value.counter + } + let previousValue = currentValue + currentValue += Int32(count) + + if let entry = CodableEntry(ApplicationSpecificTimestampAndCounterNotice(counter: currentValue, timestamp: timestamp)) { + transaction.setNotice(ApplicationSpecificNoticeKeys.chatWallpaperDarkPreviewTip(), entry) + } + + return Int(previousValue) + } + } + public static func getChatForwardOptionsTip(accountManager: AccountManager) -> Signal { return accountManager.transaction { transaction -> Int32 in if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatForwardOptionsTip())?.get(ApplicationSpecificCounterNotice.self) { diff --git a/submodules/TelegramUI/Sources/ChatBotStartInputPanelNode.swift b/submodules/TelegramUI/Sources/ChatBotStartInputPanelNode.swift index e0989b05dc..79689abe9f 100644 --- a/submodules/TelegramUI/Sources/ChatBotStartInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatBotStartInputPanelNode.swift @@ -130,7 +130,7 @@ final class ChatBotStartInputPanelNode: ChatInputPanelNode { tooltipController.location = .point(location, .bottom) } } else { - let controller = TooltipScreen(account: context.account, text: self.strings.Bot_TapToUse, icon: .downArrows, location: .point(location, .bottom), displayDuration: .infinite, shouldDismissOnTouch: { _ in + let controller = TooltipScreen(account: context.account, sharedContext: context.sharedContext, text: self.strings.Bot_TapToUse, icon: .downArrows, location: .point(location, .bottom), displayDuration: .infinite, shouldDismissOnTouch: { _ in return .ignore }) controller.alwaysVisible = true diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index bd91ce4895..5b5e2c9c82 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -676,14 +676,17 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G return false } - if strongSelf.presentVoiceMessageDiscardAlert(action: { [weak self] in - if let strongSelf = self { - Queue.mainQueue().after(0.1, { - let _ = strongSelf.controllerInteraction?.openMessage(message, mode) - }) + let displayVoiceMessageDiscardAlert: () -> Bool = { + if strongSelf.presentVoiceMessageDiscardAlert(action: { [weak self] in + if let strongSelf = self { + Queue.mainQueue().after(0.1, { + let _ = strongSelf.controllerInteraction?.openMessage(message, mode) + }) + } + }, performAction: false) { + return false } - }, performAction: false) { - return false + return true } strongSelf.commitPurposefulAction() @@ -696,6 +699,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G for media in message.media { if media is TelegramMediaMap { + if !displayVoiceMessageDiscardAlert() { + return false + } isLocation = true } if let file = media as? TelegramMediaFile, file.isInstantVideo { @@ -707,12 +713,19 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G if let invoice = media as? TelegramMediaInvoice, let extendedMedia = invoice.extendedMedia { switch extendedMedia { case .preview: - strongSelf.controllerInteraction?.openCheckoutOrReceipt(message.id) - return true + if displayVoiceMessageDiscardAlert() { + strongSelf.controllerInteraction?.openCheckoutOrReceipt(message.id) + return true + } else { + return false + } case .full: break } } else if let action = media as? TelegramMediaAction { + if !displayVoiceMessageDiscardAlert() { + return false + } switch action.action { case .pinnedMessageUpdated: for attribute in message.attributes { @@ -5839,6 +5852,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G if let strongSelf = self { let (themeEmoticonPreview, darkAppearancePreview) = themeEmoticonAndDarkAppearance + var chatWallpaper = chatWallpaper + let previousTheme = strongSelf.presentationData.theme let previousStrings = strongSelf.presentationData.strings let previousChatWallpaper = strongSelf.presentationData.chatWallpaper @@ -5846,7 +5861,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G var themeEmoticon = themeEmoticon if let themeEmoticonPreview = themeEmoticonPreview { if !themeEmoticonPreview.isEmpty { - themeEmoticon = themeEmoticonPreview + if themeEmoticon != themeEmoticonPreview { + chatWallpaper = nil + themeEmoticon = themeEmoticonPreview + } } else { themeEmoticon = nil } @@ -5857,7 +5875,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G var presentationData = presentationData var useDarkAppearance = presentationData.theme.overallDarkAppearance - + if let themeEmoticon = themeEmoticon, let theme = chatThemes.first(where: { $0.emoticon?.strippedEmoji == themeEmoticon.strippedEmoji }) { if let darkAppearancePreview = darkAppearancePreview { useDarkAppearance = darkAppearancePreview @@ -5896,7 +5914,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G lightWallpaper = theme.chat.defaultWallpaper } - lightTheme = makePresentationTheme(mediaBox: accountManager.mediaBox, themeReference: themeSettings.theme, accentColor: currentColors?.color, bubbleColors: currentColors?.customBubbleColors ?? [], wallpaper: currentColors?.wallpaper, baseColor: currentColors?.baseColor, serviceBackgroundColor: defaultServiceBackgroundColor) ?? defaultPresentationTheme + var preferredBaseTheme: TelegramBaseTheme? + if let baseTheme = themeSettings.themePreferredBaseTheme[themeSettings.theme.index], [.classic, .day].contains(baseTheme) { + preferredBaseTheme = baseTheme + } + + lightTheme = makePresentationTheme(mediaBox: accountManager.mediaBox, themeReference: themeSettings.theme, baseTheme: preferredBaseTheme, accentColor: currentColors?.color, bubbleColors: currentColors?.customBubbleColors ?? [], wallpaper: currentColors?.wallpaper, baseColor: currentColors?.baseColor, serviceBackgroundColor: defaultServiceBackgroundColor) ?? defaultPresentationTheme } else { lightTheme = presentationData.theme lightWallpaper = presentationData.chatWallpaper @@ -5905,7 +5928,14 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G let effectiveColors = themeSettings.themeSpecificAccentColors[automaticTheme.index] let themeSpecificWallpaper = (themeSettings.themeSpecificChatWallpapers[coloredThemeIndex(reference: automaticTheme, accentColor: effectiveColors)] ?? themeSettings.themeSpecificChatWallpapers[automaticTheme.index]) - darkTheme = makePresentationTheme(mediaBox: accountManager.mediaBox, themeReference: automaticTheme, accentColor: effectiveColors?.color, bubbleColors: effectiveColors?.customBubbleColors ?? [], wallpaper: effectiveColors?.wallpaper, baseColor: effectiveColors?.baseColor, serviceBackgroundColor: defaultServiceBackgroundColor) ?? defaultPresentationTheme + var preferredBaseTheme: TelegramBaseTheme? + if let baseTheme = themeSettings.themePreferredBaseTheme[automaticTheme.index], [.night, .tinted].contains(baseTheme) { + preferredBaseTheme = baseTheme + } else { + preferredBaseTheme = .night + } + + darkTheme = makePresentationTheme(mediaBox: accountManager.mediaBox, themeReference: automaticTheme, baseTheme: preferredBaseTheme, accentColor: effectiveColors?.color, bubbleColors: effectiveColors?.customBubbleColors ?? [], wallpaper: effectiveColors?.wallpaper, baseColor: effectiveColors?.baseColor, serviceBackgroundColor: defaultServiceBackgroundColor) ?? defaultPresentationTheme if let themeSpecificWallpaper = themeSpecificWallpaper { darkWallpaper = themeSpecificWallpaper @@ -5944,7 +5974,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G presentationData = presentationData.withUpdated(chatWallpaper: chatWallpaper) } - let isFirstTime = !strongSelf.didSetPresentationData strongSelf.presentationData = presentationData strongSelf.didSetPresentationData = true @@ -14314,7 +14343,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G return } - let tooltipScreen = TooltipScreen(account: self.context.account, text: solution.text, textEntities: solution.entities, icon: .info, location: .top, shouldDismissOnTouch: { point in + let tooltipScreen = TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: solution.text, textEntities: solution.entities, icon: .info, location: .top, shouldDismissOnTouch: { point in return .ignore }, openActiveTextItem: { [weak self] item, action in guard let strongSelf = self else { @@ -14407,7 +14436,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G return } - let tooltipScreen = TooltipScreen(account: self.context.account, text: psaText, textEntities: psaEntities, icon: .info, location: .top, displayDuration: .custom(10.0), shouldDismissOnTouch: { point in + let tooltipScreen = TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: psaText, textEntities: psaEntities, icon: .info, location: .top, displayDuration: .custom(10.0), shouldDismissOnTouch: { point in return .ignore }, openActiveTextItem: { [weak self] item, action in guard let strongSelf = self else { @@ -14521,7 +14550,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G return } - let tooltipScreen = TooltipScreen(account: self.context.account, text: psaText, textEntities: psaEntities, icon: .info, location: .top, displayDuration: .custom(10.0), shouldDismissOnTouch: { point in + let tooltipScreen = TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: psaText, textEntities: psaEntities, icon: .info, location: .top, displayDuration: .custom(10.0), shouldDismissOnTouch: { point in return .ignore }, openActiveTextItem: { [weak self] item, action in guard let strongSelf = self else { @@ -18508,12 +18537,18 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G let selectedEmoticon: String? = themeEmoticon + var canResetWallpaper = false + if let cachedUserData = strongSelf.peerView?.cachedData as? CachedUserData { + canResetWallpaper = cachedUserData.wallpaper != nil + } + let controller = ChatThemeScreen( context: context, updatedPresentationData: strongSelf.updatedPresentationData, animatedEmojiStickers: animatedEmojiStickers, initiallySelectedEmoticon: selectedEmoticon, peerName: strongSelf.presentationInterfaceState.renderedPeer?.chatMainPeer.flatMap(EnginePeer.init)?.compactDisplayTitle ?? "", + canResetWallpaper: canResetWallpaper, previewTheme: { [weak self] emoticon, dark in if let strongSelf = self { strongSelf.presentCrossfadeSnapshot() @@ -18540,54 +18575,47 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } } - var canDelete = false - if let cachedUserData = strongSelf.peerView?.cachedData as? CachedUserData { - canDelete = cachedUserData.wallpaper != nil - } - let controller = wallpaperMediaPickerController( - context: strongSelf.context, - updatedPresentationData: strongSelf.updatedPresentationData, - peer: EnginePeer(peer), - canDelete: canDelete, - completion: { asset in - guard let strongSelf = self else { - return - } - let controller = WallpaperGalleryController(context: strongSelf.context, source: .asset(asset), mode: .peer(EnginePeer(peer), false)) - controller.navigationPresentation = .modal - controller.apply = { [weak self] wallpaper, options, cropRect, brightness in - if let strongSelf = self { - uploadCustomPeerWallpaper(context: strongSelf.context, wallpaper: wallpaper, mode: options, cropRect: cropRect, brightness: brightness, peerId: peerId, completion: { - dismissControllers() - }) + var openWallpaperPickerImpl: (() -> Void)? + let openWallpaperPicker = { + let controller = wallpaperMediaPickerController( + context: strongSelf.context, + updatedPresentationData: strongSelf.updatedPresentationData, + peer: EnginePeer(peer), + completion: { asset in + guard let strongSelf = self else { + return } + let controller = WallpaperGalleryController(context: strongSelf.context, source: .asset(asset), mode: .peer(EnginePeer(peer), false)) + controller.navigationPresentation = .modal + controller.apply = { [weak self] wallpaper, options, cropRect, brightness in + if let strongSelf = self { + uploadCustomPeerWallpaper(context: strongSelf.context, wallpaper: wallpaper, mode: options, cropRect: cropRect, brightness: brightness, peerId: peerId, completion: { + dismissControllers() + }) + } + } + strongSelf.push(controller) + }, + openColors: { [weak self] in + guard let strongSelf = self else { + return + } + let controller = standaloneColorPickerController(context: strongSelf.context, peer: EnginePeer(peer), push: { [weak self] controller in + if let strongSelf = self { + strongSelf.push(controller) + } + }, openGallery: { + openWallpaperPickerImpl?() + }) + controller.navigationPresentation = .flatModal + strongSelf.push(controller) } - strongSelf.push(controller) - } - ) - controller.navigationPresentation = .flatModal - strongSelf.push(controller) - }, - changeColor: { - guard let strongSelf = self else { - return + ) + controller.navigationPresentation = .flatModal + strongSelf.push(controller) } - if let themeController = strongSelf.themeScreen { - strongSelf.themeScreen = nil - themeController.dimTapped() - } - - var canDelete = false - if let cachedUserData = strongSelf.peerView?.cachedData as? CachedUserData { - canDelete = cachedUserData.wallpaper != nil - } - let controller = standaloneColorPickerController(context: strongSelf.context, peer: EnginePeer(peer), canDelete: canDelete, push: { [weak self] controller in - if let strongSelf = self { - strongSelf.push(controller) - } - }) - controller.navigationPresentation = .flatModal - strongSelf.push(controller) + openWallpaperPickerImpl = openWallpaperPicker + openWallpaperPicker() }, completion: { [weak self] emoticon in guard let strongSelf = self, let peerId else { diff --git a/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift b/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift index a695150d1c..aa7835459d 100644 --- a/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift @@ -1483,7 +1483,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate { tooltipController.location = .point(location, .bottom) } } else { - let controller = TooltipScreen(account: context.account, text: interfaceState.strings.Bot_TapToUse, icon: .downArrows, location: .point(location, .bottom), displayDuration: .infinite, shouldDismissOnTouch: { _ in + let controller = TooltipScreen(account: context.account, sharedContext: context.sharedContext, text: interfaceState.strings.Bot_TapToUse, icon: .downArrows, location: .point(location, .bottom), displayDuration: .infinite, shouldDismissOnTouch: { _ in return .ignore }) controller.alwaysVisible = true diff --git a/submodules/TelegramUI/Sources/ChatThemeScreen.swift b/submodules/TelegramUI/Sources/ChatThemeScreen.swift index dd015c8b58..ae3a1955fb 100644 --- a/submodules/TelegramUI/Sources/ChatThemeScreen.swift +++ b/submodules/TelegramUI/Sources/ChatThemeScreen.swift @@ -554,9 +554,9 @@ final class ChatThemeScreen: ViewController { private let animatedEmojiStickers: [String: [StickerPackItem]] private let initiallySelectedEmoticon: String? private let peerName: String + let canResetWallpaper: Bool private let previewTheme: (String?, Bool?) -> Void fileprivate let changeWallpaper: () -> Void - fileprivate let changeColor: () -> Void private let completion: (String?) -> Void private var presentationData: PresentationData @@ -578,9 +578,9 @@ final class ChatThemeScreen: ViewController { animatedEmojiStickers: [String: [StickerPackItem]], initiallySelectedEmoticon: String?, peerName: String, + canResetWallpaper: Bool, previewTheme: @escaping (String?, Bool?) -> Void, changeWallpaper: @escaping () -> Void, - changeColor: @escaping () -> Void, completion: @escaping (String?) -> Void ) { self.context = context @@ -588,9 +588,9 @@ final class ChatThemeScreen: ViewController { self.animatedEmojiStickers = animatedEmojiStickers self.initiallySelectedEmoticon = initiallySelectedEmoticon self.peerName = peerName + self.canResetWallpaper = canResetWallpaper self.previewTheme = previewTheme self.changeWallpaper = changeWallpaper - self.changeColor = changeColor self.completion = completion super.init(navigationBarPresentationData: nil) @@ -1013,18 +1013,22 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega } private func updateButtons() { + let canResetWallpaper = self.controller?.canResetWallpaper ?? false + let doneButtonTitle: String let otherButtonTitle: String var accentButtonTheme = true + var destructiveOtherButton = false if self.selectedEmoticon == self.initiallySelectedEmoticon { doneButtonTitle = self.presentationData.strings.Conversation_Theme_SetPhotoWallpaper - otherButtonTitle = self.presentationData.strings.Conversation_Theme_SetColorWallpaper + otherButtonTitle = canResetWallpaper ? self.presentationData.strings.Conversation_Theme_ResetWallpaper : self.presentationData.strings.Common_Cancel accentButtonTheme = false + destructiveOtherButton = canResetWallpaper } else if self.selectedEmoticon == nil && self.initiallySelectedEmoticon != nil { doneButtonTitle = self.presentationData.strings.Conversation_Theme_Reset otherButtonTitle = self.presentationData.strings.Conversation_Theme_OtherOptions } else { - doneButtonTitle = self.presentationData.strings.Conversation_Theme_Apply + doneButtonTitle = self.presentationData.strings.Conversation_Theme_ApplyBackground otherButtonTitle = self.presentationData.strings.Conversation_Theme_OtherOptions } @@ -1040,7 +1044,7 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega } self.doneButton.updateTheme(buttonTheme) - self.otherButton.setTitle(otherButtonTitle, with: Font.regular(17.0), with: self.presentationData.theme.actionSheet.controlAccentColor, for: .normal) + self.otherButton.setTitle(otherButtonTitle, with: Font.regular(17.0), with: destructiveOtherButton ? self.presentationData.theme.actionSheet.destructiveActionTextColor : self.presentationData.theme.actionSheet.controlAccentColor, for: .normal) } private var switchThemeIconAnimator: DisplayLinkAnimator? @@ -1102,7 +1106,11 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega if self.selectedEmoticon != self.initiallySelectedEmoticon { self.setEmoticon(self.initiallySelectedEmoticon) } else { - self.controller?.changeColor() + if self.controller?.canResetWallpaper == true { + + } else { + self.cancelButtonPressed() + } } } @@ -1229,7 +1237,7 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega if let strongSelf = self, count < 2 && currentTimestamp > timestamp + 24 * 60 * 60 { strongSelf.displayedPreviewTooltip = true - strongSelf.present?(TooltipScreen(account: strongSelf.context.account, text: isDark ? strongSelf.presentationData.strings.Conversation_Theme_PreviewLight(strongSelf.peerName).string : strongSelf.presentationData.strings.Conversation_Theme_PreviewDark(strongSelf.peerName).string, style: .default, icon: nil, location: .point(frame.offsetBy(dx: 3.0, dy: 6.0), .bottom), displayDuration: .custom(3.0), inset: 3.0, shouldDismissOnTouch: { _ in + strongSelf.present?(TooltipScreen(account: strongSelf.context.account, sharedContext: strongSelf.context.sharedContext, text: isDark ? strongSelf.presentationData.strings.Conversation_Theme_PreviewLight(strongSelf.peerName).string : strongSelf.presentationData.strings.Conversation_Theme_PreviewDark(strongSelf.peerName).string, style: .default, icon: nil, location: .point(frame.offsetBy(dx: 3.0, dy: 6.0), .bottom), displayDuration: .custom(3.0), inset: 3.0, shouldDismissOnTouch: { _ in return .dismiss(consume: false) })) diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift index 3ae82617db..afc7f249cf 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift @@ -8467,7 +8467,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate return } let buttonFrame = buttonNode.view.convert(buttonNode.bounds, to: self.view) - controller.present(TooltipScreen(account: self.context.account, text: self.presentationData.strings.SharedMedia_CalendarTooltip, style: .default, icon: .none, location: .point(buttonFrame.insetBy(dx: 0.0, dy: 5.0), .top), shouldDismissOnTouch: { point in + controller.present(TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: self.presentationData.strings.SharedMedia_CalendarTooltip, style: .default, icon: .none, location: .point(buttonFrame.insetBy(dx: 0.0, dy: 5.0), .top), shouldDismissOnTouch: { point in return .dismiss(consume: false) }), in: .current) } diff --git a/submodules/TooltipUI/Sources/TooltipScreen.swift b/submodules/TooltipUI/Sources/TooltipScreen.swift index 0d0b017547..36e6eaacc7 100644 --- a/submodules/TooltipUI/Sources/TooltipScreen.swift +++ b/submodules/TooltipUI/Sources/TooltipScreen.swift @@ -11,6 +11,7 @@ import TelegramCore import TextFormat import Postbox import UrlEscaping +import AccountContext public protocol TooltipCustomContentNode: ASDisplayNode { func animateIn() @@ -127,12 +128,11 @@ private final class TooltipScreenNode: ViewControllerTracingNode { private let backgroundContainerNode: ASDisplayNode private let backgroundClipNode: ASDisplayNode private let backgroundMaskNode: ASDisplayNode - private var effectView: UIView? + private var effectNode: NavigationBackgroundNode? private var gradientNode: ASDisplayNode? private var arrowGradientNode: ASDisplayNode? private let arrowNode: ASImageNode private let arrowContainer: ASDisplayNode - private var arrowEffectView: UIView? private let animatedStickerNode: AnimatedStickerNode private var downArrowsNode: DownArrowsIconNode? private let textNode: ImmediateTextNode @@ -143,7 +143,7 @@ private final class TooltipScreenNode: ViewControllerTracingNode { private var validLayout: ContainerViewLayout? - init(account: Account, text: String, textEntities: [MessageTextEntity], style: TooltipScreen.Style, icon: TooltipScreen.Icon?, customContentNode: TooltipCustomContentNode? = nil, location: TooltipScreen.Location, displayDuration: TooltipScreen.DisplayDuration, inset: CGFloat = 13.0, shouldDismissOnTouch: @escaping (CGPoint) -> TooltipScreen.DismissOnTouch, requestDismiss: @escaping () -> Void, openActiveTextItem: ((TooltipActiveTextItem, TooltipActiveTextAction) -> Void)?) { + init(account: Account, sharedContext: SharedAccountContext, text: String, textEntities: [MessageTextEntity], style: TooltipScreen.Style, icon: TooltipScreen.Icon?, customContentNode: TooltipCustomContentNode? = nil, location: TooltipScreen.Location, displayDuration: TooltipScreen.DisplayDuration, inset: CGFloat = 13.0, shouldDismissOnTouch: @escaping (CGPoint) -> TooltipScreen.DismissOnTouch, requestDismiss: @escaping () -> Void, openActiveTextItem: ((TooltipActiveTextItem, TooltipActiveTextAction) -> Void)?) { self.tooltipStyle = style self.icon = icon self.customContentNode = customContentNode @@ -210,9 +210,16 @@ private final class TooltipScreenNode: ViewControllerTracingNode { self.arrowContainer = ASDisplayNode() + let theme = sharedContext.currentPresentationData.with { $0 }.theme let fontSize: CGFloat if case .top = location { - self.effectView = UIVisualEffectView(effect: UIBlurEffect(style: .dark)) + let backgroundColor: UIColor + if theme.overallDarkAppearance { + backgroundColor = theme.rootController.navigationBar.blurredBackgroundColor + } else { + backgroundColor = UIColor(rgb: 0x000000, alpha: 0.6) + } + self.effectNode = NavigationBackgroundNode(color: backgroundColor) self.backgroundMaskNode.addSubnode(self.backgroundClipNode) self.backgroundClipNode.clipsToBounds = true if case let .point(_, arrowPosition) = location, case .right = arrowPosition { @@ -258,20 +265,28 @@ private final class TooltipScreenNode: ViewControllerTracingNode { maskLayer.frame = CGRect(origin: CGPoint(), size: arrowSize) self.arrowContainer.layer.mask = maskLayer } else { - let effect: UIBlurEffect - if case .light = style { - effect = UIBlurEffect(style: .light) + var enableSaturation = true + let backgroundColor: UIColor + if case let .customBlur(color) = style { + backgroundColor = color + enableSaturation = false + } else if case .light = style { + backgroundColor = theme.rootController.navigationBar.blurredBackgroundColor } else { - effect = UIBlurEffect(style: .dark) + if theme.overallDarkAppearance { + backgroundColor = theme.rootController.navigationBar.blurredBackgroundColor + } else { + backgroundColor = UIColor(rgb: 0x000000, alpha: 0.6) + } } - self.effectView = UIVisualEffectView(effect: effect) + self.effectNode = NavigationBackgroundNode(color: backgroundColor, enableBlur: true, enableSaturation: enableSaturation) self.backgroundMaskNode.addSubnode(self.backgroundClipNode) self.backgroundClipNode.clipsToBounds = true if case let .point(_, arrowPosition) = location, case .right = arrowPosition { self.backgroundClipNode.cornerRadius = 8.5 } else { - self.backgroundClipNode.cornerRadius = 14.0 + self.backgroundClipNode.cornerRadius = 12.5 } if #available(iOS 13.0, *) { self.backgroundClipNode.layer.cornerCurve = .continuous @@ -318,8 +333,8 @@ private final class TooltipScreenNode: ViewControllerTracingNode { if let gradientNode = self.gradientNode { self.backgroundContainerNode.addSubnode(gradientNode) self.containerNode.addSubnode(self.arrowContainer) - } else if let effectView = self.effectView { - self.backgroundContainerNode.view.addSubview(effectView) + } else if let effectNode = self.effectNode { + self.backgroundContainerNode.addSubnode(effectNode) self.backgroundContainerNode.layer.mask = self.backgroundMaskNode.layer } self.containerNode.addSubnode(self.textNode) @@ -430,7 +445,7 @@ private final class TooltipScreenNode: ViewControllerTracingNode { let backgroundHeight: CGFloat switch self.tooltipStyle { - case .default, .gradient: + case .default, .gradient, .customBlur: backgroundHeight = max(animationSize.height, textSize.height) + contentVerticalInset * 2.0 case .light: backgroundHeight = max(28.0, max(animationSize.height, textSize.height) + 4.0 * 2.0) @@ -472,8 +487,10 @@ private final class TooltipScreenNode: ViewControllerTracingNode { transition.updateFrame(node: self.backgroundMaskNode, frame: CGRect(origin: CGPoint(), size: backgroundFrame.size).insetBy(dx: -10.0, dy: -10.0)) transition.updateFrame(node: self.backgroundClipNode, frame: CGRect(origin: CGPoint(x: 10.0, y: 10.0), size: backgroundFrame.size)) - if let effectView = self.effectView { - transition.updateFrame(view: effectView, frame: CGRect(origin: CGPoint(), size: backgroundFrame.size).insetBy(dx: -10.0, dy: -10.0)) + if let effectNode = self.effectNode { + let effectFrame = CGRect(origin: CGPoint(), size: backgroundFrame.size).insetBy(dx: -10.0, dy: -10.0) + transition.updateFrame(node: effectNode, frame: effectFrame) + effectNode.update(size: effectFrame.size, transition: transition) } if let gradientNode = self.gradientNode { transition.updateFrame(node: gradientNode, frame: CGRect(origin: CGPoint(), size: backgroundFrame.size)) @@ -501,7 +518,6 @@ private final class TooltipScreenNode: ViewControllerTracingNode { let arrowBounds = CGRect(origin: CGPoint(), size: arrowSize) self.arrowNode.frame = arrowBounds - self.arrowEffectView?.frame = arrowBounds self.arrowGradientNode?.frame = CGRect(origin: CGPoint(x: -arrowFrame.minX + backgroundFrame.minX, y: 0.0), size: backgroundFrame.size) case .right: arrowFrame = CGRect(origin: CGPoint(x: backgroundFrame.width + arrowSize.height, y: rect.midY), size: CGSize(width: arrowSize.height, height: arrowSize.width)) @@ -512,12 +528,10 @@ private final class TooltipScreenNode: ViewControllerTracingNode { let arrowBounds = CGRect(origin: .zero, size: arrowSize) self.arrowNode.frame = arrowBounds - self.arrowEffectView?.frame = arrowBounds self.arrowGradientNode?.frame = arrowBounds } } else { self.arrowNode.isHidden = true - self.arrowEffectView?.isHidden = true } transition.updateFrame(node: self.textNode, frame: CGRect(origin: CGPoint(x: contentInset + animationSize.width + animationSpacing, y: floor((backgroundHeight - textSize.height) / 2.0)), size: textSize)) @@ -672,10 +686,12 @@ public final class TooltipScreen: ViewController { public enum Style { case `default` case light + case customBlur(UIColor) case gradient(UIColor, UIColor) } private let account: Account + private let sharedContext: SharedAccountContext public let text: String public let textEntities: [MessageTextEntity] private let style: TooltipScreen.Style @@ -707,8 +723,9 @@ public final class TooltipScreen: ViewController { public var alwaysVisible = false - public init(account: Account, text: String, textEntities: [MessageTextEntity] = [], style: TooltipScreen.Style = .default, icon: TooltipScreen.Icon?, customContentNode: TooltipCustomContentNode? = nil, location: TooltipScreen.Location, displayDuration: DisplayDuration = .default, inset: CGFloat = 13.0, shouldDismissOnTouch: @escaping (CGPoint) -> TooltipScreen.DismissOnTouch, openActiveTextItem: ((TooltipActiveTextItem, TooltipActiveTextAction) -> Void)? = nil) { + public init(account: Account, sharedContext: SharedAccountContext, text: String, textEntities: [MessageTextEntity] = [], style: TooltipScreen.Style = .default, icon: TooltipScreen.Icon?, customContentNode: TooltipCustomContentNode? = nil, location: TooltipScreen.Location, displayDuration: DisplayDuration = .default, inset: CGFloat = 13.0, shouldDismissOnTouch: @escaping (CGPoint) -> TooltipScreen.DismissOnTouch, openActiveTextItem: ((TooltipActiveTextItem, TooltipActiveTextAction) -> Void)? = nil) { self.account = account + self.sharedContext = sharedContext self.text = text self.textEntities = textEntities self.style = style @@ -776,7 +793,7 @@ public final class TooltipScreen: ViewController { } override public func loadDisplayNode() { - self.displayNode = TooltipScreenNode(account: self.account, text: self.text, textEntities: self.textEntities, style: self.style, icon: self.icon, customContentNode: self.customContentNode, location: self.location, displayDuration: self.displayDuration, inset: self.inset, shouldDismissOnTouch: self.shouldDismissOnTouch, requestDismiss: { [weak self] in + self.displayNode = TooltipScreenNode(account: self.account, sharedContext: self.sharedContext, text: self.text, textEntities: self.textEntities, style: self.style, icon: self.icon, customContentNode: self.customContentNode, location: self.location, displayDuration: self.displayDuration, inset: self.inset, shouldDismissOnTouch: self.shouldDismissOnTouch, requestDismiss: { [weak self] in guard let strongSelf = self else { return } diff --git a/submodules/WallpaperBackgroundNode/Sources/WallpaperBackgroundNode.swift b/submodules/WallpaperBackgroundNode/Sources/WallpaperBackgroundNode.swift index 0095b1c454..af8c9bc9f0 100644 --- a/submodules/WallpaperBackgroundNode/Sources/WallpaperBackgroundNode.swift +++ b/submodules/WallpaperBackgroundNode/Sources/WallpaperBackgroundNode.swift @@ -743,6 +743,7 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode private var gradientBackgroundNode: GradientBackgroundNode? private var outgoingBubbleGradientBackgroundNode: GradientBackgroundNode? private let patternImageLayer: EffectImageLayer + private let dimLayer: SimpleLayer private var isGeneratingPatternImage: Bool = false private let bakedBackgroundView: UIImageView @@ -862,6 +863,9 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode self.bakedBackgroundView = UIImageView() self.bakedBackgroundView.isHidden = true + self.dimLayer = SimpleLayer() + self.dimLayer.backgroundColor = UIColor.black.cgColor + super.init() if #available(iOS 12.0, *) { @@ -885,6 +889,8 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode self.contentNode.frame = self.bounds self.addSubnode(self.contentNode) self.layer.addSublayer(self.patternImageLayer) + + self.layer.addSublayer(self.dimLayer) } deinit { @@ -892,6 +898,19 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode self.wallpaperDisposable.dispose() self.imageDisposable.dispose() } + + private func updateDimming() { + guard let wallpaper = self.wallpaper, let theme = self.bubbleTheme else { + return + } + var dimAlpha: Float = 0.0 + if case let .file(file) = wallpaper, !file.isPattern { + if let intensity = file.settings.intensity, intensity < 100, theme.overallDarkAppearance == true { + dimAlpha = 1.0 - max(0.0, min(1.0, Float(intensity) / 100.0)) + } + } + self.dimLayer.opacity = dimAlpha + } func update(wallpaper: TelegramWallpaper) { if self.wallpaper == wallpaper { @@ -915,7 +934,7 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode gradientColors = file.settings.colors gradientAngle = file.settings.rotation ?? 0 } - + var scheduleLoopingEvent = false if gradientColors.count >= 3 { let mappedColors = gradientColors.map { color -> UIColor in @@ -1032,6 +1051,8 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode self.animateEvent(transition: .animated(duration: 0.7, curve: .linear), extendAnimation: false) } } + + self.updateDimming() } func _internalUpdateIsSettingUpWallpaper() { @@ -1304,6 +1325,8 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode transition.updateFrame(node: outgoingBackgroundNode, frame: CGRect(origin: CGPoint(), size: size)) outgoingBackgroundNode.update(rect: CGRect(origin: CGPoint(), size: size), within: size, transition: transition) } + + transition.updateFrame(layer: self.dimLayer, frame: CGRect(origin: CGPoint(), size: size)) self.loadPatternForSizeIfNeeded(size: size, displayMode: displayMode, transition: transition) @@ -1378,6 +1401,7 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode } self.updateBubbles() + self.updateDimming() } }