Chat wallpaper improvements

This commit is contained in:
Ilya Laktyushin 2023-04-08 20:10:49 +04:00
parent 8e6ed4c4d0
commit 1e2ed2d2f4
21 changed files with 518 additions and 194 deletions

View File

@ -9149,7 +9149,7 @@ Sorry for the inconvenience.";
"WallpaperPreview.ChatBottomText" = "Enjoy the view."; "WallpaperPreview.ChatBottomText" = "Enjoy the view.";
"Conversation.Theme.SetPhotoWallpaper" = "Choose Background from Photos"; "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.OtherOptions" = "Other Options...";
"Conversation.Theme.ChooseWallpaperTitle" = "Choose Background"; "Conversation.Theme.ChooseWallpaperTitle" = "Choose Background";
@ -9161,3 +9161,8 @@ Sorry for the inconvenience.";
"WebApp.LaunchMoreInfo" = "More about this bot"; "WebApp.LaunchMoreInfo" = "More about this bot";
"WebApp.LaunchConfirmation" = "To launch this web app, you will connect to its website."; "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";

View File

@ -1370,7 +1370,7 @@ public final class CalendarMessageScreen: ViewController {
if self.selectionState?.dayRange == nil { if self.selectionState?.dayRange == nil {
if let selectionToolbarNode = self.selectionToolbarNode { if let selectionToolbarNode = self.selectionToolbarNode {
let toolbarFrame = selectionToolbarNode.view.convert(selectionToolbarNode.bounds, to: self.view) 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) return .dismiss(consume: false)
}), in: .current) }), in: .current)
} }

View File

@ -2079,7 +2079,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
let location = CGRect(origin: CGPoint(x: absoluteFrame.midX, y: absoluteFrame.minY - 8.0), size: CGSize()) 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 { guard let strongSelf = self, let parentController = strongSelf.parent as? TabBarController else {
return .dismiss(consume: false) return .dismiss(consume: false)
} }

View File

@ -829,7 +829,7 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan
text = strongSelf.presentationData.strings.Location_ProximityTip(EnginePeer(peer).compactDisplayTitle).string 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) return .dismiss(consume: false)
})) }))
}) })

View File

@ -2010,18 +2010,18 @@ public func wallpaperMediaPickerController(
context: AccountContext, context: AccountContext,
updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil,
peer: EnginePeer, peer: EnginePeer,
canDelete: Bool, completion: @escaping (PHAsset) -> Void = { _ in },
completion: @escaping (PHAsset) -> Void = { _ in } openColors: @escaping () -> Void
) -> ViewController { ) -> ViewController {
let controller = AttachmentController(context: context, updatedPresentationData: updatedPresentationData, chatLocation: nil, buttons: [.standalone], initialButton: .standalone, fromMenu: false, hasTextInput: false, makeEntityInputView: { let controller = AttachmentController(context: context, updatedPresentationData: updatedPresentationData, chatLocation: nil, buttons: [.standalone], initialButton: .standalone, fromMenu: false, hasTextInput: false, makeEntityInputView: {
return nil return nil
}) })
controller.requestController = { [weak controller] _, present in controller.requestController = { [weak controller] _, present in
let presentationData = context.sharedContext.currentPresentationData.with { $0 } 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 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: {
let _ = context.engine.themes.setChatWallpaper(peerId: peer.id, wallpaper: nil).start()
controller?.dismiss(animated: true) controller?.dismiss(animated: true)
} : nil) openColors()
})
mediaPickerController.customSelection = completion mediaPickerController.customSelection = completion
present(mediaPickerController, mediaPickerController.mediaPickerContext) present(mediaPickerController, mediaPickerController.mediaPickerContext)
} }

View File

@ -669,12 +669,8 @@ private func selectivePrivacySettingsControllerEntries(presentationData: Present
entries.append(.everybody(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenEverybody, state.setting == .everybody)) entries.append(.everybody(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenEverybody, state.setting == .everybody))
entries.append(.contacts(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenContacts, state.setting == .contacts)) entries.append(.contacts(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenContacts, state.setting == .contacts))
switch kind { entries.append(.nobody(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenNobody, state.setting == .nobody))
case .presence, .voiceCalls, .forwards, .phoneNumber, .voiceMessages, .profilePhoto:
entries.append(.nobody(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenNobody, state.setting == .nobody))
case .groupInvitations:
break
}
let phoneLink = "https://t.me/+\(phoneNumber)" let phoneLink = "https://t.me/+\(phoneNumber)"
if let settingInfoText = settingInfoText { if let settingInfoText = settingInfoText {
entries.append(.settingInfo(presentationData.theme, settingInfoText, phoneLink)) entries.append(.settingInfo(presentationData.theme, settingInfoText, phoneLink))

View File

@ -196,7 +196,7 @@ func uploadCustomWallpaper(context: AccountContext, wallpaper: WallpaperGalleryE
}).start() }).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<UIImage, NoError> let imageSignal: Signal<UIImage, NoError>
switch wallpaper { switch wallpaper {
case let .wallpaper(wallpaper, _): case let .wallpaper(wallpaper, _):
@ -279,24 +279,6 @@ public func uploadCustomPeerWallpaper(context: AccountContext, wallpaper: Wallpa
croppedImage = blurredImage(croppedImage, radius: 30.0)! 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 thumbnailDimensions = finalCropRect.size.fitted(CGSize(width: 320.0, height: 320.0))
let thumbnailImage = generateScaledImage(image: croppedImage, size: thumbnailDimensions, scale: 1.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.sharedContext.accountManager.mediaBox.storeResourceData(resource.id, data: data, synchronous: true)
context.account.postbox.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 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 let _ = context.account.postbox.transaction({ transaction in
@ -326,7 +313,7 @@ public func uploadCustomPeerWallpaper(context: AccountContext, wallpaper: Wallpa
completion() 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 .complete(wallpaper) = status {
if case let .file(file) = wallpaper { if case let .file(file) = wallpaper {
context.account.postbox.mediaBox.copyResourceData(from: resource.id, to: file.file.resource.id, synchronous: true) context.account.postbox.mediaBox.copyResourceData(from: resource.id, to: file.file.resource.id, synchronous: true)

View File

@ -11,8 +11,8 @@ import TelegramUIPreferences
import AccountContext import AccountContext
import AttachmentUI import AttachmentUI
private func availableGradients(theme: PresentationTheme) -> [[UInt32]] { private func availableGradients(dark: Bool) -> [[UInt32]] {
if theme.overallDarkAppearance { if dark {
return [ return [
[0x1e3557, 0x151a36, 0x1c4352, 0x2a4541] as [UInt32], [0x1e3557, 0x151a36, 0x1c4352, 0x2a4541] as [UInt32],
[0x1d223f, 0x1d1832, 0x1b2943, 0x141631] as [UInt32], [0x1d223f, 0x1d1832, 0x1b2943, 0x141631] as [UInt32],
@ -39,8 +39,8 @@ private func availableGradients(theme: PresentationTheme) -> [[UInt32]] {
} }
} }
private func availableColors(theme: PresentationTheme) -> [UInt32] { private func availableColors(dark: Bool) -> [UInt32] {
if theme.overallDarkAppearance { if dark {
return [ return [
0x1D2D3C, 0x1D2D3C,
0x111B26, 0x111B26,
@ -150,6 +150,7 @@ public final class ThemeColorsGridController: ViewController, AttachmentContaina
var pushController: (ViewController) -> Void = { _ in } var pushController: (ViewController) -> Void = { _ in }
var dismissControllers: (() -> Void)? var dismissControllers: (() -> Void)?
var openGallery: (() -> Void)?
public init(context: AccountContext, mode: Mode = .default, canDelete: Bool = false) { public init(context: AccountContext, mode: Mode = .default, canDelete: Bool = false) {
self.context = context self.context = context
@ -192,9 +193,7 @@ public final class ThemeColorsGridController: ViewController, AttachmentContaina
self?.push(controller) self?.push(controller)
} }
if canDelete { 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)))
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)))
}
} }
required public init(coder aDecoder: NSCoder) { required public init(coder aDecoder: NSCoder) {
@ -270,7 +269,11 @@ public final class ThemeColorsGridController: ViewController, AttachmentContaina
} }
public override func loadDisplayNode() { 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) self?.pushController(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 {
@ -327,12 +330,8 @@ public final class ThemeColorsGridController: ViewController, AttachmentContaina
} }
@objc fileprivate func mainButtonPressed() { @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.dismiss(animated: true)
self.openGallery?()
} }
public var requestAttachmentMenuExpansion: () -> Void = {} public var requestAttachmentMenuExpansion: () -> Void = {}
@ -385,18 +384,25 @@ private final class ThemeColorsGridContext: AttachmentMediaPickerContext {
} }
public func standaloneColorPickerController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peer: EnginePeer, canDelete: Bool, push: @escaping (ViewController) -> Void) -> ViewController { public func standaloneColorPickerController(
context: AccountContext,
updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = 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: { let controller = AttachmentController(context: context, updatedPresentationData: updatedPresentationData, chatLocation: nil, buttons: [.standalone], initialButton: .standalone, fromMenu: false, hasTextInput: false, makeEntityInputView: {
return nil return nil
}) })
controller.requestController = { _, present in 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 colorPickerController.pushController = { controller in
push(controller) push(controller)
} }
colorPickerController.dismissControllers = { [weak controller] in colorPickerController.dismissControllers = { [weak controller] in
controller?.dismiss(animated: true) controller?.dismiss(animated: true)
} }
colorPickerController.openGallery = openGallery
present(colorPickerController, colorPickerController.mediaPickerContext) present(colorPickerController, colorPickerController.mediaPickerContext)
} }
return controller return controller

View File

@ -19,6 +19,8 @@ import WallpaperResources
import AppBundle import AppBundle
import WallpaperBackgroundNode import WallpaperBackgroundNode
import TextFormat import TextFormat
import TooltipUI
import TelegramNotices
struct WallpaperGalleryItemArguments { struct WallpaperGalleryItemArguments {
let colorPreview: Bool let colorPreview: Bool
@ -83,7 +85,7 @@ private func reference(for resource: MediaResource, media: Media, message: Messa
final class WallpaperGalleryItemNode: GalleryItemNode { final class WallpaperGalleryItemNode: GalleryItemNode {
private let context: AccountContext private let context: AccountContext
private let presentationData: PresentationData private var presentationData: PresentationData
var entry: WallpaperGalleryEntry? var entry: WallpaperGalleryEntry?
var source: WallpaperListSource? var source: WallpaperListSource?
@ -102,6 +104,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
private let cancelButtonNode: WallpaperNavigationButtonNode private let cancelButtonNode: WallpaperNavigationButtonNode
private let shareButtonNode: WallpaperNavigationButtonNode private let shareButtonNode: WallpaperNavigationButtonNode
private let dayNightButtonNode: WallpaperNavigationButtonNode
private let blurButtonNode: WallpaperOptionButtonNode private let blurButtonNode: WallpaperOptionButtonNode
private let motionButtonNode: WallpaperOptionButtonNode private let motionButtonNode: WallpaperOptionButtonNode
@ -139,10 +142,16 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
private var isReadyDisposable: Disposable? private var isReadyDisposable: Disposable?
private var isDarkAppearance: Bool = false
private var didChangeAppearance: Bool = false
private var darkAppearanceIntensity: CGFloat = 0.8
init(context: AccountContext) { init(context: AccountContext) {
self.context = context self.context = context
self.presentationData = context.sharedContext.currentPresentationData.with { $0 } self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.isDarkAppearance = self.presentationData.theme.overallDarkAppearance
self.wrapperNode = ASDisplayNode() self.wrapperNode = ASDisplayNode()
self.imageNode = TransformImageNode() self.imageNode = TransformImageNode()
self.imageNode.contentAnimations = .subsequentUpdates self.imageNode.contentAnimations = .subsequentUpdates
@ -154,6 +163,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
self.blurredNode = BlurredImageNode() self.blurredNode = BlurredImageNode()
self.brightnessNode = ASDisplayNode() self.brightnessNode = ASDisplayNode()
self.brightnessNode.alpha = 0.0
self.messagesContainerNode = ASDisplayNode() self.messagesContainerNode = ASDisplayNode()
self.messagesContainerNode.transform = CATransform3DMakeScale(1.0, -1.0, 1.0) 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)) self.serviceBackgroundNode = NavigationBackgroundNode(color: UIColor(rgb: 0x333333, alpha: 0.33))
var sliderValueChangedImpl: ((CGFloat) -> Void)? 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) sliderValueChangedImpl?(value)
}) })
self.colorsButtonNode = WallpaperOptionButtonNode(title: self.presentationData.strings.WallpaperPreview_WallpaperColors, value: .colors(false, [.clear])) 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.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.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 self.playButtonPlayImage = generateImage(CGSize(width: 48.0, height: 48.0), rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size)) context.clear(CGRect(origin: CGPoint(), size: size))
@ -242,6 +254,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
self.addSubnode(self.sliderNode) self.addSubnode(self.sliderNode)
self.addSubnode(self.cancelButtonNode) self.addSubnode(self.cancelButtonNode)
self.addSubnode(self.shareButtonNode) self.addSubnode(self.shareButtonNode)
self.addSubnode(self.dayNightButtonNode)
self.imageNode.addSubnode(self.brightnessNode) self.imageNode.addSubnode(self.brightnessNode)
@ -252,22 +265,11 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
self.playButtonNode.addTarget(self, action: #selector(self.togglePlay), forControlEvents: .touchUpInside) self.playButtonNode.addTarget(self, action: #selector(self.togglePlay), forControlEvents: .touchUpInside)
self.cancelButtonNode.addTarget(self, action: #selector(self.cancelPressed), forControlEvents: .touchUpInside) self.cancelButtonNode.addTarget(self, action: #selector(self.cancelPressed), forControlEvents: .touchUpInside)
self.shareButtonNode.addTarget(self, action: #selector(self.actionPressed), 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 sliderValueChangedImpl = { [weak self] value in
if let self { if let self {
let value = (value - 0.5) * 2.0 self.updateIntensity(transition: .immediate)
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
}
} }
} }
} }
@ -297,7 +299,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
} }
switch entry { switch entry {
case .asset, .contextResult: case .asset, .contextResult:
return (self.sliderNode.value - 0.5) * 2.0 return self.sliderNode.value
default: default:
return nil return nil
} }
@ -311,6 +313,53 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
self.action?() 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() { @objc private func cancelPressed() {
self.dismiss() self.dismiss()
} }
@ -329,6 +378,8 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
} }
} }
var showPreviewTooltip = false
if self.entry != entry || self.arguments.colorPreview != previousArguments.colorPreview { if self.entry != entry || self.arguments.colorPreview != previousArguments.colorPreview {
let previousEntry = self.entry let previousEntry = self.entry
self.entry = entry self.entry = entry
@ -357,8 +408,6 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
var isBlurrable = true var isBlurrable = true
self.nativeNode.updateBubbleTheme(bubbleTheme: presentationData.theme, bubbleCorners: presentationData.chatBubbleCorners)
switch entry { switch entry {
case let .wallpaper(wallpaper, _): case let .wallpaper(wallpaper, _):
self.nativeNode.update(wallpaper: wallpaper) self.nativeNode.update(wallpaper: wallpaper)
@ -393,6 +442,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
} }
case .asset: case .asset:
self.nativeNode._internalUpdateIsSettingUpWallpaper() self.nativeNode._internalUpdateIsSettingUpWallpaper()
//self.nativeNode.update(wallpaper: self.presentationData.chatWallpaper)
self.nativeNode.isHidden = true self.nativeNode.isHidden = true
self.patternButtonNode.isSelected = false self.patternButtonNode.isSelected = false
self.playButtonNode.setIcon(self.playButtonRotateImage) self.playButtonNode.setIcon(self.playButtonRotateImage)
@ -402,7 +452,8 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
self.playButtonNode.setIcon(self.playButtonRotateImage) self.playButtonNode.setIcon(self.playButtonRotateImage)
} }
var isEditable = false self.nativeNode.updateBubbleTheme(bubbleTheme: presentationData.theme, bubbleCorners: presentationData.chatBubbleCorners)
var canShare = false var canShare = false
switch entry { switch entry {
case let .wallpaper(wallpaper, message): case let .wallpaper(wallpaper, message):
@ -566,7 +617,6 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
} }
self.cropNode.removeFromSupernode() self.cropNode.removeFromSupernode()
case let .asset(asset): case let .asset(asset):
isEditable = true
let dimensions = CGSize(width: asset.pixelWidth, height: asset.pixelHeight) let dimensions = CGSize(width: asset.pixelWidth, height: asset.pixelHeight)
contentSize = dimensions contentSize = dimensions
displaySize = dimensions.dividedByScreenScale().integralFloor displaySize = dimensions.dividedByScreenScale().integralFloor
@ -576,8 +626,8 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
subtitleSignal = .single(nil) subtitleSignal = .single(nil)
colorSignal = .single(UIColor(rgb: 0x000000, alpha: 0.3)) colorSignal = .single(UIColor(rgb: 0x000000, alpha: 0.3))
self.wrapperNode.addSubnode(self.cropNode) self.wrapperNode.addSubnode(self.cropNode)
showPreviewTooltip = true
case let .contextResult(result): case let .contextResult(result):
isEditable = true
var imageDimensions: CGSize? var imageDimensions: CGSize?
var imageResource: TelegramMediaResource? var imageResource: TelegramMediaResource?
var thumbnailDimensions: CGSize? var thumbnailDimensions: CGSize?
@ -631,11 +681,12 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
colorSignal = .single(UIColor(rgb: 0x000000, alpha: 0.3)) colorSignal = .single(UIColor(rgb: 0x000000, alpha: 0.3))
subtitleSignal = .single(nil) subtitleSignal = .single(nil)
self.wrapperNode.addSubnode(self.cropNode) self.wrapperNode.addSubnode(self.cropNode)
showPreviewTooltip = true
} }
self.contentSize = contentSize self.contentSize = contentSize
self.cancelButtonNode.dark = !isEditable //self.cancelButtonNode.dark = !isEditable
self.shareButtonNode.dark = !isEditable //self.shareButtonNode.dark = !isEditable
self.shareButtonNode.isHidden = !canShare self.shareButtonNode.isHidden = !canShare
if self.cropNode.supernode == nil { if self.cropNode.supernode == nil {
@ -713,6 +764,18 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
self.updateButtonsLayout(layout: layout, offset: CGPoint(), transition: .immediate) self.updateButtonsLayout(layout: layout, offset: CGPoint(), transition: .immediate)
self.updateMessagesLayout(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) { override func screenFrameUpdated(_ frame: CGRect) {
@ -966,7 +1029,9 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
if let source = self.source { if let source = self.source {
switch source { switch source {
case .asset, .contextResult: case .asset, .contextResult:
additionalYOffset -= 44.0 if self.isDarkAppearance {
additionalYOffset -= 44.0
}
default: default:
break break
} }
@ -996,8 +1061,17 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
var playAlpha: CGFloat = 0.0 var playAlpha: CGFloat = 0.0
let sliderSize = CGSize(width: 268.0, height: 30.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 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 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 cancelSize = self.cancelButtonNode.measure(layout.size)
let cancelFrame = CGRect(origin: CGPoint(x: 16.0 + offset.x, y: 16.0), size: cancelSize) 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 blurFrame = leftButtonFrame
motionAlpha = 1.0 motionAlpha = 1.0
motionFrame = rightButtonFrame motionFrame = rightButtonFrame
sliderIsHidden = false dayNightHidden = false
case .contextResult: case .contextResult:
blurAlpha = 1.0 blurAlpha = 1.0
blurFrame = leftButtonFrame blurFrame = leftButtonFrame
motionAlpha = 1.0 motionAlpha = 1.0
motionFrame = rightButtonFrame motionFrame = rightButtonFrame
sliderIsHidden = false dayNightHidden = false
case let .wallpaper(wallpaper, _): case let .wallpaper(wallpaper, _):
switch wallpaper { switch wallpaper {
case .builtin: case .builtin:
@ -1104,12 +1178,16 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
transition.updateAlpha(node: self.playButtonNode, alpha: playAlpha * alpha) transition.updateAlpha(node: self.playButtonNode, alpha: playAlpha * alpha)
transition.updateSublayerTransformScale(node: self.playButtonNode, scale: max(0.1, playAlpha)) 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.updateLayout(size: sliderFrame.size)
self.sliderNode.isHidden = sliderIsHidden
transition.updateFrame(node: self.cancelButtonNode, frame: cancelFrame) transition.updateFrame(node: self.cancelButtonNode, frame: cancelFrame)
transition.updateFrame(node: self.shareButtonNode, frame: shareFrame) 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) { private func updateMessagesLayout(layout: ContainerViewLayout, offset: CGPoint, transition: ContainedViewLayoutTransition) {
@ -1182,7 +1260,9 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
case .asset, .contextResult: case .asset, .contextResult:
topMessageText = presentationData.strings.WallpaperPreview_CropTopText topMessageText = presentationData.strings.WallpaperPreview_CropTopText
bottomMessageText = presentationData.strings.WallpaperPreview_CropBottomText bottomMessageText = presentationData.strings.WallpaperPreview_CropBottomText
bottomInset += 44.0 if self.isDarkAppearance {
bottomInset += 44.0
}
case .customColor: case .customColor:
topMessageText = presentationData.strings.WallpaperPreview_CustomColorTopText topMessageText = presentationData.strings.WallpaperPreview_CustomColorTopText
bottomMessageText = presentationData.strings.WallpaperPreview_CustomColorBottomText 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) 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)) 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.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 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 self.brightnessNode.frame = self.imageNode.bounds
@ -1322,4 +1412,41 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
func animateWallpaperAppeared() { func animateWallpaperAppeared() {
self.nativeNode.animateEvent(transition: .animated(duration: 2.0, curve: .spring), extendAnimation: true) 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()
}
}
})
}
} }

View File

@ -5,6 +5,7 @@ import AsyncDisplayKit
import SwiftSignalKit import SwiftSignalKit
import Postbox import Postbox
import CheckNode import CheckNode
import AnimationUI
enum WallpaperOptionButtonValue { enum WallpaperOptionButtonValue {
case check(Bool) case check(Bool)
@ -93,6 +94,7 @@ final class WallpaperNavigationButtonNode: HighlightTrackingButtonNode {
enum Content { enum Content {
case icon(image: UIImage?, size: CGSize) case icon(image: UIImage?, size: CGSize)
case text(String) case text(String)
case dayNight(isNight: Bool)
} }
var enableSaturation: Bool = false var enableSaturation: Bool = false
@ -115,6 +117,7 @@ final class WallpaperNavigationButtonNode: HighlightTrackingButtonNode {
private var backgroundNode: ASDisplayNode private var backgroundNode: ASDisplayNode
private let iconNode: ASImageNode private let iconNode: ASImageNode
private let textNode: ImmediateTextNode private let textNode: ImmediateTextNode
private var animationNode: AnimationNode?
func setIcon(_ image: UIImage?) { func setIcon(_ image: UIImage?) {
self.iconNode.image = generateTintedImage(image: image, color: .white) self.iconNode.image = generateTintedImage(image: image, color: .white)
@ -141,6 +144,12 @@ final class WallpaperNavigationButtonNode: HighlightTrackingButtonNode {
case let .icon(icon, _): case let .icon(icon, _):
title = "" title = ""
self.iconNode.image = generateTintedImage(image: icon, color: .white) 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() self.textNode = ImmediateTextNode()
@ -152,19 +161,53 @@ final class WallpaperNavigationButtonNode: HighlightTrackingButtonNode {
self.addSubnode(self.iconNode) self.addSubnode(self.iconNode)
self.addSubnode(self.textNode) self.addSubnode(self.textNode)
if let animationNode = self.animationNode {
self.addSubnode(animationNode)
}
self.highligthedChanged = { [weak self] highlighted in self.highligthedChanged = { [weak self] highlighted in
if let strongSelf = self { if let strongSelf = self {
if highlighted { if highlighted {
strongSelf.backgroundNode.layer.removeAnimation(forKey: "opacity") strongSelf.backgroundNode.layer.removeAnimation(forKey: "opacity")
strongSelf.backgroundNode.alpha = 0.4 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 { } else {
strongSelf.backgroundNode.alpha = 1.0 strongSelf.backgroundNode.alpha = 1.0
strongSelf.backgroundNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2) 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) { var buttonColor: UIColor = UIColor(rgb: 0x000000, alpha: 0.3) {
didSet { didSet {
} }
@ -179,6 +222,8 @@ final class WallpaperNavigationButtonNode: HighlightTrackingButtonNode {
return CGSize(width: ceil(size.width) + 16.0, height: 28.0) return CGSize(width: ceil(size.width) + 16.0, height: 28.0)
case let .icon(_, size): case let .icon(_, size):
return 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 { 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) 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) 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 self.validLayout = size
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: .zero, size: 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 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)) let foregroundFrame = CGRect(origin: CGPoint(), size: CGSize(width: value * size.width, height: size.height))
transition.updateFrameAdditive(node: self.foregroundNode, frame: foregroundFrame) transition.updateFrame(node: self.foregroundNode, frame: foregroundFrame)
transition.updateFrameAdditive(node: self.foregroundLightNode, 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) { @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)) self.value = max(self.minValue, min(self.maxValue, self.value + delta))
gestureRecognizer.setTranslation(CGPoint(), in: gestureRecognizer.view) 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) self.hapticFeedback.impact(.soft)
} else if self.value == 1.0 && previousValue != 1.0 { } else if self.value == 1.0 && previousValue != 1.0 {
self.hapticFeedback.impact(.soft) 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 { if abs(previousValue - self.value) >= 0.001 {
self.valueChanged(self.value, false) self.valueChanged(self.value, false)

View File

@ -526,7 +526,7 @@ public final class MediaNavigationAccessoryHeaderNode: ASDisplayNode, UIScrollVi
let _ = (ApplicationSpecificNotice.incrementAudioRateOptionsTip(accountManager: self.context.sharedContext.accountManager) let _ = (ApplicationSpecificNotice.incrementAudioRateOptionsTip(accountManager: self.context.sharedContext.accountManager)
|> deliverOnMainQueue).start(next: { [weak self] value in |> deliverOnMainQueue).start(next: { [weak self] value in
if let strongSelf = self, let controller = strongSelf.getController?(), value == 2 { 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) return .dismiss(consume: false)
}) })
controller.present(tooltipController, in: .window(.root)) controller.present(tooltipController, in: .window(.root))

View File

@ -760,8 +760,8 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
}) else { }) else {
return 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) return .dismiss(consume: false)
})) }))
} }

View File

@ -2310,7 +2310,7 @@ public final class VoiceChatControllerImpl: ViewController, VoiceChatController
} else { } else {
text = presentationData.strings.VoiceChat_RecordingInProgress 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) return .dismiss(consume: true)
}), in: .window(.root)) }), in: .window(.root))
} }
@ -3507,7 +3507,7 @@ public final class VoiceChatControllerImpl: ViewController, VoiceChatController
if !callState.subscribedToScheduled { if !callState.subscribedToScheduled {
let location = self.actionButton.view.convert(self.actionButton.bounds, to: self.view).center 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)) 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) return .dismiss(consume: false)
}), in: .window(.root)) }), in: .window(.root))
} }
@ -6411,7 +6411,7 @@ public final class VoiceChatControllerImpl: ViewController, VoiceChatController
point.origin.y += 32.0 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) return .dismiss(consume: false)
}), in: .window(.root)) }), in: .window(.root))
} }

View File

@ -170,6 +170,8 @@ private enum ApplicationSpecificGlobalNotice: Int32 {
case audioRateOptionsTip = 36 case audioRateOptionsTip = 36
case translationSuggestion = 37 case translationSuggestion = 37
case sendWhenOnlineTip = 38 case sendWhenOnlineTip = 38
case chatWallpaperLightPreviewTip = 39
case chatWallpaperDarkPreviewTip = 40
var key: ValueBoxKey { var key: ValueBoxKey {
let v = ValueBoxKey(length: 4) let v = ValueBoxKey(length: 4)
@ -332,6 +334,14 @@ private struct ApplicationSpecificNoticeKeys {
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.chatSpecificThemeDarkPreviewTip.key) 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 { static func chatForwardOptionsTip() -> NoticeEntryKey {
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.chatForwardOptionsTip.key) return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.chatForwardOptionsTip.key)
} }
@ -1109,6 +1119,60 @@ public struct ApplicationSpecificNotice {
} }
} }
public static func getChatWallpaperLightPreviewTip(accountManager: AccountManager<TelegramAccountManagerTypes>) -> 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<TelegramAccountManagerTypes>, count: Int = 1, timestamp: Int32) -> Signal<Int, NoError> {
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<TelegramAccountManagerTypes>) -> 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<TelegramAccountManagerTypes>, count: Int = 1, timestamp: Int32) -> Signal<Int, NoError> {
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<TelegramAccountManagerTypes>) -> Signal<Int32, NoError> { public static func getChatForwardOptionsTip(accountManager: AccountManager<TelegramAccountManagerTypes>) -> Signal<Int32, NoError> {
return accountManager.transaction { transaction -> Int32 in return accountManager.transaction { transaction -> Int32 in
if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatForwardOptionsTip())?.get(ApplicationSpecificCounterNotice.self) { if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatForwardOptionsTip())?.get(ApplicationSpecificCounterNotice.self) {

View File

@ -130,7 +130,7 @@ final class ChatBotStartInputPanelNode: ChatInputPanelNode {
tooltipController.location = .point(location, .bottom) tooltipController.location = .point(location, .bottom)
} }
} else { } 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 return .ignore
}) })
controller.alwaysVisible = true controller.alwaysVisible = true

View File

@ -676,14 +676,17 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
return false return false
} }
if strongSelf.presentVoiceMessageDiscardAlert(action: { [weak self] in let displayVoiceMessageDiscardAlert: () -> Bool = {
if let strongSelf = self { if strongSelf.presentVoiceMessageDiscardAlert(action: { [weak self] in
Queue.mainQueue().after(0.1, { if let strongSelf = self {
let _ = strongSelf.controllerInteraction?.openMessage(message, mode) Queue.mainQueue().after(0.1, {
}) let _ = strongSelf.controllerInteraction?.openMessage(message, mode)
})
}
}, performAction: false) {
return false
} }
}, performAction: false) { return true
return false
} }
strongSelf.commitPurposefulAction() strongSelf.commitPurposefulAction()
@ -696,6 +699,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
for media in message.media { for media in message.media {
if media is TelegramMediaMap { if media is TelegramMediaMap {
if !displayVoiceMessageDiscardAlert() {
return false
}
isLocation = true isLocation = true
} }
if let file = media as? TelegramMediaFile, file.isInstantVideo { 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 { if let invoice = media as? TelegramMediaInvoice, let extendedMedia = invoice.extendedMedia {
switch extendedMedia { switch extendedMedia {
case .preview: case .preview:
strongSelf.controllerInteraction?.openCheckoutOrReceipt(message.id) if displayVoiceMessageDiscardAlert() {
return true strongSelf.controllerInteraction?.openCheckoutOrReceipt(message.id)
return true
} else {
return false
}
case .full: case .full:
break break
} }
} else if let action = media as? TelegramMediaAction { } else if let action = media as? TelegramMediaAction {
if !displayVoiceMessageDiscardAlert() {
return false
}
switch action.action { switch action.action {
case .pinnedMessageUpdated: case .pinnedMessageUpdated:
for attribute in message.attributes { for attribute in message.attributes {
@ -5839,6 +5852,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if let strongSelf = self { if let strongSelf = self {
let (themeEmoticonPreview, darkAppearancePreview) = themeEmoticonAndDarkAppearance let (themeEmoticonPreview, darkAppearancePreview) = themeEmoticonAndDarkAppearance
var chatWallpaper = chatWallpaper
let previousTheme = strongSelf.presentationData.theme let previousTheme = strongSelf.presentationData.theme
let previousStrings = strongSelf.presentationData.strings let previousStrings = strongSelf.presentationData.strings
let previousChatWallpaper = strongSelf.presentationData.chatWallpaper let previousChatWallpaper = strongSelf.presentationData.chatWallpaper
@ -5846,7 +5861,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
var themeEmoticon = themeEmoticon var themeEmoticon = themeEmoticon
if let themeEmoticonPreview = themeEmoticonPreview { if let themeEmoticonPreview = themeEmoticonPreview {
if !themeEmoticonPreview.isEmpty { if !themeEmoticonPreview.isEmpty {
themeEmoticon = themeEmoticonPreview if themeEmoticon != themeEmoticonPreview {
chatWallpaper = nil
themeEmoticon = themeEmoticonPreview
}
} else { } else {
themeEmoticon = nil themeEmoticon = nil
} }
@ -5857,7 +5875,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
var presentationData = presentationData var presentationData = presentationData
var useDarkAppearance = presentationData.theme.overallDarkAppearance var useDarkAppearance = presentationData.theme.overallDarkAppearance
if let themeEmoticon = themeEmoticon, let theme = chatThemes.first(where: { $0.emoticon?.strippedEmoji == themeEmoticon.strippedEmoji }) { if let themeEmoticon = themeEmoticon, let theme = chatThemes.first(where: { $0.emoticon?.strippedEmoji == themeEmoticon.strippedEmoji }) {
if let darkAppearancePreview = darkAppearancePreview { if let darkAppearancePreview = darkAppearancePreview {
useDarkAppearance = darkAppearancePreview useDarkAppearance = darkAppearancePreview
@ -5896,7 +5914,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
lightWallpaper = theme.chat.defaultWallpaper 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 { } else {
lightTheme = presentationData.theme lightTheme = presentationData.theme
lightWallpaper = presentationData.chatWallpaper lightWallpaper = presentationData.chatWallpaper
@ -5905,7 +5928,14 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let effectiveColors = themeSettings.themeSpecificAccentColors[automaticTheme.index] let effectiveColors = themeSettings.themeSpecificAccentColors[automaticTheme.index]
let themeSpecificWallpaper = (themeSettings.themeSpecificChatWallpapers[coloredThemeIndex(reference: automaticTheme, accentColor: effectiveColors)] ?? themeSettings.themeSpecificChatWallpapers[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 { if let themeSpecificWallpaper = themeSpecificWallpaper {
darkWallpaper = themeSpecificWallpaper darkWallpaper = themeSpecificWallpaper
@ -5944,7 +5974,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
presentationData = presentationData.withUpdated(chatWallpaper: chatWallpaper) presentationData = presentationData.withUpdated(chatWallpaper: chatWallpaper)
} }
let isFirstTime = !strongSelf.didSetPresentationData let isFirstTime = !strongSelf.didSetPresentationData
strongSelf.presentationData = presentationData strongSelf.presentationData = presentationData
strongSelf.didSetPresentationData = true strongSelf.didSetPresentationData = true
@ -14314,7 +14343,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
return 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 return .ignore
}, openActiveTextItem: { [weak self] item, action in }, openActiveTextItem: { [weak self] item, action in
guard let strongSelf = self else { guard let strongSelf = self else {
@ -14407,7 +14436,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
return 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 return .ignore
}, openActiveTextItem: { [weak self] item, action in }, openActiveTextItem: { [weak self] item, action in
guard let strongSelf = self else { guard let strongSelf = self else {
@ -14521,7 +14550,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
return 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 return .ignore
}, openActiveTextItem: { [weak self] item, action in }, openActiveTextItem: { [weak self] item, action in
guard let strongSelf = self else { guard let strongSelf = self else {
@ -18508,12 +18537,18 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let selectedEmoticon: String? = themeEmoticon let selectedEmoticon: String? = themeEmoticon
var canResetWallpaper = false
if let cachedUserData = strongSelf.peerView?.cachedData as? CachedUserData {
canResetWallpaper = cachedUserData.wallpaper != nil
}
let controller = ChatThemeScreen( let controller = ChatThemeScreen(
context: context, context: context,
updatedPresentationData: strongSelf.updatedPresentationData, updatedPresentationData: strongSelf.updatedPresentationData,
animatedEmojiStickers: animatedEmojiStickers, animatedEmojiStickers: animatedEmojiStickers,
initiallySelectedEmoticon: selectedEmoticon, initiallySelectedEmoticon: selectedEmoticon,
peerName: strongSelf.presentationInterfaceState.renderedPeer?.chatMainPeer.flatMap(EnginePeer.init)?.compactDisplayTitle ?? "", peerName: strongSelf.presentationInterfaceState.renderedPeer?.chatMainPeer.flatMap(EnginePeer.init)?.compactDisplayTitle ?? "",
canResetWallpaper: canResetWallpaper,
previewTheme: { [weak self] emoticon, dark in previewTheme: { [weak self] emoticon, dark in
if let strongSelf = self { if let strongSelf = self {
strongSelf.presentCrossfadeSnapshot() strongSelf.presentCrossfadeSnapshot()
@ -18540,54 +18575,47 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} }
} }
var canDelete = false var openWallpaperPickerImpl: (() -> Void)?
if let cachedUserData = strongSelf.peerView?.cachedData as? CachedUserData { let openWallpaperPicker = {
canDelete = cachedUserData.wallpaper != nil let controller = wallpaperMediaPickerController(
} context: strongSelf.context,
let controller = wallpaperMediaPickerController( updatedPresentationData: strongSelf.updatedPresentationData,
context: strongSelf.context, peer: EnginePeer(peer),
updatedPresentationData: strongSelf.updatedPresentationData, completion: { asset in
peer: EnginePeer(peer), guard let strongSelf = self else {
canDelete: canDelete, return
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()
})
} }
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)
controller.navigationPresentation = .flatModal
strongSelf.push(controller)
},
changeColor: {
guard let strongSelf = self else {
return
} }
if let themeController = strongSelf.themeScreen { openWallpaperPickerImpl = openWallpaperPicker
strongSelf.themeScreen = nil openWallpaperPicker()
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)
}, },
completion: { [weak self] emoticon in completion: { [weak self] emoticon in
guard let strongSelf = self, let peerId else { guard let strongSelf = self, let peerId else {

View File

@ -1483,7 +1483,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
tooltipController.location = .point(location, .bottom) tooltipController.location = .point(location, .bottom)
} }
} else { } 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 return .ignore
}) })
controller.alwaysVisible = true controller.alwaysVisible = true

View File

@ -554,9 +554,9 @@ final class ChatThemeScreen: ViewController {
private let animatedEmojiStickers: [String: [StickerPackItem]] private let animatedEmojiStickers: [String: [StickerPackItem]]
private let initiallySelectedEmoticon: String? private let initiallySelectedEmoticon: String?
private let peerName: String private let peerName: String
let canResetWallpaper: Bool
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
@ -578,9 +578,9 @@ final class ChatThemeScreen: ViewController {
animatedEmojiStickers: [String: [StickerPackItem]], animatedEmojiStickers: [String: [StickerPackItem]],
initiallySelectedEmoticon: String?, initiallySelectedEmoticon: String?,
peerName: String, peerName: String,
canResetWallpaper: Bool,
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,9 +588,9 @@ final class ChatThemeScreen: ViewController {
self.animatedEmojiStickers = animatedEmojiStickers self.animatedEmojiStickers = animatedEmojiStickers
self.initiallySelectedEmoticon = initiallySelectedEmoticon self.initiallySelectedEmoticon = initiallySelectedEmoticon
self.peerName = peerName self.peerName = peerName
self.canResetWallpaper = canResetWallpaper
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)
@ -1013,18 +1013,22 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
} }
private func updateButtons() { private func updateButtons() {
let canResetWallpaper = self.controller?.canResetWallpaper ?? false
let doneButtonTitle: String let doneButtonTitle: String
let otherButtonTitle: String let otherButtonTitle: String
var accentButtonTheme = true var accentButtonTheme = true
var destructiveOtherButton = false
if self.selectedEmoticon == self.initiallySelectedEmoticon { if self.selectedEmoticon == self.initiallySelectedEmoticon {
doneButtonTitle = self.presentationData.strings.Conversation_Theme_SetPhotoWallpaper 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 accentButtonTheme = false
destructiveOtherButton = canResetWallpaper
} else if self.selectedEmoticon == nil && self.initiallySelectedEmoticon != nil { } else if self.selectedEmoticon == nil && self.initiallySelectedEmoticon != nil {
doneButtonTitle = self.presentationData.strings.Conversation_Theme_Reset doneButtonTitle = self.presentationData.strings.Conversation_Theme_Reset
otherButtonTitle = self.presentationData.strings.Conversation_Theme_OtherOptions otherButtonTitle = self.presentationData.strings.Conversation_Theme_OtherOptions
} else { } else {
doneButtonTitle = self.presentationData.strings.Conversation_Theme_Apply doneButtonTitle = self.presentationData.strings.Conversation_Theme_ApplyBackground
otherButtonTitle = self.presentationData.strings.Conversation_Theme_OtherOptions otherButtonTitle = self.presentationData.strings.Conversation_Theme_OtherOptions
} }
@ -1040,7 +1044,7 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
} }
self.doneButton.updateTheme(buttonTheme) 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? private var switchThemeIconAnimator: DisplayLinkAnimator?
@ -1102,7 +1106,11 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
if self.selectedEmoticon != self.initiallySelectedEmoticon { if self.selectedEmoticon != self.initiallySelectedEmoticon {
self.setEmoticon(self.initiallySelectedEmoticon) self.setEmoticon(self.initiallySelectedEmoticon)
} else { } 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 { if let strongSelf = self, count < 2 && currentTimestamp > timestamp + 24 * 60 * 60 {
strongSelf.displayedPreviewTooltip = true 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) return .dismiss(consume: false)
})) }))

View File

@ -8467,7 +8467,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
return return
} }
let buttonFrame = buttonNode.view.convert(buttonNode.bounds, to: self.view) 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) return .dismiss(consume: false)
}), in: .current) }), in: .current)
} }

View File

@ -11,6 +11,7 @@ import TelegramCore
import TextFormat import TextFormat
import Postbox import Postbox
import UrlEscaping import UrlEscaping
import AccountContext
public protocol TooltipCustomContentNode: ASDisplayNode { public protocol TooltipCustomContentNode: ASDisplayNode {
func animateIn() func animateIn()
@ -127,12 +128,11 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
private let backgroundContainerNode: ASDisplayNode private let backgroundContainerNode: ASDisplayNode
private let backgroundClipNode: ASDisplayNode private let backgroundClipNode: ASDisplayNode
private let backgroundMaskNode: ASDisplayNode private let backgroundMaskNode: ASDisplayNode
private var effectView: UIView? private var effectNode: NavigationBackgroundNode?
private var gradientNode: ASDisplayNode? private var gradientNode: ASDisplayNode?
private var arrowGradientNode: ASDisplayNode? private var arrowGradientNode: ASDisplayNode?
private let arrowNode: ASImageNode private let arrowNode: ASImageNode
private let arrowContainer: ASDisplayNode private let arrowContainer: ASDisplayNode
private var arrowEffectView: UIView?
private let animatedStickerNode: AnimatedStickerNode private let animatedStickerNode: AnimatedStickerNode
private var downArrowsNode: DownArrowsIconNode? private var downArrowsNode: DownArrowsIconNode?
private let textNode: ImmediateTextNode private let textNode: ImmediateTextNode
@ -143,7 +143,7 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
private var validLayout: ContainerViewLayout? 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.tooltipStyle = style
self.icon = icon self.icon = icon
self.customContentNode = customContentNode self.customContentNode = customContentNode
@ -210,9 +210,16 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
self.arrowContainer = ASDisplayNode() self.arrowContainer = ASDisplayNode()
let theme = sharedContext.currentPresentationData.with { $0 }.theme
let fontSize: CGFloat let fontSize: CGFloat
if case .top = location { 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.backgroundMaskNode.addSubnode(self.backgroundClipNode)
self.backgroundClipNode.clipsToBounds = true self.backgroundClipNode.clipsToBounds = true
if case let .point(_, arrowPosition) = location, case .right = arrowPosition { 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) maskLayer.frame = CGRect(origin: CGPoint(), size: arrowSize)
self.arrowContainer.layer.mask = maskLayer self.arrowContainer.layer.mask = maskLayer
} else { } else {
let effect: UIBlurEffect var enableSaturation = true
if case .light = style { let backgroundColor: UIColor
effect = UIBlurEffect(style: .light) if case let .customBlur(color) = style {
backgroundColor = color
enableSaturation = false
} else if case .light = style {
backgroundColor = theme.rootController.navigationBar.blurredBackgroundColor
} else { } 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.backgroundMaskNode.addSubnode(self.backgroundClipNode)
self.backgroundClipNode.clipsToBounds = true self.backgroundClipNode.clipsToBounds = true
if case let .point(_, arrowPosition) = location, case .right = arrowPosition { if case let .point(_, arrowPosition) = location, case .right = arrowPosition {
self.backgroundClipNode.cornerRadius = 8.5 self.backgroundClipNode.cornerRadius = 8.5
} else { } else {
self.backgroundClipNode.cornerRadius = 14.0 self.backgroundClipNode.cornerRadius = 12.5
} }
if #available(iOS 13.0, *) { if #available(iOS 13.0, *) {
self.backgroundClipNode.layer.cornerCurve = .continuous self.backgroundClipNode.layer.cornerCurve = .continuous
@ -318,8 +333,8 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
if let gradientNode = self.gradientNode { if let gradientNode = self.gradientNode {
self.backgroundContainerNode.addSubnode(gradientNode) self.backgroundContainerNode.addSubnode(gradientNode)
self.containerNode.addSubnode(self.arrowContainer) self.containerNode.addSubnode(self.arrowContainer)
} else if let effectView = self.effectView { } else if let effectNode = self.effectNode {
self.backgroundContainerNode.view.addSubview(effectView) self.backgroundContainerNode.addSubnode(effectNode)
self.backgroundContainerNode.layer.mask = self.backgroundMaskNode.layer self.backgroundContainerNode.layer.mask = self.backgroundMaskNode.layer
} }
self.containerNode.addSubnode(self.textNode) self.containerNode.addSubnode(self.textNode)
@ -430,7 +445,7 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
let backgroundHeight: CGFloat let backgroundHeight: CGFloat
switch self.tooltipStyle { switch self.tooltipStyle {
case .default, .gradient: case .default, .gradient, .customBlur:
backgroundHeight = max(animationSize.height, textSize.height) + contentVerticalInset * 2.0 backgroundHeight = max(animationSize.height, textSize.height) + contentVerticalInset * 2.0
case .light: case .light:
backgroundHeight = max(28.0, max(animationSize.height, textSize.height) + 4.0 * 2.0) 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.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)) transition.updateFrame(node: self.backgroundClipNode, frame: CGRect(origin: CGPoint(x: 10.0, y: 10.0), size: backgroundFrame.size))
if let effectView = self.effectView { if let effectNode = self.effectNode {
transition.updateFrame(view: effectView, frame: CGRect(origin: CGPoint(), size: backgroundFrame.size).insetBy(dx: -10.0, dy: -10.0)) 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 { if let gradientNode = self.gradientNode {
transition.updateFrame(node: gradientNode, frame: CGRect(origin: CGPoint(), size: backgroundFrame.size)) 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) let arrowBounds = CGRect(origin: CGPoint(), size: arrowSize)
self.arrowNode.frame = arrowBounds 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) self.arrowGradientNode?.frame = CGRect(origin: CGPoint(x: -arrowFrame.minX + backgroundFrame.minX, y: 0.0), size: backgroundFrame.size)
case .right: case .right:
arrowFrame = CGRect(origin: CGPoint(x: backgroundFrame.width + arrowSize.height, y: rect.midY), size: CGSize(width: arrowSize.height, height: arrowSize.width)) 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) let arrowBounds = CGRect(origin: .zero, size: arrowSize)
self.arrowNode.frame = arrowBounds self.arrowNode.frame = arrowBounds
self.arrowEffectView?.frame = arrowBounds
self.arrowGradientNode?.frame = arrowBounds self.arrowGradientNode?.frame = arrowBounds
} }
} else { } else {
self.arrowNode.isHidden = true 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)) 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 { public enum Style {
case `default` case `default`
case light case light
case customBlur(UIColor)
case gradient(UIColor, UIColor) case gradient(UIColor, UIColor)
} }
private let account: Account private let account: Account
private let sharedContext: SharedAccountContext
public let text: String public let text: String
public let textEntities: [MessageTextEntity] public let textEntities: [MessageTextEntity]
private let style: TooltipScreen.Style private let style: TooltipScreen.Style
@ -707,8 +723,9 @@ public final class TooltipScreen: ViewController {
public var alwaysVisible = false 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.account = account
self.sharedContext = sharedContext
self.text = text self.text = text
self.textEntities = textEntities self.textEntities = textEntities
self.style = style self.style = style
@ -776,7 +793,7 @@ public final class TooltipScreen: ViewController {
} }
override public func loadDisplayNode() { 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 { guard let strongSelf = self else {
return return
} }

View File

@ -743,6 +743,7 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
private var gradientBackgroundNode: GradientBackgroundNode? private var gradientBackgroundNode: GradientBackgroundNode?
private var outgoingBubbleGradientBackgroundNode: GradientBackgroundNode? private var outgoingBubbleGradientBackgroundNode: GradientBackgroundNode?
private let patternImageLayer: EffectImageLayer private let patternImageLayer: EffectImageLayer
private let dimLayer: SimpleLayer
private var isGeneratingPatternImage: Bool = false private var isGeneratingPatternImage: Bool = false
private let bakedBackgroundView: UIImageView private let bakedBackgroundView: UIImageView
@ -862,6 +863,9 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
self.bakedBackgroundView = UIImageView() self.bakedBackgroundView = UIImageView()
self.bakedBackgroundView.isHidden = true self.bakedBackgroundView.isHidden = true
self.dimLayer = SimpleLayer()
self.dimLayer.backgroundColor = UIColor.black.cgColor
super.init() super.init()
if #available(iOS 12.0, *) { if #available(iOS 12.0, *) {
@ -885,6 +889,8 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
self.contentNode.frame = self.bounds self.contentNode.frame = self.bounds
self.addSubnode(self.contentNode) self.addSubnode(self.contentNode)
self.layer.addSublayer(self.patternImageLayer) self.layer.addSublayer(self.patternImageLayer)
self.layer.addSublayer(self.dimLayer)
} }
deinit { deinit {
@ -892,6 +898,19 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
self.wallpaperDisposable.dispose() self.wallpaperDisposable.dispose()
self.imageDisposable.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) { func update(wallpaper: TelegramWallpaper) {
if self.wallpaper == wallpaper { if self.wallpaper == wallpaper {
@ -915,7 +934,7 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
gradientColors = file.settings.colors gradientColors = file.settings.colors
gradientAngle = file.settings.rotation ?? 0 gradientAngle = file.settings.rotation ?? 0
} }
var scheduleLoopingEvent = false var scheduleLoopingEvent = false
if gradientColors.count >= 3 { if gradientColors.count >= 3 {
let mappedColors = gradientColors.map { color -> UIColor in 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.animateEvent(transition: .animated(duration: 0.7, curve: .linear), extendAnimation: false)
} }
} }
self.updateDimming()
} }
func _internalUpdateIsSettingUpWallpaper() { func _internalUpdateIsSettingUpWallpaper() {
@ -1304,6 +1325,8 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
transition.updateFrame(node: outgoingBackgroundNode, frame: CGRect(origin: CGPoint(), size: size)) transition.updateFrame(node: outgoingBackgroundNode, frame: CGRect(origin: CGPoint(), size: size))
outgoingBackgroundNode.update(rect: CGRect(origin: CGPoint(), size: size), within: size, transition: transition) 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) self.loadPatternForSizeIfNeeded(size: size, displayMode: displayMode, transition: transition)
@ -1378,6 +1401,7 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
} }
self.updateBubbles() self.updateBubbles()
self.updateDimming()
} }
} }