mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-15 21:45:19 +00:00
Merge commit 'a9e441902171a81c383d6f734bcf08c66e3db3a4'
# Conflicts: # submodules/TelegramUI/Sources/FetchCachedRepresentations.swift
This commit is contained in:
commit
cdc32a8910
@ -9149,7 +9149,7 @@ Sorry for the inconvenience.";
|
||||
"WallpaperPreview.ChatBottomText" = "Enjoy the view.";
|
||||
|
||||
"Conversation.Theme.SetPhotoWallpaper" = "Choose Background from Photos";
|
||||
"Conversation.Theme.SetColorWallpaper" = "Choose Color as a Background";
|
||||
"Conversation.Theme.SetColorWallpaper" = "Set a Color as a Background";
|
||||
"Conversation.Theme.OtherOptions" = "Other Options...";
|
||||
|
||||
"Conversation.Theme.ChooseWallpaperTitle" = "Choose Background";
|
||||
@ -9158,3 +9158,11 @@ Sorry for the inconvenience.";
|
||||
"Conversation.Theme.SetCustomColor" = "Set Custom";
|
||||
|
||||
"Appearance.ShowNextMediaOnTap" = "Show Next Media on Tap";
|
||||
|
||||
"WebApp.LaunchMoreInfo" = "More about this bot";
|
||||
"WebApp.LaunchConfirmation" = "To launch this web app, you will connect to its website.";
|
||||
|
||||
"WallpaperPreview.PreviewInNightMode" = "Preview this background in night mode.";
|
||||
"WallpaperPreview.PreviewInDayMode" = "Preview this background in day mode.";
|
||||
|
||||
"Conversation.Theme.ApplyBackground" = "Set as Background";
|
||||
|
@ -756,6 +756,7 @@ public protocol SharedAccountContext: AnyObject {
|
||||
var currentInAppNotificationSettings: Atomic<InAppNotificationSettings> { get }
|
||||
var currentMediaInputSettings: Atomic<MediaInputSettings> { get }
|
||||
var currentStickerSettings: Atomic<StickerSettings> { get }
|
||||
var currentMediaDisplaySettings: Atomic<MediaDisplaySettings> { get }
|
||||
|
||||
var energyUsageSettings: EnergyUsageSettings { get }
|
||||
|
||||
|
@ -1370,7 +1370,7 @@ public final class CalendarMessageScreen: ViewController {
|
||||
if self.selectionState?.dayRange == nil {
|
||||
if let selectionToolbarNode = self.selectionToolbarNode {
|
||||
let toolbarFrame = selectionToolbarNode.view.convert(selectionToolbarNode.bounds, to: self.view)
|
||||
self.controller?.present(TooltipScreen(account: self.context.account, text: self.presentationData.strings.MessageCalendar_EmptySelectionTooltip, style: .default, icon: .none, location: .point(toolbarFrame.insetBy(dx: 0.0, dy: 10.0), .bottom), shouldDismissOnTouch: { point in
|
||||
self.controller?.present(TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: self.presentationData.strings.MessageCalendar_EmptySelectionTooltip, style: .default, icon: .none, location: .point(toolbarFrame.insetBy(dx: 0.0, dy: 10.0), .bottom), shouldDismissOnTouch: { point in
|
||||
return .dismiss(consume: false)
|
||||
}), in: .current)
|
||||
}
|
||||
|
@ -2079,7 +2079,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
|
||||
let location = CGRect(origin: CGPoint(x: absoluteFrame.midX, y: absoluteFrame.minY - 8.0), size: CGSize())
|
||||
|
||||
parentController.present(TooltipScreen(account: strongSelf.context.account, text: text, icon: .chatListPress, location: .point(location, .bottom), shouldDismissOnTouch: { point in
|
||||
parentController.present(TooltipScreen(account: strongSelf.context.account, sharedContext: strongSelf.context.sharedContext, text: text, icon: .chatListPress, location: .point(location, .bottom), shouldDismissOnTouch: { point in
|
||||
guard let strongSelf = self, let parentController = strongSelf.parent as? TabBarController else {
|
||||
return .dismiss(consume: false)
|
||||
}
|
||||
|
@ -138,6 +138,7 @@ public final class NavigationBackgroundNode: ASDisplayNode {
|
||||
private var _color: UIColor
|
||||
|
||||
private var enableBlur: Bool
|
||||
private var enableSaturation: Bool
|
||||
|
||||
public var effectView: UIVisualEffectView?
|
||||
private let backgroundNode: ASDisplayNode
|
||||
@ -152,9 +153,10 @@ public final class NavigationBackgroundNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
public init(color: UIColor, enableBlur: Bool = true) {
|
||||
public init(color: UIColor, enableBlur: Bool = true, enableSaturation: Bool = true) {
|
||||
self._color = .clear
|
||||
self.enableBlur = enableBlur
|
||||
self.enableSaturation = enableSaturation
|
||||
|
||||
self.backgroundNode = ASDisplayNode()
|
||||
|
||||
@ -195,10 +197,12 @@ public final class NavigationBackgroundNode: ASDisplayNode {
|
||||
if let sublayer = effectView.layer.sublayers?[0], let filters = sublayer.filters {
|
||||
sublayer.backgroundColor = nil
|
||||
sublayer.isOpaque = false
|
||||
let allowedKeys: [String] = [
|
||||
"colorSaturate",
|
||||
var allowedKeys: [String] = [
|
||||
"gaussianBlur"
|
||||
]
|
||||
if self.enableSaturation {
|
||||
allowedKeys.append("colorSaturate")
|
||||
}
|
||||
sublayer.filters = filters.filter { filter in
|
||||
guard let filter = filter as? NSObject else {
|
||||
return true
|
||||
@ -225,14 +229,16 @@ public final class NavigationBackgroundNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
public func updateColor(color: UIColor, enableBlur: Bool? = nil, forceKeepBlur: Bool = false, transition: ContainedViewLayoutTransition) {
|
||||
public func updateColor(color: UIColor, enableBlur: Bool? = nil, enableSaturation: Bool? = nil, forceKeepBlur: Bool = false, transition: ContainedViewLayoutTransition) {
|
||||
let effectiveEnableBlur = enableBlur ?? self.enableBlur
|
||||
|
||||
if self._color.isEqual(color) && self.enableBlur == effectiveEnableBlur {
|
||||
let effectiveEnableSaturation = enableSaturation ?? self.enableSaturation
|
||||
|
||||
if self._color.isEqual(color) && self.enableBlur == effectiveEnableBlur && self.enableSaturation == effectiveEnableSaturation {
|
||||
return
|
||||
}
|
||||
self._color = color
|
||||
self.enableBlur = effectiveEnableBlur
|
||||
self.enableSaturation = effectiveEnableSaturation
|
||||
|
||||
if sharedIsReduceTransparencyEnabled {
|
||||
transition.updateBackgroundColor(node: self.backgroundNode, color: self._color.withAlphaComponent(1.0))
|
||||
|
@ -1211,7 +1211,9 @@ public class GalleryController: ViewController, StandalonePresentableController,
|
||||
})
|
||||
}
|
||||
})
|
||||
self.displayNode = GalleryControllerNode(controllerInteraction: controllerInteraction)
|
||||
|
||||
let disableTapNavigation = !(self.context.sharedContext.currentMediaDisplaySettings.with { $0 }.showNextMediaOnTap)
|
||||
self.displayNode = GalleryControllerNode(controllerInteraction: controllerInteraction, disableTapNavigation: disableTapNavigation)
|
||||
self.displayNodeDidLoad()
|
||||
|
||||
self.galleryNode.statusBar = self.statusBar
|
||||
|
@ -39,6 +39,7 @@ public func blurredImage(_ image: UIImage, radius: CGFloat, iterations: Int = 3)
|
||||
let source = CFDataGetBytePtr(providerData)
|
||||
memcpy(inBuffer.data, source, bytes)
|
||||
|
||||
|
||||
for _ in 0 ..< iterations {
|
||||
vImageBoxConvolve_ARGB8888(&inBuffer, &outBuffer, tempData, 0, 0, boxSize, boxSize, nil, vImage_Flags(kvImageEdgeExtend))
|
||||
|
||||
|
@ -829,7 +829,7 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan
|
||||
text = strongSelf.presentationData.strings.Location_ProximityTip(EnginePeer(peer).compactDisplayTitle).string
|
||||
}
|
||||
|
||||
strongSelf.interaction.present(TooltipScreen(account: strongSelf.context.account, text: text, icon: nil, location: .point(location.offsetBy(dx: -9.0, dy: 0.0), .right), displayDuration: .custom(3.0), shouldDismissOnTouch: { _ in
|
||||
strongSelf.interaction.present(TooltipScreen(account: strongSelf.context.account, sharedContext: strongSelf.context.sharedContext, text: text, icon: nil, location: .point(location.offsetBy(dx: -9.0, dy: 0.0), .right), displayDuration: .custom(3.0), shouldDismissOnTouch: { _ in
|
||||
return .dismiss(consume: false)
|
||||
}))
|
||||
})
|
||||
|
@ -385,32 +385,40 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
||||
override func didLoad() {
|
||||
super.didLoad()
|
||||
|
||||
guard let controller = self.controller else {
|
||||
return
|
||||
}
|
||||
|
||||
self.gridNode.scrollView.alwaysBounceVertical = true
|
||||
self.gridNode.scrollView.showsVerticalScrollIndicator = false
|
||||
|
||||
let selectionGesture = MediaPickerGridSelectionGesture<TGMediaSelectableItem>()
|
||||
selectionGesture.delegate = self
|
||||
selectionGesture.began = { [weak self] in
|
||||
self?.controller?.cancelPanGesture()
|
||||
}
|
||||
selectionGesture.updateIsScrollEnabled = { [weak self] isEnabled in
|
||||
self?.gridNode.scrollView.isScrollEnabled = isEnabled
|
||||
}
|
||||
selectionGesture.itemAt = { [weak self] point in
|
||||
if let strongSelf = self, let itemNode = strongSelf.gridNode.itemNodeAtPoint(point) as? MediaPickerGridItemNode, let selectableItem = itemNode.selectableItem {
|
||||
return (selectableItem, strongSelf.controller?.interaction?.selectionState?.isIdentifierSelected(selectableItem.uniqueIdentifier) ?? false)
|
||||
} else {
|
||||
return nil
|
||||
if case let .assets(_, mode) = controller.subject, case .wallpaper = mode {
|
||||
|
||||
} else {
|
||||
let selectionGesture = MediaPickerGridSelectionGesture<TGMediaSelectableItem>()
|
||||
selectionGesture.delegate = self
|
||||
selectionGesture.began = { [weak self] in
|
||||
self?.controller?.cancelPanGesture()
|
||||
}
|
||||
}
|
||||
selectionGesture.updateSelection = { [weak self] asset, selected in
|
||||
if let strongSelf = self {
|
||||
strongSelf.controller?.interaction?.selectionState?.setItem(asset, selected: selected, animated: true, sender: nil)
|
||||
selectionGesture.updateIsScrollEnabled = { [weak self] isEnabled in
|
||||
self?.gridNode.scrollView.isScrollEnabled = isEnabled
|
||||
}
|
||||
selectionGesture.itemAt = { [weak self] point in
|
||||
if let strongSelf = self, let itemNode = strongSelf.gridNode.itemNodeAtPoint(point) as? MediaPickerGridItemNode, let selectableItem = itemNode.selectableItem {
|
||||
return (selectableItem, strongSelf.controller?.interaction?.selectionState?.isIdentifierSelected(selectableItem.uniqueIdentifier) ?? false)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
selectionGesture.updateSelection = { [weak self] asset, selected in
|
||||
if let strongSelf = self {
|
||||
strongSelf.controller?.interaction?.selectionState?.setItem(asset, selected: selected, animated: true, sender: nil)
|
||||
}
|
||||
}
|
||||
selectionGesture.sideInset = 44.0
|
||||
self.gridNode.view.addGestureRecognizer(selectionGesture)
|
||||
self.selectionGesture = selectionGesture
|
||||
}
|
||||
selectionGesture.sideInset = 44.0
|
||||
self.gridNode.view.addGestureRecognizer(selectionGesture)
|
||||
self.selectionGesture = selectionGesture
|
||||
|
||||
if let controller = self.controller, case let .assets(collection, _) = controller.subject, collection != nil {
|
||||
self.gridNode.view.interactiveTransitionGestureRecognizerTest = { point -> Bool in
|
||||
@ -741,7 +749,11 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
||||
}
|
||||
|
||||
if let customSelection = controller.customSelection {
|
||||
self.openingMedia = true
|
||||
customSelection(fetchResult[index])
|
||||
Queue.mainQueue().after(0.3) {
|
||||
self.openingMedia = false
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@ -2010,18 +2022,19 @@ public func wallpaperMediaPickerController(
|
||||
context: AccountContext,
|
||||
updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil,
|
||||
peer: EnginePeer,
|
||||
canDelete: Bool,
|
||||
completion: @escaping (PHAsset) -> Void = { _ in }
|
||||
completion: @escaping (PHAsset) -> Void = { _ in },
|
||||
openColors: @escaping () -> Void
|
||||
) -> ViewController {
|
||||
let controller = AttachmentController(context: context, updatedPresentationData: updatedPresentationData, chatLocation: nil, buttons: [.standalone], initialButton: .standalone, fromMenu: false, hasTextInput: false, makeEntityInputView: {
|
||||
return nil
|
||||
})
|
||||
//controller.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait)
|
||||
controller.requestController = { [weak controller] _, present in
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let mediaPickerController = MediaPickerScreen(context: context, peer: nil, threadTitle: nil, chatLocation: nil, bannedSendPhotos: nil, bannedSendVideos: nil, subject: .assets(nil, .wallpaper), mainButtonState: canDelete ? AttachmentMainButtonState(text: presentationData.strings.Conversation_Theme_ResetWallpaper, font: .regular, background: .color(.clear), textColor: presentationData.theme.actionSheet.destructiveActionTextColor, isVisible: true, progress: .none, isEnabled: true) : nil, mainButtonAction: canDelete ? {
|
||||
let _ = context.engine.themes.setChatWallpaper(peerId: peer.id, wallpaper: nil).start()
|
||||
let mediaPickerController = MediaPickerScreen(context: context, peer: nil, threadTitle: nil, chatLocation: nil, bannedSendPhotos: nil, bannedSendVideos: nil, subject: .assets(nil, .wallpaper), mainButtonState: AttachmentMainButtonState(text: presentationData.strings.Conversation_Theme_SetColorWallpaper, font: .regular, background: .color(.clear), textColor: presentationData.theme.actionSheet.controlAccentColor, isVisible: true, progress: .none, isEnabled: true), mainButtonAction: {
|
||||
controller?.dismiss(animated: true)
|
||||
} : nil)
|
||||
openColors()
|
||||
})
|
||||
mediaPickerController.customSelection = completion
|
||||
present(mediaPickerController, mediaPickerController.mediaPickerContext)
|
||||
}
|
||||
|
@ -669,12 +669,8 @@ private func selectivePrivacySettingsControllerEntries(presentationData: Present
|
||||
|
||||
entries.append(.everybody(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenEverybody, state.setting == .everybody))
|
||||
entries.append(.contacts(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenContacts, state.setting == .contacts))
|
||||
switch kind {
|
||||
case .presence, .voiceCalls, .forwards, .phoneNumber, .voiceMessages, .profilePhoto:
|
||||
entries.append(.nobody(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenNobody, state.setting == .nobody))
|
||||
case .groupInvitations:
|
||||
break
|
||||
}
|
||||
entries.append(.nobody(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenNobody, state.setting == .nobody))
|
||||
|
||||
let phoneLink = "https://t.me/+\(phoneNumber)"
|
||||
if let settingInfoText = settingInfoText {
|
||||
entries.append(.settingInfo(presentationData.theme, settingInfoText, phoneLink))
|
||||
|
@ -25,9 +25,9 @@ func presentCustomWallpaperPicker(context: AccountContext, present: @escaping (V
|
||||
controller.selectionBlock = { [weak legacyController] asset, _ in
|
||||
if let asset = asset {
|
||||
let controller = WallpaperGalleryController(context: context, source: .asset(asset.backingAsset))
|
||||
controller.apply = { [weak legacyController, weak controller] wallpaper, mode, cropRect in
|
||||
controller.apply = { [weak legacyController, weak controller] wallpaper, mode, cropRect, brightness in
|
||||
if let legacyController = legacyController, let controller = controller {
|
||||
uploadCustomWallpaper(context: context, wallpaper: wallpaper, mode: mode, cropRect: cropRect, completion: { [weak legacyController, weak controller] in
|
||||
uploadCustomWallpaper(context: context, wallpaper: wallpaper, mode: mode, cropRect: cropRect, brightness: brightness, completion: { [weak legacyController, weak controller] in
|
||||
if let legacyController = legacyController, let controller = controller {
|
||||
legacyController.dismiss()
|
||||
controller.dismiss(forceAway: true)
|
||||
@ -47,7 +47,7 @@ func presentCustomWallpaperPicker(context: AccountContext, present: @escaping (V
|
||||
})
|
||||
}
|
||||
|
||||
func uploadCustomWallpaper(context: AccountContext, wallpaper: WallpaperGalleryEntry, mode: WallpaperPresentationOptions, cropRect: CGRect?, completion: @escaping () -> Void) {
|
||||
func uploadCustomWallpaper(context: AccountContext, wallpaper: WallpaperGalleryEntry, mode: WallpaperPresentationOptions, cropRect: CGRect?, brightness: CGFloat?, completion: @escaping () -> Void) {
|
||||
let imageSignal: Signal<UIImage, NoError>
|
||||
switch wallpaper {
|
||||
case let .wallpaper(wallpaper, _):
|
||||
@ -131,12 +131,12 @@ func uploadCustomWallpaper(context: AccountContext, wallpaper: WallpaperGalleryE
|
||||
|
||||
if let data = croppedImage.jpegData(compressionQuality: 0.8), let thumbnailImage = thumbnailImage, let thumbnailData = thumbnailImage.jpegData(compressionQuality: 0.4) {
|
||||
let thumbnailResource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max))
|
||||
context.sharedContext.accountManager.mediaBox.storeResourceData(thumbnailResource.id, data: thumbnailData)
|
||||
context.account.postbox.mediaBox.storeResourceData(thumbnailResource.id, data: thumbnailData)
|
||||
context.sharedContext.accountManager.mediaBox.storeResourceData(thumbnailResource.id, data: thumbnailData, synchronous: true)
|
||||
context.account.postbox.mediaBox.storeResourceData(thumbnailResource.id, data: thumbnailData, synchronous: true)
|
||||
|
||||
let resource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max))
|
||||
context.sharedContext.accountManager.mediaBox.storeResourceData(resource.id, data: data)
|
||||
context.account.postbox.mediaBox.storeResourceData(resource.id, data: data)
|
||||
context.sharedContext.accountManager.mediaBox.storeResourceData(resource.id, data: data, synchronous: true)
|
||||
context.account.postbox.mediaBox.storeResourceData(resource.id, data: data, synchronous: true)
|
||||
|
||||
let autoNightModeTriggered = context.sharedContext.currentPresentationData.with {$0 }.autoNightModeTriggered
|
||||
let accountManager = context.sharedContext.accountManager
|
||||
@ -196,14 +196,14 @@ func uploadCustomWallpaper(context: AccountContext, wallpaper: WallpaperGalleryE
|
||||
}).start()
|
||||
}
|
||||
|
||||
public func uploadCustomPeerWallpaper(context: AccountContext, wallpaper: WallpaperGalleryEntry, mode: WallpaperPresentationOptions, cropRect: CGRect?, brightnessMultiplier: 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>
|
||||
switch wallpaper {
|
||||
case let .wallpaper(wallpaper, _):
|
||||
switch wallpaper {
|
||||
case let .file(file):
|
||||
if let path = context.account.postbox.mediaBox.completedResourcePath(file.file.resource), let data = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedRead) {
|
||||
context.sharedContext.accountManager.mediaBox.storeResourceData(file.file.resource.id, data: data)
|
||||
context.sharedContext.accountManager.mediaBox.storeResourceData(file.file.resource.id, data: data, synchronous: true)
|
||||
let _ = context.sharedContext.accountManager.mediaBox.cachedResourceRepresentation(file.file.resource, representation: CachedScaledImageRepresentation(size: CGSize(width: 720.0, height: 720.0), mode: .aspectFit), complete: true, fetch: true).start()
|
||||
let _ = context.sharedContext.accountManager.mediaBox.cachedResourceRepresentation(file.file.resource, representation: CachedBlurredWallpaperRepresentation(), complete: true, fetch: true).start()
|
||||
}
|
||||
@ -211,7 +211,7 @@ public func uploadCustomPeerWallpaper(context: AccountContext, wallpaper: Wallpa
|
||||
for representation in representations {
|
||||
let resource = representation.resource
|
||||
if let path = context.account.postbox.mediaBox.completedResourcePath(resource), let data = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedRead) {
|
||||
context.sharedContext.accountManager.mediaBox.storeResourceData(resource.id, data: data)
|
||||
context.sharedContext.accountManager.mediaBox.storeResourceData(resource.id, data: data, synchronous: true)
|
||||
let _ = context.sharedContext.accountManager.mediaBox.cachedResourceRepresentation(resource, representation: CachedScaledImageRepresentation(size: CGSize(width: 720.0, height: 720.0), mode: .aspectFit), complete: true, fetch: true).start()
|
||||
}
|
||||
}
|
||||
@ -276,7 +276,7 @@ public func uploadCustomPeerWallpaper(context: AccountContext, wallpaper: Wallpa
|
||||
croppedImage = TGPhotoEditorCrop(image, nil, .up, 0.0, finalCropRect, false, CGSize(width: 1440.0, height: 2960.0), image.size, true)
|
||||
|
||||
if mode.contains(.blur) {
|
||||
croppedImage = blurredImage(croppedImage, radius: 20.0)!
|
||||
croppedImage = blurredImage(croppedImage, radius: 30.0)!
|
||||
}
|
||||
|
||||
let thumbnailDimensions = finalCropRect.size.fitted(CGSize(width: 320.0, height: 320.0))
|
||||
@ -291,7 +291,12 @@ public func uploadCustomPeerWallpaper(context: AccountContext, wallpaper: Wallpa
|
||||
context.sharedContext.accountManager.mediaBox.storeResourceData(resource.id, data: data, synchronous: true)
|
||||
context.account.postbox.mediaBox.storeResourceData(resource.id, data: data, synchronous: true)
|
||||
|
||||
let settings = WallpaperSettings(blur: mode.contains(.blur), motion: mode.contains(.motion), colors: [], intensity: nil)
|
||||
var intensity: Int32?
|
||||
if let brightness {
|
||||
intensity = max(1, Int32(brightness * 100.0))
|
||||
}
|
||||
|
||||
let settings = WallpaperSettings(blur: mode.contains(.blur), motion: mode.contains(.motion), colors: [], intensity: intensity)
|
||||
let temporaryWallpaper: TelegramWallpaper = .image([TelegramMediaImageRepresentation(dimensions: PixelDimensions(thumbnailDimensions), resource: thumbnailResource, progressiveSizes: [], immediateThumbnailData: nil, hasVideo: false, isPersonal: false), TelegramMediaImageRepresentation(dimensions: PixelDimensions(croppedImage.size), resource: resource, progressiveSizes: [], immediateThumbnailData: nil, hasVideo: false, isPersonal: false)], settings)
|
||||
|
||||
let _ = context.account.postbox.transaction({ transaction in
|
||||
@ -308,7 +313,7 @@ public func uploadCustomPeerWallpaper(context: AccountContext, wallpaper: Wallpa
|
||||
completion()
|
||||
}
|
||||
|
||||
let _ = uploadWallpaper(account: context.account, resource: resource, settings: WallpaperSettings(blur: false, motion: mode.contains(.motion), colors: [], intensity: nil), forChat: true).start(next: { status in
|
||||
let _ = uploadWallpaper(account: context.account, resource: resource, settings: WallpaperSettings(blur: false, motion: mode.contains(.motion), colors: [], intensity: intensity), forChat: true).start(next: { status in
|
||||
if case let .complete(wallpaper) = status {
|
||||
if case let .file(file) = wallpaper {
|
||||
context.account.postbox.mediaBox.copyResourceData(from: resource.id, to: file.file.resource.id, synchronous: true)
|
||||
|
@ -119,7 +119,11 @@ final class ThemeAccentColorController: ViewController {
|
||||
} else {
|
||||
self.navigationItem.titleView = self.segmentedTitleView
|
||||
}
|
||||
self.navigationItem.leftBarButtonItem = UIBarButtonItem(customView: UIView())
|
||||
if case .peer = resultMode {
|
||||
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Cancel, style: .plain, target: self, action: #selector(self.cancelPressed))
|
||||
} else {
|
||||
self.navigationItem.leftBarButtonItem = UIBarButtonItem(customView: UIView())
|
||||
}
|
||||
}
|
||||
|
||||
required init(coder aDecoder: NSCoder) {
|
||||
@ -129,6 +133,10 @@ final class ThemeAccentColorController: ViewController {
|
||||
deinit {
|
||||
self.applyDisposable.dispose()
|
||||
}
|
||||
|
||||
@objc private func cancelPressed() {
|
||||
self.dismiss()
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
@ -169,6 +177,12 @@ final class ThemeAccentColorController: ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
if case let .peer(peer) = strongSelf.resultMode {
|
||||
let _ = strongSelf.context.engine.themes.setChatWallpaper(peerId: peer.id, wallpaper: coloredWallpaper).start()
|
||||
strongSelf.completion?()
|
||||
return
|
||||
}
|
||||
|
||||
let prepareWallpaper: Signal<CreateThemeResult, CreateThemeError>
|
||||
if let patternWallpaper = state.patternWallpaper, case let .file(file) = patternWallpaper, !state.backgroundColors.isEmpty {
|
||||
let resource = file.file.resource
|
||||
|
@ -152,6 +152,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
|
||||
private let context: AccountContext
|
||||
private var theme: PresentationTheme
|
||||
private let mode: ThemeAccentColorControllerMode
|
||||
private let resultMode: ThemeAccentColorController.ResultMode
|
||||
private var presentationData: PresentationData
|
||||
|
||||
private let animationCache: AnimationCache
|
||||
@ -227,6 +228,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
|
||||
init(context: AccountContext, mode: ThemeAccentColorControllerMode, resultMode: ThemeAccentColorController.ResultMode, theme: PresentationTheme, wallpaper: TelegramWallpaper, dismiss: @escaping () -> Void, apply: @escaping (ThemeColorState, UIColor?) -> Void, ready: Promise<Bool>) {
|
||||
self.context = context
|
||||
self.mode = mode
|
||||
self.resultMode = resultMode
|
||||
self.state = ThemeColorState()
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
self.theme = theme
|
||||
@ -766,6 +768,8 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
|
||||
} else {
|
||||
if case .edit(_, _, _, _, _, true, _) = self.mode {
|
||||
doneButtonType = .proceed
|
||||
} else if case .peer = self.resultMode {
|
||||
doneButtonType = .setPeer
|
||||
} else {
|
||||
doneButtonType = .set
|
||||
}
|
||||
|
@ -11,8 +11,8 @@ import TelegramUIPreferences
|
||||
import AccountContext
|
||||
import AttachmentUI
|
||||
|
||||
private func availableGradients(theme: PresentationTheme) -> [[UInt32]] {
|
||||
if theme.overallDarkAppearance {
|
||||
private func availableGradients(dark: Bool) -> [[UInt32]] {
|
||||
if dark {
|
||||
return [
|
||||
[0x1e3557, 0x151a36, 0x1c4352, 0x2a4541] as [UInt32],
|
||||
[0x1d223f, 0x1d1832, 0x1b2943, 0x141631] as [UInt32],
|
||||
@ -39,8 +39,8 @@ private func availableGradients(theme: PresentationTheme) -> [[UInt32]] {
|
||||
}
|
||||
}
|
||||
|
||||
private func availableColors(theme: PresentationTheme) -> [UInt32] {
|
||||
if theme.overallDarkAppearance {
|
||||
private func availableColors(dark: Bool) -> [UInt32] {
|
||||
if dark {
|
||||
return [
|
||||
0x1D2D3C,
|
||||
0x111B26,
|
||||
@ -149,6 +149,8 @@ public final class ThemeColorsGridController: ViewController, AttachmentContaina
|
||||
fileprivate let mainButtonStatePromise = Promise<AttachmentMainButtonState?>(nil)
|
||||
|
||||
var pushController: (ViewController) -> Void = { _ in }
|
||||
var dismissControllers: (() -> Void)?
|
||||
var openGallery: (() -> Void)?
|
||||
|
||||
public init(context: AccountContext, mode: Mode = .default, canDelete: Bool = false) {
|
||||
self.context = context
|
||||
@ -191,9 +193,7 @@ public final class ThemeColorsGridController: ViewController, AttachmentContaina
|
||||
self?.push(controller)
|
||||
}
|
||||
|
||||
if canDelete {
|
||||
self.mainButtonStatePromise.set(.single(AttachmentMainButtonState(text: self.presentationData.strings.Conversation_Theme_ResetWallpaper, font: .regular, background: .color(.clear), textColor: self.presentationData.theme.actionSheet.destructiveActionTextColor, isVisible: true, progress: .none, isEnabled: true)))
|
||||
}
|
||||
self.mainButtonStatePromise.set(.single(AttachmentMainButtonState(text: self.presentationData.strings.Conversation_Theme_SetPhotoWallpaper, font: .regular, background: .color(.clear), textColor: self.presentationData.theme.actionSheet.controlAccentColor, isVisible: true, progress: .none, isEnabled: true)))
|
||||
}
|
||||
|
||||
required public init(coder aDecoder: NSCoder) {
|
||||
@ -240,23 +240,28 @@ public final class ThemeColorsGridController: ViewController, AttachmentContaina
|
||||
}
|
||||
|
||||
let controller = ThemeAccentColorController(context: strongSelf.context, mode: .background(themeReference: themeReference), resultMode: strongSelf.mode.colorPickerMode)
|
||||
controller.completion = { [weak self] in
|
||||
if let strongSelf = self, let navigationController = strongSelf.navigationController as? NavigationController {
|
||||
var controllers = navigationController.viewControllers
|
||||
controllers = controllers.filter { controller in
|
||||
if controller is ThemeColorsGridController {
|
||||
return false
|
||||
controller.completion = { [weak self, weak controller] in
|
||||
if let strongSelf = self {
|
||||
if let dismissControllers = strongSelf.dismissControllers {
|
||||
dismissControllers()
|
||||
controller?.dismiss(animated: true)
|
||||
} else if let navigationController = strongSelf.navigationController as? NavigationController {
|
||||
var controllers = navigationController.viewControllers
|
||||
controllers = controllers.filter { controller in
|
||||
if controller is ThemeColorsGridController {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
return true
|
||||
}
|
||||
navigationController.setViewControllers(controllers, animated: false)
|
||||
controllers = controllers.filter { controller in
|
||||
if controller is ThemeAccentColorController {
|
||||
return false
|
||||
navigationController.setViewControllers(controllers, animated: false)
|
||||
controllers = controllers.filter { controller in
|
||||
if controller is ThemeAccentColorController {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
return true
|
||||
navigationController.setViewControllers(controllers, animated: true)
|
||||
}
|
||||
navigationController.setViewControllers(controllers, animated: true)
|
||||
}
|
||||
}
|
||||
strongSelf.pushController(controller)
|
||||
@ -264,7 +269,11 @@ public final class ThemeColorsGridController: ViewController, AttachmentContaina
|
||||
}
|
||||
|
||||
public override func loadDisplayNode() {
|
||||
self.displayNode = ThemeColorsGridControllerNode(context: self.context, presentationData: self.presentationData, controller: self, gradients: availableGradients(theme: self.presentationData.theme), colors: availableColors(theme: self.presentationData.theme), push: { [weak self] controller in
|
||||
var dark = false
|
||||
if case .default = self.mode {
|
||||
dark = self.presentationData.theme.overallDarkAppearance
|
||||
}
|
||||
self.displayNode = ThemeColorsGridControllerNode(context: self.context, presentationData: self.presentationData, controller: self, gradients: availableGradients(dark: dark), colors: availableColors(dark: dark), push: { [weak self] controller in
|
||||
self?.pushController(controller)
|
||||
}, pop: { [weak self] in
|
||||
if let strongSelf = self, let navigationController = strongSelf.navigationController as? NavigationController {
|
||||
@ -321,12 +330,8 @@ public final class ThemeColorsGridController: ViewController, AttachmentContaina
|
||||
}
|
||||
|
||||
@objc fileprivate func mainButtonPressed() {
|
||||
guard case let .peer(peer) = self.mode else {
|
||||
return
|
||||
}
|
||||
|
||||
let _ = self.context.engine.themes.setChatWallpaper(peerId: peer.id, wallpaper: nil).start()
|
||||
self.dismiss(animated: true)
|
||||
self.openGallery?()
|
||||
}
|
||||
|
||||
public var requestAttachmentMenuExpansion: () -> Void = {}
|
||||
@ -379,15 +384,26 @@ 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: {
|
||||
return nil
|
||||
})
|
||||
//controller.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait)
|
||||
controller.requestController = { _, present in
|
||||
let colorPickerController = ThemeColorsGridController(context: context, mode: .peer(peer), canDelete: canDelete)
|
||||
let colorPickerController = ThemeColorsGridController(context: context, mode: .peer(peer))
|
||||
colorPickerController.pushController = { controller in
|
||||
push(controller)
|
||||
}
|
||||
colorPickerController.dismissControllers = { [weak controller] in
|
||||
controller?.dismiss(animated: true)
|
||||
}
|
||||
colorPickerController.openGallery = openGallery
|
||||
present(colorPickerController, colorPickerController.mediaPickerContext)
|
||||
}
|
||||
return controller
|
||||
|
@ -132,27 +132,33 @@ final class ThemeColorsGridControllerNode: ASDisplayNode {
|
||||
self.addSubnode(self.gridNode)
|
||||
|
||||
let previousEntries = Atomic<[ThemeColorsGridControllerEntry]?>(value: nil)
|
||||
|
||||
let dismissControllers = { [weak self] in
|
||||
if let self, let navigationController = self.controller?.navigationController as? NavigationController {
|
||||
let controllers = navigationController.viewControllers.filter({ controller in
|
||||
if controller is ThemeColorsGridController || controller is WallpaperGalleryController {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
navigationController.setViewControllers(controllers, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let interaction = ThemeColorsGridControllerInteraction(openWallpaper: { [weak self] wallpaper in
|
||||
if let strongSelf = self {
|
||||
let entries = previousEntries.with { $0 }
|
||||
if let entries = entries, !entries.isEmpty {
|
||||
let wallpapers = entries.map { $0.wallpaper }
|
||||
let controller = WallpaperGalleryController(context: context, source: .list(wallpapers: wallpapers, central: wallpaper, type: .colors), mode: strongSelf.controller?.mode.galleryMode ?? .default)
|
||||
|
||||
let dismissControllers = { [weak self, weak controller] in
|
||||
if let self {
|
||||
if let dismissControllers = self.controller?.dismissControllers {
|
||||
dismissControllers()
|
||||
controller?.dismiss(animated: true)
|
||||
} else if let navigationController = self.controller?.navigationController as? NavigationController {
|
||||
let controllers = navigationController.viewControllers.filter({ controller in
|
||||
if controller is ThemeColorsGridController || controller is WallpaperGalleryController {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
navigationController.setViewControllers(controllers, animated: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
controller.navigationPresentation = .modal
|
||||
controller.apply = { [weak self] wallpaper, _, _ in
|
||||
controller.apply = { [weak self] wallpaper, _, _, _ in
|
||||
if let strongSelf = self, let mode = strongSelf.controller?.mode, case let .peer(peer) = mode, case let .wallpaper(wallpaperValue, _) = wallpaper {
|
||||
let _ = (strongSelf.context.engine.themes.setChatWallpaper(peerId: peer.id, wallpaper: wallpaperValue)
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
|
@ -120,9 +120,9 @@ public final class ThemeGridController: ViewController {
|
||||
self.displayNode = ThemeGridControllerNode(context: self.context, presentationData: self.presentationData, presentPreviewController: { [weak self] source in
|
||||
if let strongSelf = self {
|
||||
let controller = WallpaperGalleryController(context: strongSelf.context, source: source)
|
||||
controller.apply = { [weak self, weak controller] wallpaper, options, cropRect in
|
||||
controller.apply = { [weak self, weak controller] wallpaper, options, cropRect, brightness in
|
||||
if let strongSelf = self {
|
||||
uploadCustomWallpaper(context: strongSelf.context, wallpaper: wallpaper, mode: options, cropRect: cropRect, completion: { [weak self, weak controller] in
|
||||
uploadCustomWallpaper(context: strongSelf.context, wallpaper: wallpaper, mode: options, cropRect: cropRect, brightness: brightness, completion: { [weak self, weak controller] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.deactivateSearch(animated: false)
|
||||
strongSelf.controllerNode.scrollToTop(animated: false)
|
||||
@ -148,9 +148,9 @@ public final class ThemeGridController: ViewController {
|
||||
return
|
||||
}
|
||||
let controller = WallpaperGalleryController(context: strongSelf.context, source: .asset(asset))
|
||||
controller.apply = { [weak self, weak controller] wallpaper, options, cropRect in
|
||||
controller.apply = { [weak self, weak controller] wallpaper, options, cropRect, brightness in
|
||||
if let strongSelf = self, let controller = controller {
|
||||
uploadCustomWallpaper(context: strongSelf.context, wallpaper: wallpaper, mode: options, cropRect: cropRect, completion: { [weak controller] in
|
||||
uploadCustomWallpaper(context: strongSelf.context, wallpaper: wallpaper, mode: options, cropRect: cropRect, brightness: brightness, completion: { [weak controller] in
|
||||
if let controller = controller {
|
||||
controller.dismiss(forceAway: true)
|
||||
}
|
||||
|
@ -58,13 +58,13 @@ private final class ThemeSettingsControllerArguments {
|
||||
let openBubbleSettings: () -> Void
|
||||
let openPowerSavingSettings: () -> Void
|
||||
let openStickersAndEmoji: () -> Void
|
||||
let disableAnimations: (Bool) -> Void
|
||||
let toggleShowNextMediaOnTap: (Bool) -> Void
|
||||
let selectAppIcon: (PresentationAppIcon) -> Void
|
||||
let editTheme: (PresentationCloudTheme) -> Void
|
||||
let themeContextAction: (Bool, PresentationThemeReference, ASDisplayNode, ContextGesture?) -> Void
|
||||
let colorContextAction: (Bool, PresentationThemeReference, ThemeSettingsColorOption?, ASDisplayNode, ContextGesture?) -> Void
|
||||
|
||||
init(context: AccountContext, selectTheme: @escaping (PresentationThemeReference) -> Void, openThemeSettings: @escaping () -> Void, openWallpaperSettings: @escaping () -> Void, selectAccentColor: @escaping (PresentationThemeAccentColor?) -> Void, openAccentColorPicker: @escaping (PresentationThemeReference, Bool) -> Void, toggleNightTheme: @escaping (Bool) -> Void, openAutoNightTheme: @escaping () -> Void, openTextSize: @escaping () -> Void, openBubbleSettings: @escaping () -> Void, openPowerSavingSettings: @escaping () -> Void, openStickersAndEmoji: @escaping () -> Void, disableAnimations: @escaping (Bool) -> Void, selectAppIcon: @escaping (PresentationAppIcon) -> Void, editTheme: @escaping (PresentationCloudTheme) -> Void, themeContextAction: @escaping (Bool, PresentationThemeReference, ASDisplayNode, ContextGesture?) -> Void, colorContextAction: @escaping (Bool, PresentationThemeReference, ThemeSettingsColorOption?, ASDisplayNode, ContextGesture?) -> Void) {
|
||||
init(context: AccountContext, selectTheme: @escaping (PresentationThemeReference) -> Void, openThemeSettings: @escaping () -> Void, openWallpaperSettings: @escaping () -> Void, selectAccentColor: @escaping (PresentationThemeAccentColor?) -> Void, openAccentColorPicker: @escaping (PresentationThemeReference, Bool) -> Void, toggleNightTheme: @escaping (Bool) -> Void, openAutoNightTheme: @escaping () -> Void, openTextSize: @escaping () -> Void, openBubbleSettings: @escaping () -> Void, openPowerSavingSettings: @escaping () -> Void, openStickersAndEmoji: @escaping () -> Void, toggleShowNextMediaOnTap: @escaping (Bool) -> Void, selectAppIcon: @escaping (PresentationAppIcon) -> Void, editTheme: @escaping (PresentationCloudTheme) -> Void, themeContextAction: @escaping (Bool, PresentationThemeReference, ASDisplayNode, ContextGesture?) -> Void, colorContextAction: @escaping (Bool, PresentationThemeReference, ThemeSettingsColorOption?, ASDisplayNode, ContextGesture?) -> Void) {
|
||||
self.context = context
|
||||
self.selectTheme = selectTheme
|
||||
self.openThemeSettings = openThemeSettings
|
||||
@ -77,7 +77,7 @@ private final class ThemeSettingsControllerArguments {
|
||||
self.openBubbleSettings = openBubbleSettings
|
||||
self.openPowerSavingSettings = openPowerSavingSettings
|
||||
self.openStickersAndEmoji = openStickersAndEmoji
|
||||
self.disableAnimations = disableAnimations
|
||||
self.toggleShowNextMediaOnTap = toggleShowNextMediaOnTap
|
||||
self.selectAppIcon = selectAppIcon
|
||||
self.editTheme = editTheme
|
||||
self.themeContextAction = themeContextAction
|
||||
@ -128,7 +128,7 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
|
||||
case powerSaving
|
||||
case stickersAndEmoji
|
||||
case otherHeader(PresentationTheme, String)
|
||||
case animations(PresentationTheme, String, Bool)
|
||||
case showNextMediaOnTap(PresentationTheme, String, Bool)
|
||||
case animationsInfo(PresentationTheme, String)
|
||||
|
||||
var section: ItemListSectionId {
|
||||
@ -143,7 +143,7 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
|
||||
return ThemeSettingsControllerSection.icon.rawValue
|
||||
case .powerSaving, .stickersAndEmoji:
|
||||
return ThemeSettingsControllerSection.message.rawValue
|
||||
case .otherHeader, .animations, .animationsInfo:
|
||||
case .otherHeader, .showNextMediaOnTap, .animationsInfo:
|
||||
return ThemeSettingsControllerSection.other.rawValue
|
||||
}
|
||||
}
|
||||
@ -178,7 +178,7 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
|
||||
return 12
|
||||
case .otherHeader:
|
||||
return 13
|
||||
case .animations:
|
||||
case .showNextMediaOnTap:
|
||||
return 14
|
||||
case .animationsInfo:
|
||||
return 15
|
||||
@ -271,8 +271,8 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .animations(lhsTheme, lhsTitle, lhsValue):
|
||||
if case let .animations(rhsTheme, rhsTitle, rhsValue) = rhs, lhsTheme === rhsTheme, lhsTitle == rhsTitle, lhsValue == rhsValue {
|
||||
case let .showNextMediaOnTap(lhsTheme, lhsTitle, lhsValue):
|
||||
if case let .showNextMediaOnTap(rhsTheme, rhsTitle, rhsValue) = rhs, lhsTheme === rhsTheme, lhsTitle == rhsTitle, lhsValue == rhsValue {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
@ -343,9 +343,9 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
|
||||
})
|
||||
case let .otherHeader(_, text):
|
||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
|
||||
case let .animations(_, title, value):
|
||||
case let .showNextMediaOnTap(_, title, value):
|
||||
return ItemListSwitchItem(presentationData: presentationData, title: title, value: value, sectionId: self.section, style: .blocks, updated: { value in
|
||||
arguments.disableAnimations(value)
|
||||
arguments.toggleShowNextMediaOnTap(value)
|
||||
}, tag: ThemeSettingsEntryTag.animations)
|
||||
case let .animationsInfo(_, text):
|
||||
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section)
|
||||
@ -353,7 +353,7 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
|
||||
}
|
||||
}
|
||||
|
||||
private func themeSettingsControllerEntries(presentationData: PresentationData, presentationThemeSettings: PresentationThemeSettings, themeReference: PresentationThemeReference, availableThemes: [PresentationThemeReference], availableAppIcons: [PresentationAppIcon], currentAppIconName: String?, isPremium: Bool, chatThemes: [PresentationThemeReference], animatedEmojiStickers: [String: [StickerPackItem]]) -> [ThemeSettingsControllerEntry] {
|
||||
private func themeSettingsControllerEntries(presentationData: PresentationData, presentationThemeSettings: PresentationThemeSettings, mediaSettings: MediaDisplaySettings, themeReference: PresentationThemeReference, availableThemes: [PresentationThemeReference], availableAppIcons: [PresentationAppIcon], currentAppIconName: String?, isPremium: Bool, chatThemes: [PresentationThemeReference], animatedEmojiStickers: [String: [StickerPackItem]]) -> [ThemeSettingsControllerEntry] {
|
||||
var entries: [ThemeSettingsControllerEntry] = []
|
||||
|
||||
let strings = presentationData.strings
|
||||
@ -404,8 +404,7 @@ private func themeSettingsControllerEntries(presentationData: PresentationData,
|
||||
}
|
||||
|
||||
entries.append(.otherHeader(presentationData.theme, strings.Appearance_Other.uppercased()))
|
||||
entries.append(.animations(presentationData.theme, strings.Appearance_ReduceMotion, presentationData.reduceMotion))
|
||||
entries.append(.animationsInfo(presentationData.theme, strings.Appearance_ReduceMotionInfo))
|
||||
entries.append(.showNextMediaOnTap(presentationData.theme, strings.Appearance_ShowNextMediaOnTap, mediaSettings.showNextMediaOnTap))
|
||||
|
||||
return entries
|
||||
}
|
||||
@ -522,9 +521,9 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
|
||||
pushControllerImpl?(installedStickerPacksController(context: context, mode: .general, archivedPacks: archivedStickerPacks, updatedPacks: { _ in
|
||||
}))
|
||||
})
|
||||
}, disableAnimations: { reduceMotion in
|
||||
let _ = updatePresentationThemeSettingsInteractively(accountManager: context.sharedContext.accountManager, { current in
|
||||
return current.withUpdatedReduceMotion(reduceMotion)
|
||||
}, toggleShowNextMediaOnTap: { value in
|
||||
let _ = updateMediaDisplaySettingsInteractively(accountManager: context.sharedContext.accountManager, { current in
|
||||
return current.withUpdatedShowNextMediaOnTap(value)
|
||||
}).start()
|
||||
}, selectAppIcon: { icon in
|
||||
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId))
|
||||
@ -1000,10 +999,11 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
|
||||
})
|
||||
})
|
||||
|
||||
let signal = combineLatest(queue: .mainQueue(), context.sharedContext.presentationData, context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.presentationThemeSettings, SharedDataKeys.chatThemes]), cloudThemes.get(), availableAppIcons, currentAppIconName.get(), removedThemeIndexesPromise.get(), animatedEmojiStickers, context.account.postbox.peerView(id: context.account.peerId))
|
||||
let signal = combineLatest(queue: .mainQueue(), context.sharedContext.presentationData, context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.presentationThemeSettings, SharedDataKeys.chatThemes, ApplicationSpecificSharedDataKeys.mediaDisplaySettings]), cloudThemes.get(), availableAppIcons, currentAppIconName.get(), removedThemeIndexesPromise.get(), animatedEmojiStickers, context.account.postbox.peerView(id: context.account.peerId))
|
||||
|> map { presentationData, sharedData, cloudThemes, availableAppIcons, currentAppIconName, removedThemeIndexes, animatedEmojiStickers, peerView -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
||||
let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.presentationThemeSettings]?.get(PresentationThemeSettings.self) ?? PresentationThemeSettings.defaultSettings
|
||||
|
||||
let mediaSettings = sharedData.entries[ApplicationSpecificSharedDataKeys.mediaDisplaySettings]?.get(MediaDisplaySettings.self) ?? MediaDisplaySettings.defaultSettings
|
||||
|
||||
let isPremium = peerView.peers[peerView.peerId]?.isPremium ?? false
|
||||
|
||||
let themeReference: PresentationThemeReference
|
||||
@ -1041,7 +1041,7 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
|
||||
chatThemes.insert(.builtin(.dayClassic), at: 0)
|
||||
|
||||
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.Appearance_Title), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back))
|
||||
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: themeSettingsControllerEntries(presentationData: presentationData, presentationThemeSettings: settings, themeReference: themeReference, availableThemes: availableThemes, availableAppIcons: availableAppIcons, currentAppIconName: currentAppIconName, isPremium: isPremium, chatThemes: chatThemes, animatedEmojiStickers: animatedEmojiStickers), style: .blocks, ensureVisibleItemTag: focusOnItemTag, animateChanges: false)
|
||||
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: themeSettingsControllerEntries(presentationData: presentationData, presentationThemeSettings: settings, mediaSettings: mediaSettings, themeReference: themeReference, availableThemes: availableThemes, availableAppIcons: availableAppIcons, currentAppIconName: currentAppIconName, isPremium: isPremium, chatThemes: chatThemes, animatedEmojiStickers: animatedEmojiStickers), style: .blocks, ensureVisibleItemTag: focusOnItemTag, animateChanges: false)
|
||||
|
||||
return (controllerState, (listState, arguments))
|
||||
}
|
||||
|
@ -176,7 +176,7 @@ public class WallpaperGalleryController: ViewController {
|
||||
private let context: AccountContext
|
||||
private let source: WallpaperListSource
|
||||
private let mode: Mode
|
||||
public var apply: ((WallpaperGalleryEntry, WallpaperPresentationOptions, CGRect?) -> Void)?
|
||||
public var apply: ((WallpaperGalleryEntry, WallpaperPresentationOptions, CGRect?, CGFloat?) -> Void)?
|
||||
|
||||
private let _ready = Promise<Bool>()
|
||||
override public var ready: Promise<Bool> {
|
||||
@ -437,6 +437,12 @@ public class WallpaperGalleryController: ViewController {
|
||||
}
|
||||
|
||||
let toolbarNode = WallpaperGalleryToolbarNode(theme: presentationData.theme, strings: presentationData.strings, doneButtonType: doneButtonType)
|
||||
switch self.source {
|
||||
case .asset, .contextResult:
|
||||
toolbarNode.dark = false
|
||||
default:
|
||||
toolbarNode.dark = true
|
||||
}
|
||||
self.toolbarNode = toolbarNode
|
||||
overlayNode.addSubnode(toolbarNode)
|
||||
|
||||
@ -453,7 +459,7 @@ public class WallpaperGalleryController: ViewController {
|
||||
let entry = strongSelf.entries[centralItemNode.index]
|
||||
|
||||
if case .peer = strongSelf.mode {
|
||||
strongSelf.apply?(entry, options, centralItemNode.cropRect)
|
||||
strongSelf.apply?(entry, options, centralItemNode.cropRect, centralItemNode.brightness)
|
||||
return
|
||||
}
|
||||
|
||||
@ -611,7 +617,7 @@ public class WallpaperGalleryController: ViewController {
|
||||
break
|
||||
}
|
||||
|
||||
strongSelf.apply?(entry, options, centralItemNode.cropRect)
|
||||
strongSelf.apply?(entry, options, centralItemNode.cropRect, centralItemNode.brightness)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,8 @@ import WallpaperResources
|
||||
import AppBundle
|
||||
import WallpaperBackgroundNode
|
||||
import TextFormat
|
||||
import TooltipUI
|
||||
import TelegramNotices
|
||||
|
||||
struct WallpaperGalleryItemArguments {
|
||||
let colorPreview: Bool
|
||||
@ -83,7 +85,7 @@ private func reference(for resource: MediaResource, media: Media, message: Messa
|
||||
|
||||
final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
private let context: AccountContext
|
||||
private let presentationData: PresentationData
|
||||
private var presentationData: PresentationData
|
||||
|
||||
var entry: WallpaperGalleryEntry?
|
||||
var source: WallpaperListSource?
|
||||
@ -95,23 +97,28 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
let wrapperNode: ASDisplayNode
|
||||
let imageNode: TransformImageNode
|
||||
let nativeNode: WallpaperBackgroundNode
|
||||
let brightnessNode: ASDisplayNode
|
||||
private let statusNode: RadialStatusNode
|
||||
private let blurredNode: BlurredImageNode
|
||||
let cropNode: WallpaperCropNode
|
||||
|
||||
private var cancelButtonNode: WallpaperNavigationButtonNode
|
||||
private var shareButtonNode: WallpaperNavigationButtonNode
|
||||
private let cancelButtonNode: WallpaperNavigationButtonNode
|
||||
private let shareButtonNode: WallpaperNavigationButtonNode
|
||||
private let dayNightButtonNode: WallpaperNavigationButtonNode
|
||||
|
||||
private var blurButtonNode: WallpaperOptionButtonNode
|
||||
private var motionButtonNode: WallpaperOptionButtonNode
|
||||
private var patternButtonNode: WallpaperOptionButtonNode
|
||||
private var colorsButtonNode: WallpaperOptionButtonNode
|
||||
private var playButtonNode: WallpaperNavigationButtonNode
|
||||
private let blurButtonNode: WallpaperOptionButtonNode
|
||||
private let motionButtonNode: WallpaperOptionButtonNode
|
||||
private let patternButtonNode: WallpaperOptionButtonNode
|
||||
private let colorsButtonNode: WallpaperOptionButtonNode
|
||||
private let playButtonNode: WallpaperNavigationButtonNode
|
||||
private let sliderNode: WallpaperSliderNode
|
||||
|
||||
private let messagesContainerNode: ASDisplayNode
|
||||
private var messageNodes: [ListViewItemNode]?
|
||||
private var validMessages: [String]?
|
||||
|
||||
private let serviceBackgroundNode: NavigationBackgroundNode
|
||||
|
||||
fileprivate let _ready = Promise<Void>()
|
||||
private let fetchDisposable = MetaDisposable()
|
||||
private let statusDisposable = MetaDisposable()
|
||||
@ -135,10 +142,16 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
|
||||
private var isReadyDisposable: Disposable?
|
||||
|
||||
private var isDarkAppearance: Bool = false
|
||||
private var didChangeAppearance: Bool = false
|
||||
private var darkAppearanceIntensity: CGFloat = 0.8
|
||||
|
||||
init(context: AccountContext) {
|
||||
self.context = context
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
self.isDarkAppearance = self.presentationData.theme.overallDarkAppearance
|
||||
|
||||
self.wrapperNode = ASDisplayNode()
|
||||
self.imageNode = TransformImageNode()
|
||||
self.imageNode.contentAnimations = .subsequentUpdates
|
||||
@ -149,6 +162,8 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
self.statusNode.isUserInteractionEnabled = false
|
||||
|
||||
self.blurredNode = BlurredImageNode()
|
||||
self.brightnessNode = ASDisplayNode()
|
||||
self.brightnessNode.alpha = 0.0
|
||||
|
||||
self.messagesContainerNode = ASDisplayNode()
|
||||
self.messagesContainerNode.transform = CATransform3DMakeScale(1.0, -1.0, 1.0)
|
||||
@ -160,12 +175,24 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
self.motionButtonNode.setEnabled(false)
|
||||
self.patternButtonNode = WallpaperOptionButtonNode(title: self.presentationData.strings.WallpaperPreview_Pattern, value: .check(false))
|
||||
self.patternButtonNode.setEnabled(false)
|
||||
|
||||
self.serviceBackgroundNode = NavigationBackgroundNode(color: UIColor(rgb: 0x333333, alpha: 0.33))
|
||||
self.serviceBackgroundNode.isHidden = true
|
||||
|
||||
var sliderValueChangedImpl: ((CGFloat) -> Void)?
|
||||
self.sliderNode = WallpaperSliderNode(minValue: 0.0, maxValue: 1.0, value: 0.7, valueChanged: { value, _ in
|
||||
sliderValueChangedImpl?(value)
|
||||
})
|
||||
|
||||
self.colorsButtonNode = WallpaperOptionButtonNode(title: self.presentationData.strings.WallpaperPreview_WallpaperColors, value: .colors(false, [.clear]))
|
||||
|
||||
self.cancelButtonNode = WallpaperNavigationButtonNode(content: .text(self.presentationData.strings.Common_Cancel))
|
||||
self.shareButtonNode = WallpaperNavigationButtonNode(content: .icon(image: UIImage(bundleImageName: "Chat/Links/Share"), size: CGSize(width: 28.0, height: 28.0)))
|
||||
|
||||
self.cancelButtonNode = WallpaperNavigationButtonNode(content: .text(self.presentationData.strings.Common_Cancel), dark: true)
|
||||
self.cancelButtonNode.enableSaturation = true
|
||||
self.shareButtonNode = WallpaperNavigationButtonNode(content: .icon(image: UIImage(bundleImageName: "Chat/Links/Share"), size: CGSize(width: 28.0, height: 28.0)), dark: true)
|
||||
self.shareButtonNode.enableSaturation = true
|
||||
self.dayNightButtonNode = WallpaperNavigationButtonNode(content: .dayNight(isNight: self.isDarkAppearance), dark: true)
|
||||
self.dayNightButtonNode.enableSaturation = true
|
||||
|
||||
self.playButtonPlayImage = generateImage(CGSize(width: 48.0, height: 48.0), rotatedContext: { size, context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
context.setFillColor(UIColor.white.cgColor)
|
||||
@ -193,7 +220,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
|
||||
self.playButtonRotateImage = generateTintedImage(image: UIImage(bundleImageName: "Settings/ThemeColorRotateIcon"), color: .white)
|
||||
|
||||
self.playButtonNode = WallpaperNavigationButtonNode(content: .icon(image: self.playButtonPlayImage, size: CGSize(width: 48.0, height: 48.0)))
|
||||
self.playButtonNode = WallpaperNavigationButtonNode(content: .icon(image: self.playButtonPlayImage, size: CGSize(width: 48.0, height: 48.0)), dark: true)
|
||||
|
||||
super.init()
|
||||
|
||||
@ -217,6 +244,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
|
||||
self.addSubnode(self.wrapperNode)
|
||||
//self.addSubnode(self.statusNode)
|
||||
self.addSubnode(self.serviceBackgroundNode)
|
||||
self.addSubnode(self.messagesContainerNode)
|
||||
|
||||
self.addSubnode(self.blurButtonNode)
|
||||
@ -224,8 +252,12 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
self.addSubnode(self.patternButtonNode)
|
||||
self.addSubnode(self.colorsButtonNode)
|
||||
self.addSubnode(self.playButtonNode)
|
||||
self.addSubnode(self.sliderNode)
|
||||
self.addSubnode(self.cancelButtonNode)
|
||||
self.addSubnode(self.shareButtonNode)
|
||||
self.addSubnode(self.dayNightButtonNode)
|
||||
|
||||
self.imageNode.addSubnode(self.brightnessNode)
|
||||
|
||||
self.blurButtonNode.addTarget(self, action: #selector(self.toggleBlur), forControlEvents: .touchUpInside)
|
||||
self.motionButtonNode.addTarget(self, action: #selector(self.toggleMotion), forControlEvents: .touchUpInside)
|
||||
@ -234,6 +266,13 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
self.playButtonNode.addTarget(self, action: #selector(self.togglePlay), forControlEvents: .touchUpInside)
|
||||
self.cancelButtonNode.addTarget(self, action: #selector(self.cancelPressed), forControlEvents: .touchUpInside)
|
||||
self.shareButtonNode.addTarget(self, action: #selector(self.actionPressed), forControlEvents: .touchUpInside)
|
||||
self.dayNightButtonNode.addTarget(self, action: #selector(self.dayNightPressed), forControlEvents: .touchUpInside)
|
||||
|
||||
sliderValueChangedImpl = { [weak self] value in
|
||||
if let self {
|
||||
self.updateIntensity(transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deinit {
|
||||
@ -255,6 +294,18 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
}
|
||||
}
|
||||
|
||||
var brightness: CGFloat? {
|
||||
guard let entry = self.entry else {
|
||||
return nil
|
||||
}
|
||||
switch entry {
|
||||
case .asset, .contextResult:
|
||||
return self.sliderNode.value
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
override func ready() -> Signal<Void, NoError> {
|
||||
return self._ready.get()
|
||||
}
|
||||
@ -263,6 +314,173 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
self.action?()
|
||||
}
|
||||
|
||||
private func switchTheme() {
|
||||
if let messageNodes = self.messageNodes {
|
||||
for messageNode in messageNodes.prefix(2) {
|
||||
if let snapshotView = messageNode.view.snapshotContentTree() {
|
||||
messageNode.view.addSubview(snapshotView)
|
||||
snapshotView.frame = messageNode.bounds
|
||||
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.35, removeOnCompletion: false, completion: { [weak snapshotView] _ in
|
||||
snapshotView?.removeFromSuperview()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
let themeSettings = self.context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.presentationThemeSettings])
|
||||
|> map { sharedData -> PresentationThemeSettings in
|
||||
let themeSettings: PresentationThemeSettings
|
||||
if let current = sharedData.entries[ApplicationSpecificSharedDataKeys.presentationThemeSettings]?.get(PresentationThemeSettings.self) {
|
||||
themeSettings = current
|
||||
} else {
|
||||
themeSettings = PresentationThemeSettings.defaultSettings
|
||||
}
|
||||
return themeSettings
|
||||
}
|
||||
|
||||
let _ = (themeSettings
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] themeSettings in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
var presentationData = strongSelf.presentationData
|
||||
|
||||
let lightTheme: PresentationTheme
|
||||
let lightWallpaper: TelegramWallpaper
|
||||
|
||||
let darkTheme: PresentationTheme
|
||||
let darkWallpaper: TelegramWallpaper
|
||||
|
||||
if !strongSelf.isDarkAppearance {
|
||||
darkTheme = presentationData.theme
|
||||
darkWallpaper = presentationData.chatWallpaper
|
||||
|
||||
var currentColors = themeSettings.themeSpecificAccentColors[themeSettings.theme.index]
|
||||
if let colors = currentColors, colors.baseColor == .theme {
|
||||
currentColors = nil
|
||||
}
|
||||
|
||||
let themeSpecificWallpaper = (themeSettings.themeSpecificChatWallpapers[coloredThemeIndex(reference: themeSettings.theme, accentColor: currentColors)] ?? themeSettings.themeSpecificChatWallpapers[themeSettings.theme.index])
|
||||
|
||||
if let themeSpecificWallpaper = themeSpecificWallpaper {
|
||||
lightWallpaper = themeSpecificWallpaper
|
||||
} else {
|
||||
let theme = makePresentationTheme(mediaBox: strongSelf.context.sharedContext.accountManager.mediaBox, themeReference: themeSettings.theme, accentColor: currentColors?.color, bubbleColors: currentColors?.customBubbleColors ?? [], wallpaper: currentColors?.wallpaper, baseColor: currentColors?.baseColor, preview: true) ?? defaultPresentationTheme
|
||||
lightWallpaper = theme.chat.defaultWallpaper
|
||||
}
|
||||
|
||||
var preferredBaseTheme: TelegramBaseTheme?
|
||||
if let baseTheme = themeSettings.themePreferredBaseTheme[themeSettings.theme.index], [.classic, .day].contains(baseTheme) {
|
||||
preferredBaseTheme = baseTheme
|
||||
}
|
||||
|
||||
lightTheme = makePresentationTheme(mediaBox: strongSelf.context.sharedContext.accountManager.mediaBox, themeReference: themeSettings.theme, baseTheme: preferredBaseTheme, accentColor: currentColors?.color, bubbleColors: currentColors?.customBubbleColors ?? [], wallpaper: currentColors?.wallpaper, baseColor: currentColors?.baseColor, serviceBackgroundColor: defaultServiceBackgroundColor) ?? defaultPresentationTheme
|
||||
} else {
|
||||
lightTheme = presentationData.theme
|
||||
lightWallpaper = presentationData.chatWallpaper
|
||||
|
||||
let automaticTheme = themeSettings.automaticThemeSwitchSetting.theme
|
||||
let effectiveColors = themeSettings.themeSpecificAccentColors[automaticTheme.index]
|
||||
let themeSpecificWallpaper = (themeSettings.themeSpecificChatWallpapers[coloredThemeIndex(reference: automaticTheme, accentColor: effectiveColors)] ?? themeSettings.themeSpecificChatWallpapers[automaticTheme.index])
|
||||
|
||||
var preferredBaseTheme: TelegramBaseTheme?
|
||||
if let baseTheme = themeSettings.themePreferredBaseTheme[automaticTheme.index], [.night, .tinted].contains(baseTheme) {
|
||||
preferredBaseTheme = baseTheme
|
||||
} else {
|
||||
preferredBaseTheme = .night
|
||||
}
|
||||
|
||||
darkTheme = makePresentationTheme(mediaBox: strongSelf.context.sharedContext.accountManager.mediaBox, themeReference: automaticTheme, baseTheme: preferredBaseTheme, accentColor: effectiveColors?.color, bubbleColors: effectiveColors?.customBubbleColors ?? [], wallpaper: effectiveColors?.wallpaper, baseColor: effectiveColors?.baseColor, serviceBackgroundColor: defaultServiceBackgroundColor) ?? defaultPresentationTheme
|
||||
|
||||
if let themeSpecificWallpaper = themeSpecificWallpaper {
|
||||
darkWallpaper = themeSpecificWallpaper
|
||||
} else {
|
||||
switch lightWallpaper {
|
||||
case .builtin, .color, .gradient:
|
||||
darkWallpaper = darkTheme.chat.defaultWallpaper
|
||||
case .file:
|
||||
if lightWallpaper.isPattern {
|
||||
darkWallpaper = darkTheme.chat.defaultWallpaper
|
||||
} else {
|
||||
darkWallpaper = lightWallpaper
|
||||
}
|
||||
default:
|
||||
darkWallpaper = lightWallpaper
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if strongSelf.isDarkAppearance {
|
||||
darkTheme.forceSync = true
|
||||
Queue.mainQueue().after(1.0, {
|
||||
darkTheme.forceSync = false
|
||||
})
|
||||
presentationData = presentationData.withUpdated(theme: darkTheme).withUpdated(chatWallpaper: darkWallpaper)
|
||||
} else {
|
||||
lightTheme.forceSync = true
|
||||
Queue.mainQueue().after(1.0, {
|
||||
lightTheme.forceSync = false
|
||||
})
|
||||
presentationData = presentationData.withUpdated(theme: lightTheme).withUpdated(chatWallpaper: lightWallpaper)
|
||||
}
|
||||
|
||||
strongSelf.presentationData = presentationData
|
||||
strongSelf.nativeNode.updateBubbleTheme(bubbleTheme: presentationData.theme, bubbleCorners: presentationData.chatBubbleCorners)
|
||||
|
||||
if let (layout, _) = strongSelf.validLayout {
|
||||
strongSelf.updateMessagesLayout(layout: layout, offset: CGPoint(), transition: .animated(duration: 0.3, curve: .easeInOut))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@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))
|
||||
}
|
||||
}
|
||||
|
||||
self.switchTheme()
|
||||
}
|
||||
|
||||
private func animateIntensityChange(delay: Double) {
|
||||
let targetValue: CGFloat = self.sliderNode.value
|
||||
self.sliderNode.internalUpdateLayout(size: self.sliderNode.frame.size, value: 1.0)
|
||||
self.sliderNode.ignoreUpdates = true
|
||||
Queue.mainQueue().after(delay, {
|
||||
self.brightnessNode.backgroundColor = UIColor(rgb: 0x000000)
|
||||
self.brightnessNode.layer.compositingFilter = nil
|
||||
|
||||
self.sliderNode.ignoreUpdates = false
|
||||
let transition: ContainedViewLayoutTransition = .animated(duration: 0.35, curve: .easeInOut)
|
||||
self.sliderNode.animateValue(from: 1.0, to: targetValue, transition: transition)
|
||||
self.updateIntensity(transition: transition)
|
||||
})
|
||||
}
|
||||
|
||||
private func updateIntensity(transition: ContainedViewLayoutTransition) {
|
||||
let value = self.isDarkAppearance ? self.sliderNode.value : 1.0
|
||||
if value < 1.0 {
|
||||
self.brightnessNode.backgroundColor = UIColor(rgb: 0x000000)
|
||||
self.brightnessNode.layer.compositingFilter = nil
|
||||
transition.updateAlpha(node: self.brightnessNode, alpha: 1.0 - value)
|
||||
} else {
|
||||
self.brightnessNode.layer.compositingFilter = nil
|
||||
transition.updateAlpha(node: self.brightnessNode, alpha: 0.0)
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func cancelPressed() {
|
||||
self.dismiss()
|
||||
}
|
||||
@ -281,6 +499,8 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
}
|
||||
}
|
||||
|
||||
var showPreviewTooltip = false
|
||||
|
||||
if self.entry != entry || self.arguments.colorPreview != previousArguments.colorPreview {
|
||||
let previousEntry = self.entry
|
||||
self.entry = entry
|
||||
@ -308,7 +528,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
let progressAction = UIBarButtonItem(customDisplayNode: ProgressNavigationButtonNode(color: presentationData.theme.rootController.navigationBar.accentTextColor))
|
||||
|
||||
var isBlurrable = true
|
||||
|
||||
|
||||
self.nativeNode.updateBubbleTheme(bubbleTheme: presentationData.theme, bubbleCorners: presentationData.chatBubbleCorners)
|
||||
|
||||
switch entry {
|
||||
@ -345,7 +565,9 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
}
|
||||
case .asset:
|
||||
self.nativeNode._internalUpdateIsSettingUpWallpaper()
|
||||
self.nativeNode.isHidden = true
|
||||
|
||||
//self.nativeNode.update(wallpaper: .color(0xff000000))
|
||||
self.nativeNode.isHidden = false
|
||||
self.patternButtonNode.isSelected = false
|
||||
self.playButtonNode.setIcon(self.playButtonRotateImage)
|
||||
default:
|
||||
@ -353,7 +575,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
self.patternButtonNode.isSelected = false
|
||||
self.playButtonNode.setIcon(self.playButtonRotateImage)
|
||||
}
|
||||
|
||||
|
||||
var canShare = false
|
||||
switch entry {
|
||||
case let .wallpaper(wallpaper, message):
|
||||
@ -526,6 +748,8 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
subtitleSignal = .single(nil)
|
||||
colorSignal = .single(UIColor(rgb: 0x000000, alpha: 0.3))
|
||||
self.wrapperNode.addSubnode(self.cropNode)
|
||||
showPreviewTooltip = true
|
||||
self.serviceBackgroundNode.isHidden = false
|
||||
case let .contextResult(result):
|
||||
var imageDimensions: CGSize?
|
||||
var imageResource: TelegramMediaResource?
|
||||
@ -580,6 +804,8 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
colorSignal = .single(UIColor(rgb: 0x000000, alpha: 0.3))
|
||||
subtitleSignal = .single(nil)
|
||||
self.wrapperNode.addSubnode(self.cropNode)
|
||||
showPreviewTooltip = true
|
||||
self.serviceBackgroundNode.isHidden = false
|
||||
}
|
||||
self.contentSize = contentSize
|
||||
|
||||
@ -590,6 +816,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
self.wrapperNode.addSubnode(self.imageNode)
|
||||
self.wrapperNode.addSubnode(self.nativeNode)
|
||||
} else {
|
||||
self.wrapperNode.insertSubnode(self.nativeNode, at: 0)
|
||||
self.imageNode.contentMode = .scaleToFill
|
||||
}
|
||||
|
||||
@ -609,6 +836,14 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
}
|
||||
strongSelf.blurredNode.image = image
|
||||
imagePromise.set(.single(image))
|
||||
|
||||
if case .asset = entry, let image, let data = image.jpegData(compressionQuality: 0.5) {
|
||||
let resource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max))
|
||||
strongSelf.context.sharedContext.accountManager.mediaBox.storeResourceData(resource.id, data: data, synchronous: true)
|
||||
|
||||
let wallpaper: TelegramWallpaper = .image([TelegramMediaImageRepresentation(dimensions: PixelDimensions(image.size), resource: resource, progressiveSizes: [], immediateThumbnailData: nil, hasVideo: false, isPersonal: false)], WallpaperSettings())
|
||||
strongSelf.nativeNode.update(wallpaper: wallpaper)
|
||||
}
|
||||
}
|
||||
}
|
||||
self.fetchDisposable.set(fetchSignal.start())
|
||||
@ -660,6 +895,18 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
self.updateButtonsLayout(layout: layout, offset: CGPoint(), transition: .immediate)
|
||||
self.updateMessagesLayout(layout: layout, offset: CGPoint(), transition: .immediate)
|
||||
}
|
||||
|
||||
if showPreviewTooltip {
|
||||
Queue.mainQueue().after(0.35) {
|
||||
self.maybePresentPreviewTooltip()
|
||||
}
|
||||
if self.isDarkAppearance && !self.didChangeAppearance {
|
||||
Queue.mainQueue().justDispatch {
|
||||
self.didChangeAppearance = true
|
||||
self.animateIntensityChange(delay: 0.35)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override func screenFrameUpdated(_ frame: CGRect) {
|
||||
@ -721,7 +968,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
}
|
||||
|
||||
func setBlurEnabled(_ enabled: Bool, animated: Bool) {
|
||||
let blurRadius: CGFloat = 45.0
|
||||
let blurRadius: CGFloat = 30.0
|
||||
|
||||
var animated = animated
|
||||
if animated, let (layout, _) = self.validLayout {
|
||||
@ -732,13 +979,8 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
|
||||
if enabled {
|
||||
if self.blurredNode.supernode == nil {
|
||||
if self.cropNode.supernode != nil {
|
||||
self.blurredNode.frame = self.imageNode.bounds
|
||||
self.imageNode.addSubnode(self.blurredNode)
|
||||
} else {
|
||||
self.blurredNode.frame = self.imageNode.bounds
|
||||
self.imageNode.addSubnode(self.blurredNode)
|
||||
}
|
||||
self.blurredNode.frame = self.imageNode.bounds
|
||||
self.imageNode.insertSubnode(self.blurredNode, at: 0)
|
||||
}
|
||||
|
||||
if animated {
|
||||
@ -914,12 +1156,17 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
let buttonSize = CGSize(width: maxButtonWidth, height: 30.0)
|
||||
let alpha = 1.0 - min(1.0, max(0.0, abs(offset.y) / 50.0))
|
||||
|
||||
let additionalYOffset: CGFloat = 0.0
|
||||
/*if self.patternButtonNode.isSelected {
|
||||
additionalYOffset = -235.0
|
||||
} else if self.colorsButtonNode.isSelected {
|
||||
additionalYOffset = -235.0
|
||||
}*/
|
||||
var additionalYOffset: CGFloat = 0.0
|
||||
if let source = self.source {
|
||||
switch source {
|
||||
case .asset, .contextResult:
|
||||
if self.isDarkAppearance {
|
||||
additionalYOffset -= 44.0
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
let buttonSpacing: CGFloat = 18.0
|
||||
|
||||
@ -937,13 +1184,26 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
|
||||
var motionFrame = centerButtonFrame
|
||||
var motionAlpha: CGFloat = 0.0
|
||||
|
||||
|
||||
var colorsFrame = CGRect(origin: CGPoint(x: rightButtonFrame.maxX - colorsButtonSize.width, y: rightButtonFrame.minY), size: colorsButtonSize)
|
||||
var colorsAlpha: CGFloat = 0.0
|
||||
|
||||
let playFrame = CGRect(origin: CGPoint(x: centerButtonFrame.midX - playButtonSize.width / 2.0, y: centerButtonFrame.midY - playButtonSize.height / 2.0), size: playButtonSize)
|
||||
var playAlpha: CGFloat = 0.0
|
||||
|
||||
let sliderSize = CGSize(width: 268.0, height: 30.0)
|
||||
var sliderFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - sliderSize.width) / 2.0) + offset.x, y: layout.size.height - toolbarHeight - layout.intrinsicInsets.bottom - 52.0 + offset.y), size: sliderSize)
|
||||
var sliderAlpha: CGFloat = 0.0
|
||||
var sliderScale: CGFloat = 0.2
|
||||
if !additionalYOffset.isZero {
|
||||
sliderAlpha = 1.0
|
||||
sliderScale = 1.0
|
||||
} else {
|
||||
sliderFrame = sliderFrame.offsetBy(dx: 0.0, dy: 22.0)
|
||||
}
|
||||
|
||||
var dayNightHidden = true
|
||||
|
||||
let cancelSize = self.cancelButtonNode.measure(layout.size)
|
||||
let cancelFrame = CGRect(origin: CGPoint(x: 16.0 + offset.x, y: 16.0), size: cancelSize)
|
||||
|
||||
@ -958,11 +1218,13 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
blurFrame = leftButtonFrame
|
||||
motionAlpha = 1.0
|
||||
motionFrame = rightButtonFrame
|
||||
dayNightHidden = false
|
||||
case .contextResult:
|
||||
blurAlpha = 1.0
|
||||
blurFrame = leftButtonFrame
|
||||
motionAlpha = 1.0
|
||||
motionFrame = rightButtonFrame
|
||||
dayNightHidden = false
|
||||
case let .wallpaper(wallpaper, _):
|
||||
switch wallpaper {
|
||||
case .builtin:
|
||||
@ -1047,17 +1309,21 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
transition.updateAlpha(node: self.playButtonNode, alpha: playAlpha * alpha)
|
||||
transition.updateSublayerTransformScale(node: self.playButtonNode, scale: max(0.1, playAlpha))
|
||||
|
||||
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)
|
||||
|
||||
transition.updateFrame(node: self.cancelButtonNode, frame: cancelFrame)
|
||||
transition.updateFrame(node: self.shareButtonNode, frame: shareFrame)
|
||||
transition.updateFrame(node: self.dayNightButtonNode, frame: shareFrame)
|
||||
|
||||
self.dayNightButtonNode.isHidden = dayNightHidden
|
||||
}
|
||||
|
||||
private func updateMessagesLayout(layout: ContainerViewLayout, offset: CGPoint, transition: ContainedViewLayoutTransition) {
|
||||
let bottomInset: CGFloat = 132.0
|
||||
var bottomInset: CGFloat = 132.0
|
||||
|
||||
if self.patternButtonNode.isSelected || self.colorsButtonNode.isSelected {
|
||||
//bottomInset = 350.0
|
||||
}
|
||||
|
||||
var items: [ListViewItem] = []
|
||||
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(1))
|
||||
let otherPeerId = self.context.account.peerId
|
||||
@ -1125,6 +1391,9 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
case .asset, .contextResult:
|
||||
topMessageText = presentationData.strings.WallpaperPreview_CropTopText
|
||||
bottomMessageText = presentationData.strings.WallpaperPreview_CropBottomText
|
||||
if self.isDarkAppearance {
|
||||
bottomInset += 44.0
|
||||
}
|
||||
case .customColor:
|
||||
topMessageText = presentationData.strings.WallpaperPreview_CustomColorTopText
|
||||
bottomMessageText = presentationData.strings.WallpaperPreview_CustomColorBottomText
|
||||
@ -1139,7 +1408,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
}
|
||||
}
|
||||
|
||||
let theme = self.presentationData.theme.withUpdated(preview: true)
|
||||
let theme = self.presentationData.theme
|
||||
|
||||
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))
|
||||
@ -1157,18 +1426,15 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
|
||||
let params = ListViewItemLayoutParams(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, availableHeight: layout.size.height)
|
||||
if let messageNodes = self.messageNodes {
|
||||
if self.validMessages != [topMessageText, bottomMessageText] {
|
||||
self.validMessages = [topMessageText, bottomMessageText]
|
||||
for i in 0 ..< items.count {
|
||||
items[i].updateNode(async: { f in f() }, node: { return messageNodes[i] }, params: params, previousItem: i == 0 ? nil : items[i - 1], nextItem: i == (items.count - 1) ? nil : items[i + 1], animation: .None) { layout, apply in
|
||||
let nodeFrame = CGRect(origin: messageNodes[i].frame.origin, size: CGSize(width: layout.size.width, height: layout.size.height))
|
||||
for i in 0 ..< items.count {
|
||||
items[i].updateNode(async: { f in f() }, node: { return messageNodes[i] }, params: params, previousItem: i == 0 ? nil : items[i - 1], nextItem: i == (items.count - 1) ? nil : items[i + 1], animation: .None) { layout, apply in
|
||||
let nodeFrame = CGRect(origin: messageNodes[i].frame.origin, size: CGSize(width: layout.size.width, height: layout.size.height))
|
||||
|
||||
messageNodes[i].contentSize = layout.contentSize
|
||||
messageNodes[i].insets = layout.insets
|
||||
messageNodes[i].frame = nodeFrame
|
||||
messageNodes[i].contentSize = layout.contentSize
|
||||
messageNodes[i].insets = layout.insets
|
||||
messageNodes[i].frame = nodeFrame
|
||||
|
||||
apply(ListViewItemApply(isOnScreen: true))
|
||||
}
|
||||
apply(ListViewItemApply(isOnScreen: true))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -1187,7 +1453,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
}
|
||||
self.messageNodes = messageNodes
|
||||
}
|
||||
|
||||
|
||||
let alpha = 1.0 - min(1.0, max(0.0, abs(offset.y) / 50.0))
|
||||
|
||||
if let messageNodes = self.messageNodes {
|
||||
@ -1199,6 +1465,15 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
transition.updateAlpha(node: itemNode, alpha: alpha)
|
||||
}
|
||||
}
|
||||
|
||||
if let _ = serviceMessageText, let messageNodes = self.messageNodes, let node = messageNodes.last {
|
||||
if let backgroundNode = node.subnodes?.first?.subnodes?.first?.subnodes?.first?.subnodes?.first, let backdropNode = node.subnodes?.first?.subnodes?.first?.subnodes?.first?.subnodes?.last?.subnodes?.last?.subnodes?.first {
|
||||
backdropNode.isHidden = true
|
||||
let serviceBackgroundFrame = backgroundNode.view.convert(backgroundNode.bounds, to: self.view).offsetBy(dx: 0.0, dy: -1.0).insetBy(dx: 0.0, dy: -1.0)
|
||||
transition.updateFrame(node: self.serviceBackgroundNode, frame: serviceBackgroundFrame)
|
||||
self.serviceBackgroundNode.update(size: serviceBackgroundFrame.size, cornerRadius: serviceBackgroundFrame.height / 2.0, transition: transition)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
@ -1236,7 +1511,18 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
self.cropNode.zoom(to: CGRect(x: (contentSize.width - fittedSize.width) / 2.0, y: (contentSize.height - fittedSize.height) / 2.0, width: fittedSize.width, height: fittedSize.height))
|
||||
}
|
||||
self.blurredNode.frame = self.imageNode.bounds
|
||||
|
||||
let displayMode: WallpaperDisplayMode
|
||||
if case .regular = layout.metrics.widthClass {
|
||||
displayMode = .aspectFit
|
||||
} else {
|
||||
displayMode = .aspectFill
|
||||
}
|
||||
|
||||
self.nativeNode.frame = self.wrapperNode.bounds
|
||||
self.nativeNode.updateLayout(size: self.nativeNode.bounds.size, displayMode: displayMode, transition: .immediate)
|
||||
}
|
||||
self.brightnessNode.frame = self.imageNode.bounds
|
||||
|
||||
let additionalYOffset: CGFloat = 0.0
|
||||
|
||||
@ -1255,4 +1541,41 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
func animateWallpaperAppeared() {
|
||||
self.nativeNode.animateEvent(transition: .animated(duration: 2.0, curve: .spring), extendAnimation: true)
|
||||
}
|
||||
|
||||
private var displayedPreviewTooltip = false
|
||||
private func maybePresentPreviewTooltip() {
|
||||
guard !self.displayedPreviewTooltip else {
|
||||
return
|
||||
}
|
||||
|
||||
let frame = self.dayNightButtonNode.view.convert(self.dayNightButtonNode.bounds, to: self.view)
|
||||
let currentTimestamp = Int32(Date().timeIntervalSince1970)
|
||||
|
||||
let isDark = self.isDarkAppearance
|
||||
|
||||
let signal: Signal<(Int32, Int32), NoError>
|
||||
if isDark {
|
||||
signal = ApplicationSpecificNotice.getChatWallpaperLightPreviewTip(accountManager: self.context.sharedContext.accountManager)
|
||||
} else {
|
||||
signal = ApplicationSpecificNotice.getChatWallpaperDarkPreviewTip(accountManager: self.context.sharedContext.accountManager)
|
||||
}
|
||||
|
||||
let _ = (signal
|
||||
|> deliverOnMainQueue).start(next: { [weak self] count, timestamp in
|
||||
if let strongSelf = self, (count < 2 && currentTimestamp > timestamp + 24 * 60 * 60) {
|
||||
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()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -17,39 +17,6 @@ enum WallpaperGalleryToolbarDoneButtonType {
|
||||
case none
|
||||
}
|
||||
|
||||
final class WallpaperLightButtonBackgroundNode: ASDisplayNode {
|
||||
private let backgroundNode: NavigationBackgroundNode
|
||||
private let overlayNode: ASDisplayNode
|
||||
private let lightNode: ASDisplayNode
|
||||
|
||||
override init() {
|
||||
self.backgroundNode = NavigationBackgroundNode(color: UIColor(rgb: 0x000000, alpha: 0.01), enableBlur: true)
|
||||
self.overlayNode = ASDisplayNode()
|
||||
self.overlayNode.backgroundColor = UIColor(rgb: 0xffffff, alpha: 0.55)
|
||||
self.overlayNode.layer.compositingFilter = "overlayBlendMode"
|
||||
|
||||
self.lightNode = ASDisplayNode()
|
||||
self.lightNode.backgroundColor = UIColor(rgb: 0xf2f2f2, alpha: 0.3)
|
||||
|
||||
super.init()
|
||||
|
||||
self.clipsToBounds = true
|
||||
|
||||
self.addSubnode(self.backgroundNode)
|
||||
self.addSubnode(self.overlayNode)
|
||||
//self.addSubnode(self.lightNode)
|
||||
}
|
||||
|
||||
func updateLayout(size: CGSize) {
|
||||
let frame = CGRect(origin: .zero, size: size)
|
||||
self.backgroundNode.frame = frame
|
||||
self.overlayNode.frame = frame
|
||||
self.lightNode.frame = frame
|
||||
|
||||
self.backgroundNode.update(size: size, transition: .immediate)
|
||||
}
|
||||
}
|
||||
|
||||
final class WallpaperGalleryToolbarNode: ASDisplayNode {
|
||||
private var theme: PresentationTheme
|
||||
private let strings: PresentationStrings
|
||||
@ -65,8 +32,23 @@ final class WallpaperGalleryToolbarNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
var dark: Bool {
|
||||
didSet {
|
||||
if self.dark != oldValue {
|
||||
self.doneButtonBackgroundNode.removeFromSupernode()
|
||||
if self.dark {
|
||||
self.doneButtonBackgroundNode = WallpaperOptionBackgroundNode(enableSaturation: true)
|
||||
} else {
|
||||
self.doneButtonBackgroundNode = WallpaperLightButtonBackgroundNode()
|
||||
}
|
||||
self.doneButtonBackgroundNode.cornerRadius = 14.0
|
||||
self.insertSubnode(self.doneButtonBackgroundNode, at: 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private let doneButton = HighlightTrackingButtonNode()
|
||||
private let doneButtonBackgroundNode: WallpaperLightButtonBackgroundNode
|
||||
private var doneButtonBackgroundNode: ASDisplayNode
|
||||
|
||||
private let doneButtonTitleNode: ImmediateTextNode
|
||||
|
||||
@ -81,6 +63,7 @@ final class WallpaperGalleryToolbarNode: ASDisplayNode {
|
||||
self.strings = strings
|
||||
self.cancelButtonType = cancelButtonType
|
||||
self.doneButtonType = doneButtonType
|
||||
self.dark = false
|
||||
|
||||
self.doneButtonBackgroundNode = WallpaperLightButtonBackgroundNode()
|
||||
self.doneButtonBackgroundNode.cornerRadius = 14.0
|
||||
@ -106,7 +89,7 @@ final class WallpaperGalleryToolbarNode: ASDisplayNode {
|
||||
super.init()
|
||||
|
||||
self.addSubnode(self.doneButtonBackgroundNode)
|
||||
self.doneButtonBackgroundNode.addSubnode(self.doneButtonTitleNode)
|
||||
self.addSubnode(self.doneButtonTitleNode)
|
||||
|
||||
self.addSubnode(self.doneButtonSolidBackgroundNode)
|
||||
self.addSubnode(self.doneButtonSolidTitleNode)
|
||||
@ -196,14 +179,18 @@ final class WallpaperGalleryToolbarNode: ASDisplayNode {
|
||||
let doneFrame = CGRect(origin: CGPoint(x: inset, y: 2.0), size: CGSize(width: size.width - inset * 2.0, height: buttonHeight))
|
||||
self.doneButton.frame = doneFrame
|
||||
self.doneButtonBackgroundNode.frame = doneFrame
|
||||
self.doneButtonBackgroundNode.updateLayout(size: doneFrame.size)
|
||||
if let backgroundNode = self.doneButtonBackgroundNode as? WallpaperOptionBackgroundNode {
|
||||
backgroundNode.updateLayout(size: doneFrame.size)
|
||||
} else if let backgroundNode = self.doneButtonBackgroundNode as? WallpaperLightButtonBackgroundNode {
|
||||
backgroundNode.updateLayout(size: doneFrame.size)
|
||||
}
|
||||
self.doneButtonSolidBackgroundNode.frame = doneFrame
|
||||
|
||||
let doneTitleSize = self.doneButtonTitleNode.updateLayout(doneFrame.size)
|
||||
self.doneButtonTitleNode.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((doneFrame.width - doneTitleSize.width) / 2.0), y: floorToScreenPixels((doneFrame.height - doneTitleSize.height) / 2.0)), size: doneTitleSize)
|
||||
self.doneButtonTitleNode.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((doneFrame.width - doneTitleSize.width) / 2.0), y: floorToScreenPixels((doneFrame.height - doneTitleSize.height) / 2.0)), size: doneTitleSize).offsetBy(dx: doneFrame.minX, dy: doneFrame.minY)
|
||||
|
||||
let _ = self.doneButtonSolidTitleNode.updateLayout(doneFrame.size)
|
||||
self.doneButtonSolidTitleNode.frame = self.doneButtonTitleNode.frame.offsetBy(dx: doneFrame.minX, dy: doneFrame.minY)
|
||||
self.doneButtonSolidTitleNode.frame = self.doneButtonTitleNode.frame
|
||||
}
|
||||
|
||||
@objc func cancelPressed() {
|
||||
|
@ -5,6 +5,7 @@ import AsyncDisplayKit
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
import CheckNode
|
||||
import AnimationUI
|
||||
|
||||
enum WallpaperOptionButtonValue {
|
||||
case check(Bool)
|
||||
@ -34,28 +35,103 @@ private func generateColorsImage(diameter: CGFloat, colors: [UIColor]) -> UIImag
|
||||
})
|
||||
}
|
||||
|
||||
final class WallpaperLightButtonBackgroundNode: ASDisplayNode {
|
||||
private let backgroundNode: NavigationBackgroundNode
|
||||
private let overlayNode: ASDisplayNode
|
||||
private let lightNode: ASDisplayNode
|
||||
|
||||
override init() {
|
||||
self.backgroundNode = NavigationBackgroundNode(color: UIColor(rgb: 0x333333, alpha: 0.3), enableBlur: true, enableSaturation: false)
|
||||
self.overlayNode = ASDisplayNode()
|
||||
self.overlayNode.backgroundColor = UIColor(rgb: 0xffffff, alpha: 0.75)
|
||||
self.overlayNode.layer.compositingFilter = "overlayBlendMode"
|
||||
|
||||
self.lightNode = ASDisplayNode()
|
||||
self.lightNode.backgroundColor = UIColor(rgb: 0xf2f2f2, alpha: 0.2)
|
||||
|
||||
super.init()
|
||||
|
||||
self.clipsToBounds = true
|
||||
|
||||
self.addSubnode(self.backgroundNode)
|
||||
self.addSubnode(self.overlayNode)
|
||||
self.addSubnode(self.lightNode)
|
||||
}
|
||||
|
||||
func updateLayout(size: CGSize) {
|
||||
let frame = CGRect(origin: .zero, size: size)
|
||||
self.backgroundNode.frame = frame
|
||||
self.overlayNode.frame = frame
|
||||
self.lightNode.frame = frame
|
||||
|
||||
self.backgroundNode.update(size: size, transition: .immediate)
|
||||
}
|
||||
}
|
||||
|
||||
final class WallpaperOptionBackgroundNode: ASDisplayNode {
|
||||
private let backgroundNode: NavigationBackgroundNode
|
||||
|
||||
init(enableSaturation: Bool = false) {
|
||||
self.backgroundNode = NavigationBackgroundNode(color: UIColor(rgb: 0x333333, alpha: 0.3), enableBlur: true, enableSaturation: enableSaturation)
|
||||
|
||||
super.init()
|
||||
|
||||
self.clipsToBounds = true
|
||||
self.isUserInteractionEnabled = false
|
||||
|
||||
self.addSubnode(self.backgroundNode)
|
||||
}
|
||||
|
||||
func updateLayout(size: CGSize) {
|
||||
let frame = CGRect(origin: .zero, size: size)
|
||||
self.backgroundNode.frame = frame
|
||||
|
||||
self.backgroundNode.update(size: size, transition: .immediate)
|
||||
}
|
||||
}
|
||||
|
||||
final class WallpaperNavigationButtonNode: HighlightTrackingButtonNode {
|
||||
enum Content {
|
||||
case icon(image: UIImage?, size: CGSize)
|
||||
case text(String)
|
||||
case dayNight(isNight: Bool)
|
||||
}
|
||||
|
||||
var enableSaturation: Bool = false
|
||||
|
||||
private let content: Content
|
||||
var dark: Bool {
|
||||
didSet {
|
||||
if self.dark != oldValue {
|
||||
self.backgroundNode.removeFromSupernode()
|
||||
if self.dark {
|
||||
self.backgroundNode = WallpaperOptionBackgroundNode(enableSaturation: self.enableSaturation)
|
||||
} else {
|
||||
self.backgroundNode = WallpaperLightButtonBackgroundNode()
|
||||
}
|
||||
self.insertSubnode(self.backgroundNode, at: 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private let backgroundNode: WallpaperLightButtonBackgroundNode
|
||||
|
||||
private var backgroundNode: ASDisplayNode
|
||||
private let iconNode: ASImageNode
|
||||
|
||||
private let textNode: ImmediateTextNode
|
||||
private var animationNode: AnimationNode?
|
||||
|
||||
func setIcon(_ image: UIImage?) {
|
||||
self.iconNode.image = generateTintedImage(image: image, color: .white)
|
||||
}
|
||||
|
||||
init(content: Content) {
|
||||
init(content: Content, dark: Bool) {
|
||||
self.content = content
|
||||
self.dark = dark
|
||||
|
||||
self.backgroundNode = WallpaperLightButtonBackgroundNode()
|
||||
if dark {
|
||||
self.backgroundNode = WallpaperOptionBackgroundNode()
|
||||
} else {
|
||||
self.backgroundNode = WallpaperLightButtonBackgroundNode()
|
||||
}
|
||||
|
||||
self.iconNode = ASImageNode()
|
||||
self.iconNode.displaysAsynchronously = false
|
||||
@ -68,6 +144,12 @@ final class WallpaperNavigationButtonNode: HighlightTrackingButtonNode {
|
||||
case let .icon(icon, _):
|
||||
title = ""
|
||||
self.iconNode.image = generateTintedImage(image: icon, color: .white)
|
||||
case let .dayNight(isNight):
|
||||
title = ""
|
||||
let animationNode = AnimationNode(animation: isNight ? "anim_sun_reverse" : "anim_sun", colors: [:], scale: 1.0)
|
||||
animationNode.speed = 1.66
|
||||
animationNode.isUserInteractionEnabled = false
|
||||
self.animationNode = animationNode
|
||||
}
|
||||
|
||||
self.textNode = ImmediateTextNode()
|
||||
@ -79,26 +161,53 @@ final class WallpaperNavigationButtonNode: HighlightTrackingButtonNode {
|
||||
self.addSubnode(self.iconNode)
|
||||
self.addSubnode(self.textNode)
|
||||
|
||||
if let animationNode = self.animationNode {
|
||||
self.addSubnode(animationNode)
|
||||
}
|
||||
|
||||
self.highligthedChanged = { [weak self] highlighted in
|
||||
if let strongSelf = self {
|
||||
if highlighted {
|
||||
strongSelf.backgroundNode.layer.removeAnimation(forKey: "opacity")
|
||||
strongSelf.backgroundNode.alpha = 0.4
|
||||
|
||||
strongSelf.iconNode.layer.removeAnimation(forKey: "opacity")
|
||||
strongSelf.iconNode.alpha = 0.4
|
||||
|
||||
strongSelf.textNode.layer.removeAnimation(forKey: "opacity")
|
||||
strongSelf.textNode.alpha = 0.4
|
||||
|
||||
// if let animationNode = strongSelf.animationNode {
|
||||
// animationNode.layer.removeAnimation(forKey: "opacity")
|
||||
// animationNode.alpha = 0.4
|
||||
// }
|
||||
} else {
|
||||
strongSelf.backgroundNode.alpha = 1.0
|
||||
strongSelf.backgroundNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
|
||||
|
||||
strongSelf.iconNode.alpha = 1.0
|
||||
strongSelf.iconNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
|
||||
|
||||
strongSelf.textNode.alpha = 1.0
|
||||
strongSelf.textNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
|
||||
|
||||
// if let animationNode = strongSelf.animationNode {
|
||||
// animationNode.alpha = 1.0
|
||||
// animationNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func setIsNight(_ isNight: Bool) {
|
||||
self.animationNode?.setAnimation(name: !isNight ? "anim_sun_reverse" : "anim_sun", colors: [:])
|
||||
self.animationNode?.speed = 1.66
|
||||
self.animationNode?.playOnce()
|
||||
}
|
||||
|
||||
var buttonColor: UIColor = UIColor(rgb: 0x000000, alpha: 0.3) {
|
||||
didSet {
|
||||
// if self.buttonColor == UIColor(rgb: 0x000000, alpha: 0.3) {
|
||||
// self.backgroundNode.updateColor(color: UIColor(rgb: 0xf2f2f2, alpha: 0.75), transition: .immediate)
|
||||
// } else {
|
||||
// self.backgroundNode.updateColor(color: self.buttonColor, transition: .immediate)
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@ -111,6 +220,8 @@ final class WallpaperNavigationButtonNode: HighlightTrackingButtonNode {
|
||||
return CGSize(width: ceil(size.width) + 16.0, height: 28.0)
|
||||
case let .icon(_, size):
|
||||
return size
|
||||
case .dayNight:
|
||||
return CGSize(width: 28.0, height: 28.0)
|
||||
}
|
||||
}
|
||||
|
||||
@ -119,7 +230,11 @@ final class WallpaperNavigationButtonNode: HighlightTrackingButtonNode {
|
||||
|
||||
let size = self.bounds.size
|
||||
self.backgroundNode.frame = self.bounds
|
||||
self.backgroundNode.updateLayout(size: self.backgroundNode.bounds.size)
|
||||
if let backgroundNode = self.backgroundNode as? WallpaperOptionBackgroundNode {
|
||||
backgroundNode.updateLayout(size: self.backgroundNode.bounds.size)
|
||||
} else if let backgroundNode = self.backgroundNode as? WallpaperLightButtonBackgroundNode {
|
||||
backgroundNode.updateLayout(size: self.backgroundNode.bounds.size)
|
||||
}
|
||||
self.backgroundNode.cornerRadius = size.height / 2.0
|
||||
|
||||
self.iconNode.frame = self.bounds
|
||||
@ -127,12 +242,17 @@ final class WallpaperNavigationButtonNode: HighlightTrackingButtonNode {
|
||||
if let textSize = self.textSize {
|
||||
self.textNode.frame = CGRect(x: floorToScreenPixels((size.width - textSize.width) / 2.0), y: floorToScreenPixels((size.height - textSize.height) / 2.0), width: textSize.width, height: textSize.height)
|
||||
}
|
||||
|
||||
if let animationNode = self.animationNode {
|
||||
animationNode.bounds = CGRect(origin: .zero, size: CGSize(width: 24.0, height: 24.0))
|
||||
animationNode.position = CGPoint(x: 14.0, y: 14.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
final class WallpaperOptionButtonNode: HighlightTrackingButtonNode {
|
||||
private let backgroundNode: NavigationBackgroundNode
|
||||
private let backgroundNode: WallpaperOptionBackgroundNode
|
||||
|
||||
private let checkNode: CheckNode
|
||||
private let colorNode: ASImageNode
|
||||
@ -172,9 +292,8 @@ final class WallpaperOptionButtonNode: HighlightTrackingButtonNode {
|
||||
self._value = value
|
||||
self.title = title
|
||||
|
||||
self.backgroundNode = NavigationBackgroundNode(color: UIColor(rgb: 0x000000, alpha: 0.01))
|
||||
self.backgroundNode.cornerRadius = 14.0
|
||||
|
||||
self.backgroundNode = WallpaperOptionBackgroundNode()
|
||||
|
||||
self.checkNode = CheckNode(theme: CheckNodeTheme(backgroundColor: .white, strokeColor: .clear, borderColor: .white, overlayBorder: false, hasInset: false, hasShadow: false, borderWidth: 1.5))
|
||||
self.checkNode.isUserInteractionEnabled = false
|
||||
|
||||
@ -186,6 +305,9 @@ final class WallpaperOptionButtonNode: HighlightTrackingButtonNode {
|
||||
|
||||
super.init()
|
||||
|
||||
self.clipsToBounds = true
|
||||
self.cornerRadius = 14.0
|
||||
|
||||
switch value {
|
||||
case let .check(selected):
|
||||
self.checkNode.isHidden = false
|
||||
@ -202,6 +324,7 @@ final class WallpaperOptionButtonNode: HighlightTrackingButtonNode {
|
||||
}
|
||||
|
||||
self.addSubnode(self.backgroundNode)
|
||||
|
||||
self.addSubnode(self.checkNode)
|
||||
self.addSubnode(self.textNode)
|
||||
self.addSubnode(self.colorNode)
|
||||
@ -227,11 +350,6 @@ final class WallpaperOptionButtonNode: HighlightTrackingButtonNode {
|
||||
|
||||
var buttonColor: UIColor = UIColor(rgb: 0x000000, alpha: 0.3) {
|
||||
didSet {
|
||||
// if self.buttonColor == UIColor(rgb: 0x000000, alpha: 0.3) {
|
||||
// self.backgroundNode.updateColor(color: UIColor(rgb: 0xf2f2f2, alpha: 0.75), transition: .immediate)
|
||||
// } else {
|
||||
// self.backgroundNode.updateColor(color: self.buttonColor, transition: .immediate)
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@ -322,7 +440,7 @@ final class WallpaperOptionButtonNode: HighlightTrackingButtonNode {
|
||||
super.layout()
|
||||
|
||||
self.backgroundNode.frame = self.bounds
|
||||
self.backgroundNode.update(size: self.backgroundNode.bounds.size, cornerRadius: 15.0, transition: .immediate)
|
||||
self.backgroundNode.updateLayout(size: self.backgroundNode.bounds.size)
|
||||
|
||||
guard let _ = self.textSize else {
|
||||
return
|
||||
@ -340,3 +458,159 @@ final class WallpaperOptionButtonNode: HighlightTrackingButtonNode {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final class WallpaperSliderNode: ASDisplayNode {
|
||||
let minValue: CGFloat
|
||||
let maxValue: CGFloat
|
||||
var value: CGFloat = 1.0 {
|
||||
didSet {
|
||||
if let size = self.validLayout {
|
||||
self.updateLayout(size: size)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private let backgroundNode: NavigationBackgroundNode
|
||||
|
||||
private let foregroundNode: ASDisplayNode
|
||||
private let foregroundLightNode: ASDisplayNode
|
||||
private let leftIconNode: ASImageNode
|
||||
private let rightIconNode: ASImageNode
|
||||
|
||||
private let valueChanged: (CGFloat, Bool) -> Void
|
||||
|
||||
private let hapticFeedback = HapticFeedback()
|
||||
|
||||
private var validLayout: CGSize?
|
||||
|
||||
init(minValue: CGFloat, maxValue: CGFloat, value: CGFloat, valueChanged: @escaping (CGFloat, Bool) -> Void) {
|
||||
self.minValue = minValue
|
||||
self.maxValue = maxValue
|
||||
self.value = value
|
||||
self.valueChanged = valueChanged
|
||||
|
||||
self.backgroundNode = NavigationBackgroundNode(color: UIColor(rgb: 0x333333, alpha: 0.3), enableBlur: true, enableSaturation: false)
|
||||
|
||||
self.foregroundNode = ASDisplayNode()
|
||||
self.foregroundNode.clipsToBounds = true
|
||||
self.foregroundNode.cornerRadius = 3.0
|
||||
self.foregroundNode.isAccessibilityElement = false
|
||||
self.foregroundNode.backgroundColor = UIColor(rgb: 0xffffff, alpha: 0.75)
|
||||
self.foregroundNode.layer.compositingFilter = "overlayBlendMode"
|
||||
self.foregroundNode.isUserInteractionEnabled = false
|
||||
|
||||
self.foregroundLightNode = ASDisplayNode()
|
||||
self.foregroundLightNode.clipsToBounds = true
|
||||
self.foregroundLightNode.cornerRadius = 3.0
|
||||
self.foregroundLightNode.backgroundColor = UIColor(rgb: 0xf2f2f2, alpha: 0.2)
|
||||
|
||||
self.leftIconNode = ASImageNode()
|
||||
self.leftIconNode.displaysAsynchronously = false
|
||||
self.leftIconNode.image = UIImage(bundleImageName: "Settings/WallpaperBrightnessMin")
|
||||
self.leftIconNode.contentMode = .center
|
||||
|
||||
self.rightIconNode = ASImageNode()
|
||||
self.rightIconNode.displaysAsynchronously = false
|
||||
self.rightIconNode.image = UIImage(bundleImageName: "Settings/WallpaperBrightnessMax")
|
||||
self.rightIconNode.contentMode = .center
|
||||
|
||||
super.init()
|
||||
|
||||
self.clipsToBounds = true
|
||||
self.cornerRadius = 15.0
|
||||
self.isUserInteractionEnabled = true
|
||||
|
||||
self.addSubnode(self.backgroundNode)
|
||||
|
||||
self.addSubnode(self.foregroundNode)
|
||||
self.addSubnode(self.foregroundLightNode)
|
||||
|
||||
self.addSubnode(self.leftIconNode)
|
||||
self.addSubnode(self.rightIconNode)
|
||||
}
|
||||
|
||||
override func didLoad() {
|
||||
super.didLoad()
|
||||
|
||||
let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(self.panGesture(_:)))
|
||||
self.view.addGestureRecognizer(panGestureRecognizer)
|
||||
|
||||
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:)))
|
||||
self.view.addGestureRecognizer(tapGestureRecognizer)
|
||||
}
|
||||
|
||||
var ignoreUpdates = false
|
||||
func animateValue(from: CGFloat, to: CGFloat, transition: ContainedViewLayoutTransition = .immediate) {
|
||||
guard let size = self.validLayout else {
|
||||
return
|
||||
}
|
||||
self.internalUpdateLayout(size: size, value: from)
|
||||
self.internalUpdateLayout(size: size, value: to, transition: transition)
|
||||
}
|
||||
|
||||
func internalUpdateLayout(size: CGSize, value: CGFloat, transition: ContainedViewLayoutTransition = .immediate) {
|
||||
self.validLayout = size
|
||||
|
||||
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: .zero, size: size))
|
||||
self.backgroundNode.update(size: size, transition: transition)
|
||||
|
||||
if let icon = self.leftIconNode.image {
|
||||
transition.updateFrame(node: self.leftIconNode, frame: CGRect(origin: CGPoint(x: 7.0, y: floorToScreenPixels((size.height - icon.size.height) / 2.0)), size: icon.size))
|
||||
}
|
||||
|
||||
if let icon = self.rightIconNode.image {
|
||||
transition.updateFrame(node: self.rightIconNode, frame: CGRect(origin: CGPoint(x: size.width - icon.size.width - 6.0, y: floorToScreenPixels((size.height - icon.size.height) / 2.0)), size: icon.size))
|
||||
}
|
||||
|
||||
let range = self.maxValue - self.minValue
|
||||
let value = (value - self.minValue) / range
|
||||
let foregroundFrame = CGRect(origin: CGPoint(), size: CGSize(width: value * size.width, height: size.height))
|
||||
transition.updateFrame(node: self.foregroundNode, frame: foregroundFrame)
|
||||
transition.updateFrame(node: self.foregroundLightNode, frame: foregroundFrame)
|
||||
}
|
||||
|
||||
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition = .immediate) {
|
||||
guard !self.ignoreUpdates else {
|
||||
return
|
||||
}
|
||||
self.internalUpdateLayout(size: size, value: self.value, transition: transition)
|
||||
}
|
||||
|
||||
@objc private func panGesture(_ gestureRecognizer: UIPanGestureRecognizer) {
|
||||
let range = self.maxValue - self.minValue
|
||||
switch gestureRecognizer.state {
|
||||
case .began:
|
||||
break
|
||||
case .changed:
|
||||
let previousValue = self.value
|
||||
|
||||
let translation: CGFloat = gestureRecognizer.translation(in: gestureRecognizer.view).x
|
||||
let delta = translation / self.bounds.width * range
|
||||
self.value = max(self.minValue, min(self.maxValue, self.value + delta))
|
||||
gestureRecognizer.setTranslation(CGPoint(), in: gestureRecognizer.view)
|
||||
|
||||
if self.value == 0.0 && previousValue != 0.0 {
|
||||
self.hapticFeedback.impact(.soft)
|
||||
} else if self.value == 1.0 && previousValue != 1.0 {
|
||||
self.hapticFeedback.impact(.soft)
|
||||
}
|
||||
if abs(previousValue - self.value) >= 0.001 {
|
||||
self.valueChanged(self.value, false)
|
||||
}
|
||||
case .ended:
|
||||
let translation: CGFloat = gestureRecognizer.translation(in: gestureRecognizer.view).x
|
||||
let delta = translation / self.bounds.width * range
|
||||
self.value = max(self.minValue, min(self.maxValue, self.value + delta))
|
||||
self.valueChanged(self.value, true)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func tapGesture(_ gestureRecognizer: UITapGestureRecognizer) {
|
||||
let range = self.maxValue - self.minValue
|
||||
let location = gestureRecognizer.location(in: gestureRecognizer.view)
|
||||
self.value = max(self.minValue, min(self.maxValue, self.minValue + location.x / self.bounds.width * range))
|
||||
self.valueChanged(self.value, true)
|
||||
}
|
||||
}
|
||||
|
@ -526,7 +526,7 @@ public final class MediaNavigationAccessoryHeaderNode: ASDisplayNode, UIScrollVi
|
||||
let _ = (ApplicationSpecificNotice.incrementAudioRateOptionsTip(accountManager: self.context.sharedContext.accountManager)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] value in
|
||||
if let strongSelf = self, let controller = strongSelf.getController?(), value == 2 {
|
||||
let tooltipController = TooltipScreen(account: strongSelf.context.account, text: strongSelf.strings.Conversation_AudioRateOptionsTooltip, style: .default, icon: nil, location: .point(frame.offsetBy(dx: 0.0, dy: 4.0), .bottom), displayDuration: .custom(3.0), inset: 3.0, shouldDismissOnTouch: { _ in
|
||||
let tooltipController = TooltipScreen(account: strongSelf.context.account, sharedContext: strongSelf.context.sharedContext, text: strongSelf.strings.Conversation_AudioRateOptionsTooltip, style: .default, icon: nil, location: .point(frame.offsetBy(dx: 0.0, dy: 4.0), .bottom), displayDuration: .custom(3.0), inset: 3.0, shouldDismissOnTouch: { _ in
|
||||
return .dismiss(consume: false)
|
||||
})
|
||||
controller.present(tooltipController, in: .window(.root))
|
||||
|
@ -760,8 +760,8 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
|
||||
}) else {
|
||||
return
|
||||
}
|
||||
|
||||
self.present?(TooltipScreen(account: self.account, text: self.presentationData.strings.Call_CameraOrScreenTooltip, style: .light, icon: nil, location: .point(location.offsetBy(dx: 0.0, dy: -14.0), .bottom), displayDuration: .custom(5.0), shouldDismissOnTouch: { _ in
|
||||
|
||||
self.present?(TooltipScreen(account: self.account, sharedContext: self.sharedContext, text: self.presentationData.strings.Call_CameraOrScreenTooltip, style: .light, icon: nil, location: .point(location.offsetBy(dx: 0.0, dy: -14.0), .bottom), displayDuration: .custom(5.0), shouldDismissOnTouch: { _ in
|
||||
return .dismiss(consume: false)
|
||||
}))
|
||||
}
|
||||
|
@ -2310,7 +2310,7 @@ public final class VoiceChatControllerImpl: ViewController, VoiceChatController
|
||||
} else {
|
||||
text = presentationData.strings.VoiceChat_RecordingInProgress
|
||||
}
|
||||
strongSelf.controller?.present(TooltipScreen(account: strongSelf.context.account, text: text, icon: nil, location: .point(location.offsetBy(dx: 1.0, dy: 0.0), .top), displayDuration: .custom(3.0), shouldDismissOnTouch: { _ in
|
||||
strongSelf.controller?.present(TooltipScreen(account: strongSelf.context.account, sharedContext: strongSelf.context.sharedContext, text: text, icon: nil, location: .point(location.offsetBy(dx: 1.0, dy: 0.0), .top), displayDuration: .custom(3.0), shouldDismissOnTouch: { _ in
|
||||
return .dismiss(consume: true)
|
||||
}), in: .window(.root))
|
||||
}
|
||||
@ -3507,7 +3507,7 @@ public final class VoiceChatControllerImpl: ViewController, VoiceChatController
|
||||
if !callState.subscribedToScheduled {
|
||||
let location = self.actionButton.view.convert(self.actionButton.bounds, to: self.view).center
|
||||
let point = CGRect(origin: CGPoint(x: location.x - 5.0, y: location.y - 5.0 - 68.0), size: CGSize(width: 10.0, height: 10.0))
|
||||
self.controller?.present(TooltipScreen(account: self.context.account, text: self.presentationData.strings.VoiceChat_ReminderNotify, style: .gradient(UIColor(rgb: 0x262c5a), UIColor(rgb: 0x5d2835)), icon: nil, location: .point(point, .bottom), displayDuration: .custom(3.0), shouldDismissOnTouch: { _ in
|
||||
self.controller?.present(TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: self.presentationData.strings.VoiceChat_ReminderNotify, style: .gradient(UIColor(rgb: 0x262c5a), UIColor(rgb: 0x5d2835)), icon: nil, location: .point(point, .bottom), displayDuration: .custom(3.0), shouldDismissOnTouch: { _ in
|
||||
return .dismiss(consume: false)
|
||||
}), in: .window(.root))
|
||||
}
|
||||
@ -6411,7 +6411,7 @@ public final class VoiceChatControllerImpl: ViewController, VoiceChatController
|
||||
point.origin.y += 32.0
|
||||
}
|
||||
}
|
||||
self.controller?.present(TooltipScreen(account: self.context.account, text: self.presentationData.strings.VoiceChat_UnmuteSuggestion, style: .gradient(UIColor(rgb: 0x1d446c), UIColor(rgb: 0x193e63)), icon: nil, location: .point(point, position), displayDuration: .custom(8.0), shouldDismissOnTouch: { _ in
|
||||
self.controller?.present(TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: self.presentationData.strings.VoiceChat_UnmuteSuggestion, style: .gradient(UIColor(rgb: 0x1d446c), UIColor(rgb: 0x193e63)), icon: nil, location: .point(point, position), displayDuration: .custom(8.0), shouldDismissOnTouch: { _ in
|
||||
return .dismiss(consume: false)
|
||||
}), in: .window(.root))
|
||||
}
|
||||
|
@ -170,6 +170,8 @@ private enum ApplicationSpecificGlobalNotice: Int32 {
|
||||
case audioRateOptionsTip = 36
|
||||
case translationSuggestion = 37
|
||||
case sendWhenOnlineTip = 38
|
||||
case chatWallpaperLightPreviewTip = 39
|
||||
case chatWallpaperDarkPreviewTip = 40
|
||||
|
||||
var key: ValueBoxKey {
|
||||
let v = ValueBoxKey(length: 4)
|
||||
@ -332,6 +334,14 @@ private struct ApplicationSpecificNoticeKeys {
|
||||
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.chatSpecificThemeDarkPreviewTip.key)
|
||||
}
|
||||
|
||||
static func chatWallpaperLightPreviewTip() -> NoticeEntryKey {
|
||||
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.chatWallpaperLightPreviewTip.key)
|
||||
}
|
||||
|
||||
static func chatWallpaperDarkPreviewTip() -> NoticeEntryKey {
|
||||
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.chatWallpaperDarkPreviewTip.key)
|
||||
}
|
||||
|
||||
static func chatForwardOptionsTip() -> NoticeEntryKey {
|
||||
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.chatForwardOptionsTip.key)
|
||||
}
|
||||
@ -1109,6 +1119,60 @@ public struct ApplicationSpecificNotice {
|
||||
}
|
||||
}
|
||||
|
||||
public static func getChatWallpaperLightPreviewTip(accountManager: AccountManager<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> {
|
||||
return accountManager.transaction { transaction -> Int32 in
|
||||
if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatForwardOptionsTip())?.get(ApplicationSpecificCounterNotice.self) {
|
||||
|
@ -218,16 +218,18 @@ public final class InitialPresentationDataAndSettings {
|
||||
public let callListSettings: CallListSettings
|
||||
public let inAppNotificationSettings: InAppNotificationSettings
|
||||
public let mediaInputSettings: MediaInputSettings
|
||||
public let mediaDisplaySettings: MediaDisplaySettings
|
||||
public let stickerSettings: StickerSettings
|
||||
public let experimentalUISettings: ExperimentalUISettings
|
||||
|
||||
public init(presentationData: PresentationData, automaticMediaDownloadSettings: MediaAutoDownloadSettings, autodownloadSettings: AutodownloadSettings, callListSettings: CallListSettings, inAppNotificationSettings: InAppNotificationSettings, mediaInputSettings: MediaInputSettings, stickerSettings: StickerSettings, experimentalUISettings: ExperimentalUISettings) {
|
||||
public init(presentationData: PresentationData, automaticMediaDownloadSettings: MediaAutoDownloadSettings, autodownloadSettings: AutodownloadSettings, callListSettings: CallListSettings, inAppNotificationSettings: InAppNotificationSettings, mediaInputSettings: MediaInputSettings, mediaDisplaySettings: MediaDisplaySettings, stickerSettings: StickerSettings, experimentalUISettings: ExperimentalUISettings) {
|
||||
self.presentationData = presentationData
|
||||
self.automaticMediaDownloadSettings = automaticMediaDownloadSettings
|
||||
self.autodownloadSettings = autodownloadSettings
|
||||
self.callListSettings = callListSettings
|
||||
self.inAppNotificationSettings = inAppNotificationSettings
|
||||
self.mediaInputSettings = mediaInputSettings
|
||||
self.mediaDisplaySettings = mediaDisplaySettings
|
||||
self.stickerSettings = stickerSettings
|
||||
self.experimentalUISettings = experimentalUISettings
|
||||
}
|
||||
@ -242,6 +244,7 @@ public func currentPresentationDataAndSettings(accountManager: AccountManager<Te
|
||||
var callListSettings: PreferencesEntry?
|
||||
var inAppNotificationSettings: PreferencesEntry?
|
||||
var mediaInputSettings: PreferencesEntry?
|
||||
var mediaDisplaySettings: PreferencesEntry?
|
||||
var experimentalUISettings: PreferencesEntry?
|
||||
var contactSynchronizationSettings: PreferencesEntry?
|
||||
var stickerSettings: PreferencesEntry?
|
||||
@ -254,6 +257,7 @@ public func currentPresentationDataAndSettings(accountManager: AccountManager<Te
|
||||
callListSettings: PreferencesEntry?,
|
||||
inAppNotificationSettings: PreferencesEntry?,
|
||||
mediaInputSettings: PreferencesEntry?,
|
||||
mediaDisplaySettings: PreferencesEntry?,
|
||||
experimentalUISettings: PreferencesEntry?,
|
||||
contactSynchronizationSettings: PreferencesEntry?,
|
||||
stickerSettings: PreferencesEntry?
|
||||
@ -265,6 +269,7 @@ public func currentPresentationDataAndSettings(accountManager: AccountManager<Te
|
||||
self.callListSettings = callListSettings
|
||||
self.inAppNotificationSettings = inAppNotificationSettings
|
||||
self.mediaInputSettings = mediaInputSettings
|
||||
self.mediaDisplaySettings = mediaDisplaySettings
|
||||
self.experimentalUISettings = experimentalUISettings
|
||||
self.contactSynchronizationSettings = contactSynchronizationSettings
|
||||
self.stickerSettings = stickerSettings
|
||||
@ -279,6 +284,7 @@ public func currentPresentationDataAndSettings(accountManager: AccountManager<Te
|
||||
let callListSettings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.callListSettings)
|
||||
let inAppNotificationSettings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.inAppNotificationSettings)
|
||||
let mediaInputSettings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.mediaInputSettings)
|
||||
let mediaDisplaySettings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.mediaDisplaySettings)
|
||||
let experimentalUISettings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.experimentalUISettings)
|
||||
let contactSynchronizationSettings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.contactSynchronizationSettings)
|
||||
let stickerSettings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.stickerSettings)
|
||||
@ -291,6 +297,7 @@ public func currentPresentationDataAndSettings(accountManager: AccountManager<Te
|
||||
callListSettings: callListSettings,
|
||||
inAppNotificationSettings: inAppNotificationSettings,
|
||||
mediaInputSettings: mediaInputSettings,
|
||||
mediaDisplaySettings: mediaDisplaySettings,
|
||||
experimentalUISettings: experimentalUISettings,
|
||||
contactSynchronizationSettings: contactSynchronizationSettings,
|
||||
stickerSettings: stickerSettings
|
||||
@ -347,6 +354,13 @@ public func currentPresentationDataAndSettings(accountManager: AccountManager<Te
|
||||
mediaInputSettings = MediaInputSettings.defaultSettings
|
||||
}
|
||||
|
||||
let mediaDisplaySettings: MediaDisplaySettings
|
||||
if let value = internalData.mediaDisplaySettings?.get(MediaDisplaySettings.self) {
|
||||
mediaDisplaySettings = value
|
||||
} else {
|
||||
mediaDisplaySettings = MediaDisplaySettings.defaultSettings
|
||||
}
|
||||
|
||||
let stickerSettings: StickerSettings
|
||||
if let value = internalData.stickerSettings?.get(StickerSettings.self) {
|
||||
stickerSettings = value
|
||||
@ -402,7 +416,7 @@ public func currentPresentationDataAndSettings(accountManager: AccountManager<Te
|
||||
|
||||
let chatBubbleCorners = PresentationChatBubbleCorners(mainRadius: CGFloat(themeSettings.chatBubbleSettings.mainRadius), auxiliaryRadius: CGFloat(themeSettings.chatBubbleSettings.auxiliaryRadius), mergeBubbleCorners: themeSettings.chatBubbleSettings.mergeBubbleCorners)
|
||||
|
||||
return InitialPresentationDataAndSettings(presentationData: PresentationData(strings: stringsValue, theme: theme, autoNightModeTriggered: autoNightModeTriggered, chatWallpaper: effectiveChatWallpaper, chatFontSize: chatFontSize, chatBubbleCorners: chatBubbleCorners, listsFontSize: listsFontSize, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, nameSortOrder: nameSortOrder, reduceMotion: themeSettings.reduceMotion, largeEmoji: themeSettings.largeEmoji), automaticMediaDownloadSettings: automaticMediaDownloadSettings, autodownloadSettings: autodownloadSettings, callListSettings: callListSettings, inAppNotificationSettings: inAppNotificationSettings, mediaInputSettings: mediaInputSettings, stickerSettings: stickerSettings, experimentalUISettings: experimentalUISettings)
|
||||
return InitialPresentationDataAndSettings(presentationData: PresentationData(strings: stringsValue, theme: theme, autoNightModeTriggered: autoNightModeTriggered, chatWallpaper: effectiveChatWallpaper, chatFontSize: chatFontSize, chatBubbleCorners: chatBubbleCorners, listsFontSize: listsFontSize, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, nameSortOrder: nameSortOrder, reduceMotion: themeSettings.reduceMotion, largeEmoji: themeSettings.largeEmoji), automaticMediaDownloadSettings: automaticMediaDownloadSettings, autodownloadSettings: autodownloadSettings, callListSettings: callListSettings, inAppNotificationSettings: inAppNotificationSettings, mediaInputSettings: mediaInputSettings, mediaDisplaySettings: mediaDisplaySettings, stickerSettings: stickerSettings, experimentalUISettings: experimentalUISettings)
|
||||
}
|
||||
}
|
||||
|
||||
|
12
submodules/TelegramUI/Images.xcassets/Settings/WallpaperBrightnessMax.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Settings/WallpaperBrightnessMax.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "brightness_max.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
135
submodules/TelegramUI/Images.xcassets/Settings/WallpaperBrightnessMax.imageset/brightness_max.pdf
vendored
Normal file
135
submodules/TelegramUI/Images.xcassets/Settings/WallpaperBrightnessMax.imageset/brightness_max.pdf
vendored
Normal file
@ -0,0 +1,135 @@
|
||||
%PDF-1.7
|
||||
|
||||
1 0 obj
|
||||
<< >>
|
||||
endobj
|
||||
|
||||
2 0 obj
|
||||
<< /Length 3 0 R >>
|
||||
stream
|
||||
/DeviceRGB CS
|
||||
/DeviceRGB cs
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm
|
||||
1.000000 1.000000 1.000000 scn
|
||||
9.140625 16.273438 m
|
||||
9.140625 16.648438 8.828125 16.960938 8.453125 16.960938 c
|
||||
8.085938 16.960938 7.773438 16.648438 7.773438 16.273438 c
|
||||
7.773438 14.632812 l
|
||||
7.773438 14.265625 8.085938 13.953125 8.453125 13.953125 c
|
||||
8.828125 13.953125 9.140625 14.265625 9.140625 14.632812 c
|
||||
9.140625 16.273438 l
|
||||
h
|
||||
12.312500 13.296875 m
|
||||
12.054688 13.031250 12.054688 12.601562 12.312500 12.335938 c
|
||||
12.578125 12.078125 13.015625 12.070312 13.281250 12.335938 c
|
||||
14.445312 13.500000 l
|
||||
14.710938 13.765625 14.710938 14.210938 14.445312 14.468750 c
|
||||
14.187500 14.734375 13.750000 14.734375 13.492188 14.468750 c
|
||||
12.312500 13.296875 l
|
||||
h
|
||||
3.625000 12.335938 m
|
||||
3.890625 12.078125 4.328125 12.078125 4.585938 12.335938 c
|
||||
4.851562 12.585938 4.851562 13.039062 4.593750 13.296875 c
|
||||
3.429688 14.468750 l
|
||||
3.179688 14.726562 2.734375 14.734375 2.468750 14.468750 c
|
||||
2.210938 14.210938 2.210938 13.765625 2.460938 13.507812 c
|
||||
3.625000 12.335938 l
|
||||
h
|
||||
8.453125 12.468750 m
|
||||
6.273438 12.468750 4.468750 10.664062 4.468750 8.476562 c
|
||||
4.468750 6.296875 6.273438 4.492188 8.453125 4.492188 c
|
||||
10.625000 4.492188 12.429688 6.296875 12.429688 8.476562 c
|
||||
12.429688 10.664062 10.625000 12.468750 8.453125 12.468750 c
|
||||
h
|
||||
16.226562 7.796875 m
|
||||
16.601562 7.796875 16.914062 8.109375 16.914062 8.476562 c
|
||||
16.914062 8.843750 16.601562 9.156250 16.226562 9.156250 c
|
||||
14.593750 9.156250 l
|
||||
14.226562 9.156250 13.914062 8.843750 13.914062 8.476562 c
|
||||
13.914062 8.109375 14.226562 7.796875 14.593750 7.796875 c
|
||||
16.226562 7.796875 l
|
||||
h
|
||||
0.679688 9.156250 m
|
||||
0.312500 9.156250 0.000000 8.843750 0.000000 8.476562 c
|
||||
0.000000 8.109375 0.312500 7.796875 0.679688 7.796875 c
|
||||
2.312500 7.796875 l
|
||||
2.687500 7.796875 3.000000 8.109375 3.000000 8.476562 c
|
||||
3.000000 8.843750 2.687500 9.156250 2.312500 9.156250 c
|
||||
0.679688 9.156250 l
|
||||
h
|
||||
13.273438 4.609375 m
|
||||
13.015625 4.875000 12.578125 4.875000 12.312500 4.609375 c
|
||||
12.054688 4.351562 12.054688 3.914062 12.312500 3.648438 c
|
||||
13.492188 2.476562 l
|
||||
13.750000 2.218750 14.187500 2.226562 14.445312 2.484375 c
|
||||
14.710938 2.750000 14.710938 3.187500 14.445312 3.445312 c
|
||||
13.273438 4.609375 l
|
||||
h
|
||||
2.460938 3.453125 m
|
||||
2.203125 3.195312 2.203125 2.757812 2.453125 2.492188 c
|
||||
2.710938 2.234375 3.156250 2.226562 3.421875 2.484375 c
|
||||
4.585938 3.648438 l
|
||||
4.851562 3.906250 4.851562 4.343750 4.593750 4.609375 c
|
||||
4.335938 4.867188 3.890625 4.867188 3.625000 4.609375 c
|
||||
2.460938 3.453125 l
|
||||
h
|
||||
9.140625 2.320312 m
|
||||
9.140625 2.695312 8.828125 3.007812 8.453125 3.007812 c
|
||||
8.085938 3.007812 7.773438 2.695312 7.773438 2.320312 c
|
||||
7.773438 0.679688 l
|
||||
7.773438 0.312500 8.085938 0.000000 8.453125 0.000000 c
|
||||
8.828125 0.000000 9.140625 0.312500 9.140625 0.679688 c
|
||||
9.140625 2.320312 l
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
2760
|
||||
endobj
|
||||
|
||||
4 0 obj
|
||||
<< /Annots []
|
||||
/Type /Page
|
||||
/MediaBox [ 0.000000 0.000000 16.914062 16.960938 ]
|
||||
/Resources 1 0 R
|
||||
/Contents 2 0 R
|
||||
/Parent 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
5 0 obj
|
||||
<< /Kids [ 4 0 R ]
|
||||
/Count 1
|
||||
/Type /Pages
|
||||
>>
|
||||
endobj
|
||||
|
||||
6 0 obj
|
||||
<< /Pages 5 0 R
|
||||
/Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 7
|
||||
0000000000 65535 f
|
||||
0000000010 00000 n
|
||||
0000000034 00000 n
|
||||
0000002850 00000 n
|
||||
0000002873 00000 n
|
||||
0000003046 00000 n
|
||||
0000003120 00000 n
|
||||
trailer
|
||||
<< /ID [ (some) (id) ]
|
||||
/Root 6 0 R
|
||||
/Size 7
|
||||
>>
|
||||
startxref
|
||||
3179
|
||||
%%EOF
|
12
submodules/TelegramUI/Images.xcassets/Settings/WallpaperBrightnessMin.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Settings/WallpaperBrightnessMin.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "brightness_min.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
198
submodules/TelegramUI/Images.xcassets/Settings/WallpaperBrightnessMin.imageset/brightness_min.pdf
vendored
Normal file
198
submodules/TelegramUI/Images.xcassets/Settings/WallpaperBrightnessMin.imageset/brightness_min.pdf
vendored
Normal file
@ -0,0 +1,198 @@
|
||||
%PDF-1.7
|
||||
|
||||
1 0 obj
|
||||
<< /Length 2 0 R >>
|
||||
stream
|
||||
1.154297 0 0.087402 -0.137207 1.066895 1.066895 d1
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
2 0 obj
|
||||
51
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
[ 1.154297 ]
|
||||
endobj
|
||||
|
||||
4 0 obj
|
||||
<< /Length 5 0 R >>
|
||||
stream
|
||||
/CIDInit /ProcSet findresource begin
|
||||
12 dict begin
|
||||
begincmap
|
||||
/CIDSystemInfo
|
||||
<< /Registry (FigmaPDF)
|
||||
/Ordering (FigmaPDF)
|
||||
/Supplement 0
|
||||
>> def
|
||||
/CMapName /A-B-C def
|
||||
/CMapType 2 def
|
||||
1 begincodespacerange
|
||||
<00> <FF>
|
||||
endcodespacerange
|
||||
1 beginbfchar
|
||||
<00> <DBC0DDAC>
|
||||
endbfchar
|
||||
endcmap
|
||||
CMapName currentdict /CMap defineresource pop
|
||||
end
|
||||
end
|
||||
endstream
|
||||
endobj
|
||||
|
||||
5 0 obj
|
||||
336
|
||||
endobj
|
||||
|
||||
6 0 obj
|
||||
<< /Subtype /Type3
|
||||
/CharProcs << /C0 1 0 R >>
|
||||
/Encoding << /Type /Encoding
|
||||
/Differences [ 0 /C0 ]
|
||||
>>
|
||||
/Widths 3 0 R
|
||||
/FontBBox [ 0.000000 0.000000 0.000000 0.000000 ]
|
||||
/FontMatrix [ 1.000000 0.000000 0.000000 1.000000 0.000000 0.000000 ]
|
||||
/Type /Font
|
||||
/ToUnicode 4 0 R
|
||||
/FirstChar 0
|
||||
/LastChar 0
|
||||
/Resources << >>
|
||||
>>
|
||||
endobj
|
||||
|
||||
7 0 obj
|
||||
<< /Font << /F1 6 0 R >> >>
|
||||
endobj
|
||||
|
||||
8 0 obj
|
||||
<< /Length 9 0 R >>
|
||||
stream
|
||||
/DeviceRGB CS
|
||||
/DeviceRGB cs
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 -1.653809 1.365723 cm
|
||||
1.000000 1.000000 1.000000 scn
|
||||
0.342773 0.692383 m
|
||||
h
|
||||
9.000000 11.612793 m
|
||||
9.468750 11.612793 9.856934 12.000977 9.856934 12.469727 c
|
||||
9.856934 12.938477 9.468750 13.326660 9.000000 13.326660 c
|
||||
8.531250 13.326660 8.143066 12.938477 8.143066 12.469727 c
|
||||
8.143066 12.000977 8.531250 11.612793 9.000000 11.612793 c
|
||||
h
|
||||
4.407715 9.715820 m
|
||||
4.883789 9.715820 5.264648 10.104004 5.264648 10.572754 c
|
||||
5.264648 11.041504 4.883789 11.429688 4.407715 11.429688 c
|
||||
3.938965 11.429688 3.550781 11.041504 3.550781 10.572754 c
|
||||
3.550781 10.104004 3.938965 9.715820 4.407715 9.715820 c
|
||||
h
|
||||
13.592285 9.715820 m
|
||||
14.061035 9.715820 14.449219 10.104004 14.449219 10.572754 c
|
||||
14.449219 11.041504 14.061035 11.429688 13.592285 11.429688 c
|
||||
13.123535 11.429688 12.735352 11.041504 12.735352 10.572754 c
|
||||
12.735352 10.104004 13.123535 9.715820 13.592285 9.715820 c
|
||||
h
|
||||
9.000000 2.252441 m
|
||||
11.036133 2.252441 12.735352 3.944336 12.735352 5.980469 c
|
||||
12.735352 8.023926 11.036133 9.715820 9.000000 9.715820 c
|
||||
6.963867 9.715820 5.271973 8.023926 5.271973 5.980469 c
|
||||
5.271973 3.944336 6.963867 2.252441 9.000000 2.252441 c
|
||||
h
|
||||
2.510742 5.123535 m
|
||||
2.979492 5.123535 3.367676 5.511719 3.367676 5.980469 c
|
||||
3.367676 6.456543 2.979492 6.837402 2.510742 6.837402 c
|
||||
2.041992 6.837402 1.653809 6.456543 1.653809 5.980469 c
|
||||
1.653809 5.511719 2.041992 5.123535 2.510742 5.123535 c
|
||||
h
|
||||
15.489258 5.123535 m
|
||||
15.958008 5.123535 16.346191 5.511719 16.346191 5.980469 c
|
||||
16.346191 6.456543 15.958008 6.837402 15.489258 6.837402 c
|
||||
15.020508 6.837402 14.632324 6.456543 14.632324 5.980469 c
|
||||
14.632324 5.511719 15.020508 5.123535 15.489258 5.123535 c
|
||||
h
|
||||
13.592285 0.531250 m
|
||||
14.061035 0.531250 14.449219 0.919434 14.449219 1.388184 c
|
||||
14.449219 1.864258 14.061035 2.245117 13.592285 2.245117 c
|
||||
13.123535 2.245117 12.735352 1.864258 12.735352 1.388184 c
|
||||
12.735352 0.919434 13.123535 0.531250 13.592285 0.531250 c
|
||||
h
|
||||
4.407715 0.531250 m
|
||||
4.883789 0.531250 5.264648 0.919434 5.264648 1.388184 c
|
||||
5.264648 1.864258 4.883789 2.245117 4.407715 2.245117 c
|
||||
3.938965 2.245117 3.550781 1.864258 3.550781 1.388184 c
|
||||
3.550781 0.919434 3.938965 0.531250 4.407715 0.531250 c
|
||||
h
|
||||
9.000000 -1.365723 m
|
||||
9.468750 -1.365723 9.856934 -0.977539 9.856934 -0.508789 c
|
||||
9.856934 -0.032715 9.468750 0.348145 9.000000 0.348145 c
|
||||
8.531250 0.348145 8.143066 -0.032715 8.143066 -0.508789 c
|
||||
8.143066 -0.977539 8.531250 -1.365723 9.000000 -1.365723 c
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 -1.653809 1.365723 cm
|
||||
BT
|
||||
15.000000 0.000000 0.000000 15.000000 0.342773 0.692383 Tm
|
||||
/F1 1.000000 Tf
|
||||
[ (\000) ] TJ
|
||||
ET
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
9 0 obj
|
||||
2605
|
||||
endobj
|
||||
|
||||
10 0 obj
|
||||
<< /Annots []
|
||||
/Type /Page
|
||||
/MediaBox [ 0.000000 0.000000 14.692383 14.692383 ]
|
||||
/Resources 7 0 R
|
||||
/Contents 8 0 R
|
||||
/Parent 11 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
11 0 obj
|
||||
<< /Kids [ 10 0 R ]
|
||||
/Count 1
|
||||
/Type /Pages
|
||||
>>
|
||||
endobj
|
||||
|
||||
12 0 obj
|
||||
<< /Pages 11 0 R
|
||||
/Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 13
|
||||
0000000000 65535 f
|
||||
0000000010 00000 n
|
||||
0000000117 00000 n
|
||||
0000000138 00000 n
|
||||
0000000169 00000 n
|
||||
0000000561 00000 n
|
||||
0000000583 00000 n
|
||||
0000000995 00000 n
|
||||
0000001041 00000 n
|
||||
0000003702 00000 n
|
||||
0000003725 00000 n
|
||||
0000003900 00000 n
|
||||
0000003976 00000 n
|
||||
trailer
|
||||
<< /ID [ (some) (id) ]
|
||||
/Root 12 0 R
|
||||
/Size 13
|
||||
>>
|
||||
startxref
|
||||
4037
|
||||
%%EOF
|
@ -130,7 +130,7 @@ final class ChatBotStartInputPanelNode: ChatInputPanelNode {
|
||||
tooltipController.location = .point(location, .bottom)
|
||||
}
|
||||
} else {
|
||||
let controller = TooltipScreen(account: context.account, text: self.strings.Bot_TapToUse, icon: .downArrows, location: .point(location, .bottom), displayDuration: .infinite, shouldDismissOnTouch: { _ in
|
||||
let controller = TooltipScreen(account: context.account, sharedContext: context.sharedContext, text: self.strings.Bot_TapToUse, icon: .downArrows, location: .point(location, .bottom), displayDuration: .infinite, shouldDismissOnTouch: { _ in
|
||||
return .ignore
|
||||
})
|
||||
controller.alwaysVisible = true
|
||||
|
@ -676,14 +676,17 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
return false
|
||||
}
|
||||
|
||||
if strongSelf.presentVoiceMessageDiscardAlert(action: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
Queue.mainQueue().after(0.1, {
|
||||
let _ = strongSelf.controllerInteraction?.openMessage(message, mode)
|
||||
})
|
||||
let displayVoiceMessageDiscardAlert: () -> Bool = {
|
||||
if strongSelf.presentVoiceMessageDiscardAlert(action: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
Queue.mainQueue().after(0.1, {
|
||||
let _ = strongSelf.controllerInteraction?.openMessage(message, mode)
|
||||
})
|
||||
}
|
||||
}, performAction: false) {
|
||||
return false
|
||||
}
|
||||
}, performAction: false) {
|
||||
return false
|
||||
return true
|
||||
}
|
||||
|
||||
strongSelf.commitPurposefulAction()
|
||||
@ -696,6 +699,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
|
||||
for media in message.media {
|
||||
if media is TelegramMediaMap {
|
||||
if !displayVoiceMessageDiscardAlert() {
|
||||
return false
|
||||
}
|
||||
isLocation = true
|
||||
}
|
||||
if let file = media as? TelegramMediaFile, file.isInstantVideo {
|
||||
@ -707,12 +713,19 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
if let invoice = media as? TelegramMediaInvoice, let extendedMedia = invoice.extendedMedia {
|
||||
switch extendedMedia {
|
||||
case .preview:
|
||||
strongSelf.controllerInteraction?.openCheckoutOrReceipt(message.id)
|
||||
return true
|
||||
if displayVoiceMessageDiscardAlert() {
|
||||
strongSelf.controllerInteraction?.openCheckoutOrReceipt(message.id)
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case .full:
|
||||
break
|
||||
}
|
||||
} else if let action = media as? TelegramMediaAction {
|
||||
if !displayVoiceMessageDiscardAlert() {
|
||||
return false
|
||||
}
|
||||
switch action.action {
|
||||
case .pinnedMessageUpdated:
|
||||
for attribute in message.attributes {
|
||||
@ -845,7 +858,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
strongSelf.chatDisplayNode.dismissInput()
|
||||
let wallpaperPreviewController = WallpaperGalleryController(context: strongSelf.context, source: .wallpaper(wallpaper, nil, [], nil, nil, nil), mode: .peer(EnginePeer(peer), true))
|
||||
wallpaperPreviewController.apply = { wallpaper, options, _ in
|
||||
wallpaperPreviewController.apply = { wallpaper, options, _, _ in
|
||||
let _ = (strongSelf.context.engine.themes.setExistingChatWallpaper(messageId: message.id, settings: nil)
|
||||
|> deliverOnMainQueue).start(completed: { [weak wallpaperPreviewController] in
|
||||
wallpaperPreviewController?.dismiss()
|
||||
@ -4264,12 +4277,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
if value {
|
||||
openWebView()
|
||||
} else {
|
||||
strongSelf.present(textAlertController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, title: strongSelf.presentationData.strings.WebApp_OpenWebViewAlertTitle, text: strongSelf.presentationData.strings.WebApp_OpenWebViewAlertText(botName).string, actions: [TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: { }), TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {
|
||||
if let strongSelf = self {
|
||||
let _ = ApplicationSpecificNotice.setBotGameNotice(accountManager: strongSelf.context.sharedContext.accountManager, peerId: peer.id).start()
|
||||
openWebView()
|
||||
}
|
||||
})], parseMarkdown: true), in: .window(.root), with: nil)
|
||||
let controller = webAppLaunchConfirmationController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peer: EnginePeer(peer), commit: {
|
||||
let _ = ApplicationSpecificNotice.setBotGameNotice(accountManager: strongSelf.context.sharedContext.accountManager, peerId: peer.id).start()
|
||||
openWebView()
|
||||
}, showMore: nil)
|
||||
strongSelf.present(controller, in: .window(.root))
|
||||
}
|
||||
})
|
||||
}, activateAdAction: { [weak self] messageId in
|
||||
@ -5840,6 +5852,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
if let strongSelf = self {
|
||||
let (themeEmoticonPreview, darkAppearancePreview) = themeEmoticonAndDarkAppearance
|
||||
|
||||
var chatWallpaper = chatWallpaper
|
||||
|
||||
let previousTheme = strongSelf.presentationData.theme
|
||||
let previousStrings = strongSelf.presentationData.strings
|
||||
let previousChatWallpaper = strongSelf.presentationData.chatWallpaper
|
||||
@ -5847,7 +5861,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
var themeEmoticon = themeEmoticon
|
||||
if let themeEmoticonPreview = themeEmoticonPreview {
|
||||
if !themeEmoticonPreview.isEmpty {
|
||||
themeEmoticon = themeEmoticonPreview
|
||||
if themeEmoticon != themeEmoticonPreview {
|
||||
chatWallpaper = nil
|
||||
themeEmoticon = themeEmoticonPreview
|
||||
}
|
||||
} else {
|
||||
themeEmoticon = nil
|
||||
}
|
||||
@ -5858,7 +5875,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
|
||||
var presentationData = presentationData
|
||||
var useDarkAppearance = presentationData.theme.overallDarkAppearance
|
||||
|
||||
|
||||
if let themeEmoticon = themeEmoticon, let theme = chatThemes.first(where: { $0.emoticon?.strippedEmoji == themeEmoticon.strippedEmoji }) {
|
||||
if let darkAppearancePreview = darkAppearancePreview {
|
||||
useDarkAppearance = darkAppearancePreview
|
||||
@ -5897,7 +5914,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
lightWallpaper = theme.chat.defaultWallpaper
|
||||
}
|
||||
|
||||
lightTheme = makePresentationTheme(mediaBox: accountManager.mediaBox, themeReference: themeSettings.theme, accentColor: currentColors?.color, bubbleColors: currentColors?.customBubbleColors ?? [], wallpaper: currentColors?.wallpaper, baseColor: currentColors?.baseColor, serviceBackgroundColor: defaultServiceBackgroundColor) ?? defaultPresentationTheme
|
||||
var preferredBaseTheme: TelegramBaseTheme?
|
||||
if let baseTheme = themeSettings.themePreferredBaseTheme[themeSettings.theme.index], [.classic, .day].contains(baseTheme) {
|
||||
preferredBaseTheme = baseTheme
|
||||
}
|
||||
|
||||
lightTheme = makePresentationTheme(mediaBox: accountManager.mediaBox, themeReference: themeSettings.theme, baseTheme: preferredBaseTheme, accentColor: currentColors?.color, bubbleColors: currentColors?.customBubbleColors ?? [], wallpaper: currentColors?.wallpaper, baseColor: currentColors?.baseColor, serviceBackgroundColor: defaultServiceBackgroundColor) ?? defaultPresentationTheme
|
||||
} else {
|
||||
lightTheme = presentationData.theme
|
||||
lightWallpaper = presentationData.chatWallpaper
|
||||
@ -5906,7 +5928,14 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
let effectiveColors = themeSettings.themeSpecificAccentColors[automaticTheme.index]
|
||||
let themeSpecificWallpaper = (themeSettings.themeSpecificChatWallpapers[coloredThemeIndex(reference: automaticTheme, accentColor: effectiveColors)] ?? themeSettings.themeSpecificChatWallpapers[automaticTheme.index])
|
||||
|
||||
darkTheme = makePresentationTheme(mediaBox: accountManager.mediaBox, themeReference: automaticTheme, accentColor: effectiveColors?.color, bubbleColors: effectiveColors?.customBubbleColors ?? [], wallpaper: effectiveColors?.wallpaper, baseColor: effectiveColors?.baseColor, serviceBackgroundColor: defaultServiceBackgroundColor) ?? defaultPresentationTheme
|
||||
var preferredBaseTheme: TelegramBaseTheme?
|
||||
if let baseTheme = themeSettings.themePreferredBaseTheme[automaticTheme.index], [.night, .tinted].contains(baseTheme) {
|
||||
preferredBaseTheme = baseTheme
|
||||
} else {
|
||||
preferredBaseTheme = .night
|
||||
}
|
||||
|
||||
darkTheme = makePresentationTheme(mediaBox: accountManager.mediaBox, themeReference: automaticTheme, baseTheme: preferredBaseTheme, accentColor: effectiveColors?.color, bubbleColors: effectiveColors?.customBubbleColors ?? [], wallpaper: effectiveColors?.wallpaper, baseColor: effectiveColors?.baseColor, serviceBackgroundColor: defaultServiceBackgroundColor) ?? defaultPresentationTheme
|
||||
|
||||
if let themeSpecificWallpaper = themeSpecificWallpaper {
|
||||
darkWallpaper = themeSpecificWallpaper
|
||||
@ -5945,7 +5974,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
presentationData = presentationData.withUpdated(chatWallpaper: chatWallpaper)
|
||||
}
|
||||
|
||||
|
||||
let isFirstTime = !strongSelf.didSetPresentationData
|
||||
strongSelf.presentationData = presentationData
|
||||
strongSelf.didSetPresentationData = true
|
||||
@ -10942,6 +10970,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
return false
|
||||
}
|
||||
|
||||
if strongSelf.effectiveNavigationController?.topViewController !== strongSelf {
|
||||
return false
|
||||
}
|
||||
|
||||
if strongSelf.presentationInterfaceState.inputTextPanelState.mediaRecordingState != nil {
|
||||
return false
|
||||
}
|
||||
@ -12765,7 +12797,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
self.presentAttachmentMenu(subject: .bot(id: botId, payload: payload, justInstalled: justInstalled))
|
||||
}
|
||||
|
||||
public func presentBotApp(botApp: BotApp, payload: String?) {
|
||||
public func presentBotApp(botApp: BotApp, botPeer: EnginePeer, payload: String?) {
|
||||
guard let peerId = self.chatLocation.peerId else {
|
||||
return
|
||||
}
|
||||
@ -12813,6 +12845,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
}
|
||||
|
||||
let botAddress = botPeer.addressName ?? ""
|
||||
|
||||
self.messageActionCallbackDisposable.set(((self.context.engine.messages.requestAppWebView(peerId: peerId, appReference: .id(id: botApp.id, accessHash: botApp.accessHash), payload: payload, themeParams: generateWebAppThemeParams(self.presentationData.theme), allowWrite: false)
|
||||
|> afterDisposed {
|
||||
updateProgress()
|
||||
@ -12824,6 +12858,22 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
let params = WebAppParameters(peerId: peerId, botId: peerId, botName: botApp.title, url: url, queryId: 0, payload: payload, buttonText: "", keepAliveSignal: nil, fromMenu: false, fromAttachMenu: false, isInline: false, isSimple: false)
|
||||
let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, threadId: strongSelf.chatLocation.threadId, openUrl: { [weak self] url in
|
||||
self?.openUrl(url, concealed: true, forceExternal: true)
|
||||
}, requestSwitchInline: { [weak self] query, chatTypes, completion in
|
||||
if let strongSelf = self {
|
||||
if let chatTypes {
|
||||
let controller = strongSelf.context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: strongSelf.context, filter: [.excludeRecent, .doNotSearchMessages], requestPeerType: chatTypes, hasContactSelector: false, hasCreation: false))
|
||||
controller.peerSelected = { [weak self, weak controller] peer, _ in
|
||||
if let strongSelf = self {
|
||||
completion()
|
||||
controller?.dismiss()
|
||||
strongSelf.controllerInteraction?.activateSwitchInline(peer.id, "@\(botAddress) \(query)")
|
||||
}
|
||||
}
|
||||
strongSelf.push(controller)
|
||||
} else {
|
||||
strongSelf.controllerInteraction?.activateSwitchInline(peerId, "@\(botAddress) \(query)")
|
||||
}
|
||||
}
|
||||
}, completion: { [weak self] in
|
||||
self?.chatDisplayNode.historyNode.scrollToEndOfHistory()
|
||||
}, getNavigationController: { [weak self] in
|
||||
@ -14315,7 +14365,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
return
|
||||
}
|
||||
|
||||
let tooltipScreen = TooltipScreen(account: self.context.account, text: solution.text, textEntities: solution.entities, icon: .info, location: .top, shouldDismissOnTouch: { point in
|
||||
let tooltipScreen = TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: solution.text, textEntities: solution.entities, icon: .info, location: .top, shouldDismissOnTouch: { point in
|
||||
return .ignore
|
||||
}, openActiveTextItem: { [weak self] item, action in
|
||||
guard let strongSelf = self else {
|
||||
@ -14408,7 +14458,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
return
|
||||
}
|
||||
|
||||
let tooltipScreen = TooltipScreen(account: self.context.account, text: psaText, textEntities: psaEntities, icon: .info, location: .top, displayDuration: .custom(10.0), shouldDismissOnTouch: { point in
|
||||
let tooltipScreen = TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: psaText, textEntities: psaEntities, icon: .info, location: .top, displayDuration: .custom(10.0), shouldDismissOnTouch: { point in
|
||||
return .ignore
|
||||
}, openActiveTextItem: { [weak self] item, action in
|
||||
guard let strongSelf = self else {
|
||||
@ -14522,7 +14572,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
return
|
||||
}
|
||||
|
||||
let tooltipScreen = TooltipScreen(account: self.context.account, text: psaText, textEntities: psaEntities, icon: .info, location: .top, displayDuration: .custom(10.0), shouldDismissOnTouch: { point in
|
||||
let tooltipScreen = TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: psaText, textEntities: psaEntities, icon: .info, location: .top, displayDuration: .custom(10.0), shouldDismissOnTouch: { point in
|
||||
return .ignore
|
||||
}, openActiveTextItem: { [weak self] item, action in
|
||||
guard let strongSelf = self else {
|
||||
@ -17173,7 +17223,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}))
|
||||
}
|
||||
|
||||
private func openResolved(result: ResolvedUrl, sourceMessageId: MessageId?, forceExternal: Bool = false) {
|
||||
private func openResolved(result: ResolvedUrl, sourceMessageId: MessageId?, forceExternal: Bool = false, concealed: Bool = false) {
|
||||
guard let peerId = self.chatLocation.peerId else {
|
||||
return
|
||||
}
|
||||
@ -17230,7 +17280,28 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peerId), attachBotStart: attachBotStart))
|
||||
}
|
||||
case let .withBotApp(botAppStart):
|
||||
strongSelf.presentBotApp(botApp: botAppStart.botApp, payload: botAppStart.payload)
|
||||
let _ = (strongSelf.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId.id))
|
||||
|> deliverOnMainQueue).start(next: { [weak self] peer in
|
||||
if let strongSelf = self, let peer {
|
||||
let openBotApp = { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.presentBotApp(botApp: botAppStart.botApp, botPeer: peerId, payload: botAppStart.payload)
|
||||
}
|
||||
}
|
||||
if concealed {
|
||||
let controller = webAppLaunchConfirmationController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peer: peer, commit: {
|
||||
openBotApp()
|
||||
}, showMore: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.openResolved(result: .peer(peer._asPeer(), .info), sourceMessageId: nil)
|
||||
}
|
||||
})
|
||||
strongSelf.present(controller, in: .window(.root))
|
||||
} else {
|
||||
openBotApp()
|
||||
}
|
||||
}
|
||||
})
|
||||
default:
|
||||
break
|
||||
}
|
||||
@ -17256,7 +17327,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
openUserGeneratedUrl(context: self.context, peerId: self.peerView?.peerId, url: url, concealed: concealed, skipUrlAuth: skipUrlAuth, skipConcealedAlert: skipConcealedAlert, present: { [weak self] c in
|
||||
self?.present(c, in: .window(.root))
|
||||
}, openResolved: { [weak self] resolved in
|
||||
self?.openResolved(result: resolved, sourceMessageId: message?.id, forceExternal: forceExternal)
|
||||
self?.openResolved(result: resolved, sourceMessageId: message?.id, forceExternal: forceExternal, concealed: concealed)
|
||||
})
|
||||
}, performAction: true)
|
||||
}
|
||||
@ -18485,22 +18556,25 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
let selectedEmoticon: String? = themeEmoticon
|
||||
var canResetWallpaper = false
|
||||
if let cachedUserData = strongSelf.peerView?.cachedData as? CachedUserData {
|
||||
canResetWallpaper = cachedUserData.wallpaper != nil
|
||||
}
|
||||
|
||||
let controller = ChatThemeScreen(
|
||||
context: context,
|
||||
updatedPresentationData: strongSelf.updatedPresentationData,
|
||||
animatedEmojiStickers: animatedEmojiStickers,
|
||||
initiallySelectedEmoticon: selectedEmoticon,
|
||||
initiallySelectedEmoticon: themeEmoticon,
|
||||
peerName: strongSelf.presentationInterfaceState.renderedPeer?.chatMainPeer.flatMap(EnginePeer.init)?.compactDisplayTitle ?? "",
|
||||
canResetWallpaper: canResetWallpaper,
|
||||
previewTheme: { [weak self] emoticon, dark in
|
||||
if let strongSelf = self {
|
||||
strongSelf.presentCrossfadeSnapshot()
|
||||
strongSelf.themeEmoticonAndDarkAppearancePreviewPromise.set(.single((emoticon, dark)))
|
||||
}
|
||||
},
|
||||
changeWallpaper: {
|
||||
changeWallpaper: { [weak self] in
|
||||
guard let strongSelf = self, let peerId else {
|
||||
return
|
||||
}
|
||||
@ -18519,60 +18593,64 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
navigationController.setViewControllers(controllers, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
var canDelete = false
|
||||
if let cachedUserData = strongSelf.peerView?.cachedData as? CachedUserData {
|
||||
canDelete = cachedUserData.wallpaper != nil
|
||||
}
|
||||
let controller = wallpaperMediaPickerController(
|
||||
context: strongSelf.context,
|
||||
updatedPresentationData: strongSelf.updatedPresentationData,
|
||||
peer: EnginePeer(peer),
|
||||
canDelete: canDelete,
|
||||
completion: { asset in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let controller = WallpaperGalleryController(context: strongSelf.context, source: .asset(asset), mode: .peer(EnginePeer(peer), false))
|
||||
controller.navigationPresentation = .modal
|
||||
controller.apply = { [weak self] wallpaper, options, cropRect in
|
||||
if let strongSelf = self {
|
||||
uploadCustomPeerWallpaper(context: strongSelf.context, wallpaper: wallpaper, mode: options, cropRect: cropRect, brightnessMultiplier: nil, peerId: peerId, completion: {
|
||||
dismissControllers()
|
||||
})
|
||||
}
|
||||
}
|
||||
strongSelf.push(controller)
|
||||
var openWallpaperPickerImpl: (() -> Void)?
|
||||
let openWallpaperPicker = { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
)
|
||||
controller.navigationPresentation = .flatModal
|
||||
strongSelf.push(controller)
|
||||
let controller = wallpaperMediaPickerController(
|
||||
context: strongSelf.context,
|
||||
updatedPresentationData: strongSelf.updatedPresentationData,
|
||||
peer: EnginePeer(peer),
|
||||
completion: { [weak self] asset in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let controller = WallpaperGalleryController(context: strongSelf.context, source: .asset(asset), mode: .peer(EnginePeer(peer), false))
|
||||
controller.navigationPresentation = .modal
|
||||
controller.apply = { [weak self] wallpaper, options, cropRect, brightness in
|
||||
if let strongSelf = self {
|
||||
uploadCustomPeerWallpaper(context: strongSelf.context, wallpaper: wallpaper, mode: options, cropRect: cropRect, brightness: brightness, peerId: peerId, completion: {
|
||||
dismissControllers()
|
||||
})
|
||||
}
|
||||
}
|
||||
strongSelf.push(controller)
|
||||
},
|
||||
openColors: { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let controller = standaloneColorPickerController(context: strongSelf.context, peer: EnginePeer(peer), push: { [weak self] controller in
|
||||
if let strongSelf = self {
|
||||
strongSelf.push(controller)
|
||||
}
|
||||
}, openGallery: {
|
||||
openWallpaperPickerImpl?()
|
||||
})
|
||||
controller.navigationPresentation = .flatModal
|
||||
strongSelf.push(controller)
|
||||
}
|
||||
)
|
||||
controller.navigationPresentation = .flatModal
|
||||
strongSelf.push(controller)
|
||||
}
|
||||
openWallpaperPickerImpl = openWallpaperPicker
|
||||
openWallpaperPicker()
|
||||
},
|
||||
changeColor: {
|
||||
guard let strongSelf = self else {
|
||||
resetWallpaper: { [weak self] in
|
||||
guard let strongSelf = self, let peerId else {
|
||||
return
|
||||
}
|
||||
if let themeController = strongSelf.themeScreen {
|
||||
strongSelf.themeScreen = nil
|
||||
themeController.dimTapped()
|
||||
}
|
||||
|
||||
var canDelete = false
|
||||
if let cachedUserData = strongSelf.peerView?.cachedData as? CachedUserData {
|
||||
canDelete = cachedUserData.wallpaper != nil
|
||||
}
|
||||
let controller = standaloneColorPickerController(context: strongSelf.context, peer: EnginePeer(peer), canDelete: canDelete, push: { [weak self] controller in
|
||||
if let strongSelf = self {
|
||||
strongSelf.push(controller)
|
||||
}
|
||||
})
|
||||
controller.navigationPresentation = .flatModal
|
||||
strongSelf.push(controller)
|
||||
let _ = strongSelf.context.engine.themes.setChatWallpaper(peerId: peerId, wallpaper: nil).start()
|
||||
},
|
||||
completion: { [weak self] emoticon in
|
||||
guard let strongSelf = self, let peerId else {
|
||||
return
|
||||
}
|
||||
if canResetWallpaper {
|
||||
let _ = context.engine.themes.setChatWallpaper(peerId: peerId, wallpaper: nil).start()
|
||||
}
|
||||
strongSelf.themeEmoticonAndDarkAppearancePreviewPromise.set(.single((emoticon ?? "", nil)))
|
||||
let _ = context.engine.themes.setChatTheme(peerId: peerId, emoticon: emoticon).start(completed: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
@ -18581,6 +18659,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
})
|
||||
}
|
||||
)
|
||||
controller.navigationPresentation = .flatModal
|
||||
controller.passthroughHitTestImpl = { [weak self] _ in
|
||||
if let strongSelf = self {
|
||||
return strongSelf.chatDisplayNode.historyNode.view
|
||||
@ -18596,7 +18675,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
strongSelf.chatDisplayNode.historyNode.tapped = { [weak controller] in
|
||||
controller?.dimTapped()
|
||||
}
|
||||
strongSelf.present(controller, in: .window(.root))
|
||||
strongSelf.push(controller)
|
||||
strongSelf.themeScreen = controller
|
||||
})
|
||||
}
|
||||
@ -18630,7 +18709,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
}) {
|
||||
let isEmoji = actions[0].0.id.namespace == Namespaces.ItemCollection.CloudEmojiPacks
|
||||
|
||||
strongSelf.presentInGlobalOverlay(UndoOverlayController(presentationData: presentationData, content: .stickersModified(title: isEmoji ? presentationData.strings.EmojiPackActionInfo_RemovedTitle : presentationData.strings.StickerPackActionInfo_RemovedTitle, text: isEmoji ? presentationData.strings.EmojiPackActionInfo_MultipleRemovedText(Int32(actions.count)) : presentationData.strings.StickerPackActionInfo_MultipleRemovedText(Int32(actions.count)), undo: true, info: actions[0].0, topItem: actions[0].1.first, context: context), elevatedLayout: true, animateInAsReplacement: false, action: { action in
|
||||
if case .undo = action {
|
||||
var itemsAndIndices: [(StickerPackCollectionInfo, [StickerPackItem], Int)] = actions.compactMap { action -> (StickerPackCollectionInfo, [StickerPackItem], Int)? in
|
||||
@ -18650,7 +18728,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
} else if let (info, items, action) = actions.first {
|
||||
let isEmoji = info.id.namespace == Namespaces.ItemCollection.CloudEmojiPacks
|
||||
|
||||
switch action {
|
||||
case .add:
|
||||
strongSelf.presentInGlobalOverlay(UndoOverlayController(presentationData: presentationData, content: .stickersModified(title: isEmoji ? presentationData.strings.EmojiPackActionInfo_AddedTitle : presentationData.strings.StickerPackActionInfo_AddedTitle, text: isEmoji ? presentationData.strings.EmojiPackActionInfo_AddedText(info.title).string : presentationData.strings.StickerPackActionInfo_AddedText(info.title).string, undo: false, info: info, topItem: items.first, context: context), elevatedLayout: true, animateInAsReplacement: false, action: { _ in
|
||||
|
@ -1472,43 +1472,47 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
} else {
|
||||
transition.animatePosition(layer: self.startButton.layer, from: CGPoint(x: 0.0, y: 80.0), to: CGPoint(), additive: true)
|
||||
}
|
||||
}
|
||||
|
||||
if let context = self.context {
|
||||
let absoluteFrame = self.startButton.view.convert(self.startButton.bounds, to: nil)
|
||||
let location = CGRect(origin: CGPoint(x: absoluteFrame.midX, y: absoluteFrame.minY - 1.0), size: CGSize())
|
||||
|
||||
if let tooltipController = self.tooltipController {
|
||||
if self.view.window != nil {
|
||||
tooltipController.location = .point(location, .bottom)
|
||||
}
|
||||
} else {
|
||||
let controller = TooltipScreen(account: context.account, text: interfaceState.strings.Bot_TapToUse, icon: .downArrows, location: .point(location, .bottom), displayDuration: .infinite, shouldDismissOnTouch: { _ in
|
||||
return .ignore
|
||||
})
|
||||
controller.alwaysVisible = true
|
||||
self.tooltipController = controller
|
||||
if let context = self.context {
|
||||
let absoluteFrame = self.startButton.view.convert(self.startButton.bounds, to: nil)
|
||||
let location = CGRect(origin: CGPoint(x: absoluteFrame.midX, y: absoluteFrame.minY - 1.0), size: CGSize())
|
||||
|
||||
let delay: Double
|
||||
if case .regular = metrics.widthClass {
|
||||
delay = 0.1
|
||||
if let tooltipController = self.tooltipController {
|
||||
if self.view.window != nil {
|
||||
tooltipController.location = .point(location, .bottom)
|
||||
}
|
||||
} else {
|
||||
delay = 0.35
|
||||
let controller = TooltipScreen(account: context.account, sharedContext: context.sharedContext, text: interfaceState.strings.Bot_TapToUse, icon: .downArrows, location: .point(location, .bottom), displayDuration: .infinite, shouldDismissOnTouch: { _ in
|
||||
return .ignore
|
||||
})
|
||||
controller.alwaysVisible = true
|
||||
self.tooltipController = controller
|
||||
|
||||
let delay: Double
|
||||
if case .regular = metrics.widthClass {
|
||||
delay = 0.1
|
||||
} else {
|
||||
delay = 0.35
|
||||
}
|
||||
Queue.mainQueue().after(delay, {
|
||||
let absoluteFrame = self.startButton.view.convert(self.startButton.bounds, to: nil)
|
||||
let location = CGRect(origin: CGPoint(x: absoluteFrame.midX, y: absoluteFrame.minY - 1.0), size: CGSize())
|
||||
controller.location = .point(location, .bottom)
|
||||
self.interfaceInteraction?.presentControllerInCurrent(controller, nil)
|
||||
})
|
||||
}
|
||||
Queue.mainQueue().after(delay, {
|
||||
let absoluteFrame = self.startButton.view.convert(self.startButton.bounds, to: nil)
|
||||
let location = CGRect(origin: CGPoint(x: absoluteFrame.midX, y: absoluteFrame.minY - 1.0), size: CGSize())
|
||||
controller.location = .point(location, .bottom)
|
||||
self.interfaceInteraction?.presentControllerInCurrent(controller, nil)
|
||||
})
|
||||
}
|
||||
} else {
|
||||
if hasMenuButton && !self.animatingTransition {
|
||||
self.menuButton.isHidden = true
|
||||
}
|
||||
}
|
||||
} else if !self.startButton.isHidden {
|
||||
if hasMenuButton {
|
||||
self.animateBotButtonOutToMenu(transition: transition)
|
||||
} else {
|
||||
transition.animatePosition(node: self.startButton, to: CGPoint(x: 0.0, y: 80.0), additive: true, completion: { _ in
|
||||
transition.animatePosition(node: self.startButton, to: CGPoint(x: 0.0, y: 80.0), removeOnCompletion: false, additive: true, completion: { _ in
|
||||
self.startButton.isHidden = true
|
||||
self.startButton.layer.removeAllAnimations()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -554,9 +554,10 @@ final class ChatThemeScreen: ViewController {
|
||||
private let animatedEmojiStickers: [String: [StickerPackItem]]
|
||||
private let initiallySelectedEmoticon: String?
|
||||
private let peerName: String
|
||||
let canResetWallpaper: Bool
|
||||
private let previewTheme: (String?, Bool?) -> Void
|
||||
fileprivate let changeWallpaper: () -> Void
|
||||
fileprivate let changeColor: () -> Void
|
||||
fileprivate let resetWallpaper: () -> Void
|
||||
private let completion: (String?) -> Void
|
||||
|
||||
private var presentationData: PresentationData
|
||||
@ -578,9 +579,10 @@ final class ChatThemeScreen: ViewController {
|
||||
animatedEmojiStickers: [String: [StickerPackItem]],
|
||||
initiallySelectedEmoticon: String?,
|
||||
peerName: String,
|
||||
canResetWallpaper: Bool,
|
||||
previewTheme: @escaping (String?, Bool?) -> Void,
|
||||
changeWallpaper: @escaping () -> Void,
|
||||
changeColor: @escaping () -> Void,
|
||||
resetWallpaper: @escaping () -> Void,
|
||||
completion: @escaping (String?) -> Void
|
||||
) {
|
||||
self.context = context
|
||||
@ -588,15 +590,18 @@ final class ChatThemeScreen: ViewController {
|
||||
self.animatedEmojiStickers = animatedEmojiStickers
|
||||
self.initiallySelectedEmoticon = initiallySelectedEmoticon
|
||||
self.peerName = peerName
|
||||
self.canResetWallpaper = canResetWallpaper
|
||||
self.previewTheme = previewTheme
|
||||
self.changeWallpaper = changeWallpaper
|
||||
self.changeColor = changeColor
|
||||
self.resetWallpaper = resetWallpaper
|
||||
self.completion = completion
|
||||
|
||||
super.init(navigationBarPresentationData: nil)
|
||||
|
||||
self.statusBar.statusBarStyle = .Ignore
|
||||
|
||||
self.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait)
|
||||
|
||||
self.blocksBackgroundWhenInOverlay = true
|
||||
|
||||
self.presentationDataDisposable = (updatedPresentationData.signal
|
||||
@ -634,20 +639,20 @@ final class ChatThemeScreen: ViewController {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.dismiss()
|
||||
strongSelf.dismiss(animated: true)
|
||||
if strongSelf.initiallySelectedEmoticon == nil && emoticon == nil {
|
||||
} else {
|
||||
strongSelf.completion(emoticon)
|
||||
}
|
||||
}
|
||||
self.controllerNode.dismiss = { [weak self] in
|
||||
self?.presentingViewController?.dismiss(animated: false, completion: nil)
|
||||
self?.dismiss(animated: false)
|
||||
}
|
||||
self.controllerNode.cancel = { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.dismiss()
|
||||
strongSelf.dismiss(animated: true)
|
||||
strongSelf.previewTheme(nil, nil)
|
||||
}
|
||||
}
|
||||
@ -667,15 +672,22 @@ final class ChatThemeScreen: ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
override public func dismiss(completion: (() -> Void)? = nil) {
|
||||
override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
|
||||
self.forEachController({ controller in
|
||||
if let controller = controller as? TooltipScreen {
|
||||
controller.dismiss()
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
self.controllerNode.animateOut(completion: completion)
|
||||
|
||||
if flag {
|
||||
self.controllerNode.animateOut(completion: {
|
||||
super.dismiss(animated: flag, completion: completion)
|
||||
completion?()
|
||||
})
|
||||
} else {
|
||||
super.dismiss(animated: flag, completion: completion)
|
||||
}
|
||||
|
||||
self.dismissed?()
|
||||
}
|
||||
@ -889,6 +901,8 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
|
||||
return
|
||||
}
|
||||
|
||||
let selectedEmoticon = selectedEmoticon?.strippedEmoji
|
||||
|
||||
let isFirstTime = strongSelf.entries == nil
|
||||
let presentationData = strongSelf.presentationData
|
||||
|
||||
@ -898,7 +912,7 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
|
||||
guard let emoticon = theme.emoticon else {
|
||||
continue
|
||||
}
|
||||
entries.append(ThemeSettingsThemeEntry(index: entries.count, emoticon: emoticon, emojiFile: animatedEmojiStickers[emoticon]?.first?.file, themeReference: .cloud(PresentationCloudTheme(theme: theme, resolvedWallpaper: nil, creatorAccountId: nil)), nightMode: isDarkAppearance, selected: selectedEmoticon == theme.emoticon, theme: presentationData.theme, strings: presentationData.strings, wallpaper: nil))
|
||||
entries.append(ThemeSettingsThemeEntry(index: entries.count, emoticon: emoticon, emojiFile: animatedEmojiStickers[emoticon]?.first?.file, themeReference: .cloud(PresentationCloudTheme(theme: theme, resolvedWallpaper: nil, creatorAccountId: nil)), nightMode: isDarkAppearance, selected: selectedEmoticon == theme.emoticon?.strippedEmoji, theme: presentationData.theme, strings: presentationData.strings, wallpaper: nil))
|
||||
}
|
||||
|
||||
let action: (String?) -> Void = { [weak self] emoticon in
|
||||
@ -981,7 +995,7 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
|
||||
var scrollToItem: ListViewScrollToItem?
|
||||
if !self.initialized {
|
||||
if let index = transition.entries.firstIndex(where: { entry in
|
||||
return entry.emoticon == self.initiallySelectedEmoticon
|
||||
return entry.emoticon?.strippedEmoji == self.initiallySelectedEmoticon?.strippedEmoji
|
||||
}) {
|
||||
scrollToItem = ListViewScrollToItem(index: index, position: .bottom(-57.0), animated: false, curve: .Default(duration: 0.0), directionHint: .Down)
|
||||
self.initialized = true
|
||||
@ -1013,18 +1027,22 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
|
||||
}
|
||||
|
||||
private func updateButtons() {
|
||||
let canResetWallpaper = self.controller?.canResetWallpaper ?? false
|
||||
|
||||
let doneButtonTitle: String
|
||||
let otherButtonTitle: String
|
||||
var accentButtonTheme = true
|
||||
if self.selectedEmoticon == self.initiallySelectedEmoticon {
|
||||
var destructiveOtherButton = false
|
||||
if self.selectedEmoticon?.strippedEmoji == self.initiallySelectedEmoticon?.strippedEmoji {
|
||||
doneButtonTitle = self.presentationData.strings.Conversation_Theme_SetPhotoWallpaper
|
||||
otherButtonTitle = self.presentationData.strings.Conversation_Theme_SetColorWallpaper
|
||||
otherButtonTitle = canResetWallpaper ? self.presentationData.strings.Conversation_Theme_ResetWallpaper : self.presentationData.strings.Common_Cancel
|
||||
accentButtonTheme = false
|
||||
destructiveOtherButton = canResetWallpaper
|
||||
} else if self.selectedEmoticon == nil && self.initiallySelectedEmoticon != nil {
|
||||
doneButtonTitle = self.presentationData.strings.Conversation_Theme_Reset
|
||||
otherButtonTitle = self.presentationData.strings.Conversation_Theme_OtherOptions
|
||||
} else {
|
||||
doneButtonTitle = self.presentationData.strings.Conversation_Theme_Apply
|
||||
doneButtonTitle = self.presentationData.strings.Conversation_Theme_ApplyBackground
|
||||
otherButtonTitle = self.presentationData.strings.Conversation_Theme_OtherOptions
|
||||
}
|
||||
|
||||
@ -1040,7 +1058,7 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
|
||||
}
|
||||
self.doneButton.updateTheme(buttonTheme)
|
||||
|
||||
self.otherButton.setTitle(otherButtonTitle, with: Font.regular(17.0), with: self.presentationData.theme.actionSheet.controlAccentColor, for: .normal)
|
||||
self.otherButton.setTitle(otherButtonTitle, with: Font.regular(17.0), with: destructiveOtherButton ? self.presentationData.theme.actionSheet.destructiveActionTextColor : self.presentationData.theme.actionSheet.controlAccentColor, for: .normal)
|
||||
}
|
||||
|
||||
private var switchThemeIconAnimator: DisplayLinkAnimator?
|
||||
@ -1099,15 +1117,20 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
|
||||
}
|
||||
|
||||
@objc func otherButtonPressed() {
|
||||
if self.selectedEmoticon != self.initiallySelectedEmoticon {
|
||||
if self.selectedEmoticon?.strippedEmoji != self.initiallySelectedEmoticon?.strippedEmoji {
|
||||
self.setEmoticon(self.initiallySelectedEmoticon)
|
||||
} else {
|
||||
self.controller?.changeColor()
|
||||
if self.controller?.canResetWallpaper == true {
|
||||
self.controller?.resetWallpaper()
|
||||
self.cancelButtonPressed()
|
||||
} else {
|
||||
self.cancelButtonPressed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func dimTapped() {
|
||||
if self.selectedEmoticon == self.initiallySelectedEmoticon {
|
||||
if self.selectedEmoticon?.strippedEmoji == self.initiallySelectedEmoticon?.strippedEmoji {
|
||||
self.cancelButtonPressed()
|
||||
} else {
|
||||
let alertController = textAlertController(context: self.context, updatedPresentationData: (self.presentationData, .single(self.presentationData)), title: nil, text: self.presentationData.strings.Conversation_Theme_DismissAlert, actions: [TextAlertAction(type: .genericAction, title: self.presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Conversation_Theme_DismissAlertApply, action: { [weak self] in
|
||||
@ -1229,7 +1252,7 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
|
||||
if let strongSelf = self, count < 2 && currentTimestamp > timestamp + 24 * 60 * 60 {
|
||||
strongSelf.displayedPreviewTooltip = true
|
||||
|
||||
strongSelf.present?(TooltipScreen(account: strongSelf.context.account, text: isDark ? strongSelf.presentationData.strings.Conversation_Theme_PreviewLight(strongSelf.peerName).string : strongSelf.presentationData.strings.Conversation_Theme_PreviewDark(strongSelf.peerName).string, style: .default, icon: nil, location: .point(frame.offsetBy(dx: 3.0, dy: 6.0), .bottom), displayDuration: .custom(3.0), inset: 3.0, shouldDismissOnTouch: { _ in
|
||||
strongSelf.present?(TooltipScreen(account: strongSelf.context.account, sharedContext: strongSelf.context.sharedContext, text: isDark ? strongSelf.presentationData.strings.Conversation_Theme_PreviewLight(strongSelf.peerName).string : strongSelf.presentationData.strings.Conversation_Theme_PreviewDark(strongSelf.peerName).string, style: .default, icon: nil, location: .point(frame.offsetBy(dx: 3.0, dy: 6.0), .bottom), displayDuration: .custom(3.0), inset: 3.0, shouldDismissOnTouch: { _ in
|
||||
return .dismiss(consume: false)
|
||||
}))
|
||||
|
||||
|
@ -398,9 +398,9 @@ private func fetchCachedBlurredWallpaperRepresentation(resource: MediaResource,
|
||||
let path = NSTemporaryDirectory() + "\(Int64.random(in: Int64.min ... Int64.max))"
|
||||
let url = URL(fileURLWithPath: path)
|
||||
|
||||
if let colorImage = blurredImage(image, radius: 20.0), let colorDestination = CGImageDestinationCreateWithURL(url as CFURL, kUTTypeJPEG, 1, nil) {
|
||||
if let colorImage = blurredImage(image, radius: 30.0), let colorDestination = CGImageDestinationCreateWithURL(url as CFURL, kUTTypeJPEG, 1, nil) {
|
||||
CGImageDestinationSetProperties(colorDestination, NSDictionary() as CFDictionary)
|
||||
|
||||
|
||||
let colorQuality: Float = 0.5
|
||||
|
||||
let options = NSMutableDictionary()
|
||||
@ -447,7 +447,7 @@ private func fetchCachedBlurredWallpaperRepresentation(account: Account, resourc
|
||||
let path = NSTemporaryDirectory() + "\(Int64.random(in: Int64.min ... Int64.max))"
|
||||
let url = URL(fileURLWithPath: path)
|
||||
|
||||
if let colorImage = blurredImage(image, radius: 20.0), let colorDestination = CGImageDestinationCreateWithURL(url as CFURL, kUTTypeJPEG, 1, nil) {
|
||||
if let colorImage = blurredImage(image, radius: 30.0), let colorDestination = CGImageDestinationCreateWithURL(url as CFURL, kUTTypeJPEG, 1, nil) {
|
||||
CGImageDestinationSetProperties(colorDestination, NSDictionary() as CFDictionary)
|
||||
|
||||
let colorQuality: Float = 0.5
|
||||
|
@ -132,8 +132,8 @@ public func navigateToChatControllerImpl(_ params: NavigateToChatControllerParam
|
||||
if let attachBotStart = params.attachBotStart {
|
||||
controller.presentAttachmentBot(botId: attachBotStart.botId, payload: attachBotStart.payload, justInstalled: attachBotStart.justInstalled)
|
||||
}
|
||||
if let botAppStart = params.botAppStart {
|
||||
controller.presentBotApp(botApp: botAppStart.botApp, payload: botAppStart.payload)
|
||||
if let botAppStart = params.botAppStart, case let .peer(peer) = params.chatLocation {
|
||||
controller.presentBotApp(botApp: botAppStart.botApp, botPeer: peer, payload: botAppStart.payload)
|
||||
}
|
||||
} else {
|
||||
controller = ChatControllerImpl(context: params.context, chatLocation: params.chatLocation.asChatLocation, chatLocationContextHolder: params.chatLocationContextHolder, subject: params.subject, botStart: params.botStart, attachBotStart: params.attachBotStart, botAppStart: params.botAppStart, peekData: params.peekData, peerNearbyData: params.peerNearbyData, chatListFilter: params.chatListFilter, chatNavigationStack: params.chatNavigationStack)
|
||||
|
@ -8467,7 +8467,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
return
|
||||
}
|
||||
let buttonFrame = buttonNode.view.convert(buttonNode.bounds, to: self.view)
|
||||
controller.present(TooltipScreen(account: self.context.account, text: self.presentationData.strings.SharedMedia_CalendarTooltip, style: .default, icon: .none, location: .point(buttonFrame.insetBy(dx: 0.0, dy: 5.0), .top), shouldDismissOnTouch: { point in
|
||||
controller.present(TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: self.presentationData.strings.SharedMedia_CalendarTooltip, style: .default, icon: .none, location: .point(buttonFrame.insetBy(dx: 0.0, dy: 5.0), .top), shouldDismissOnTouch: { point in
|
||||
return .dismiss(consume: false)
|
||||
}), in: .current)
|
||||
}
|
||||
|
@ -162,6 +162,9 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
public let currentMediaInputSettings: Atomic<MediaInputSettings>
|
||||
private var mediaInputSettingsDisposable: Disposable?
|
||||
|
||||
public let currentMediaDisplaySettings: Atomic<MediaDisplaySettings>
|
||||
private var mediaDisplaySettingsDisposable: Disposable?
|
||||
|
||||
public let currentStickerSettings: Atomic<StickerSettings>
|
||||
private var stickerSettingsDisposable: Disposable?
|
||||
|
||||
@ -241,6 +244,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
self.currentAutomaticMediaDownloadSettings = initialPresentationDataAndSettings.automaticMediaDownloadSettings
|
||||
self.currentAutodownloadSettings = Atomic(value: initialPresentationDataAndSettings.autodownloadSettings)
|
||||
self.currentMediaInputSettings = Atomic(value: initialPresentationDataAndSettings.mediaInputSettings)
|
||||
self.currentMediaDisplaySettings = Atomic(value: initialPresentationDataAndSettings.mediaDisplaySettings)
|
||||
self.currentStickerSettings = Atomic(value: initialPresentationDataAndSettings.stickerSettings)
|
||||
self.currentInAppNotificationSettings = Atomic(value: initialPresentationDataAndSettings.inAppNotificationSettings)
|
||||
|
||||
@ -359,6 +363,15 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
}
|
||||
})
|
||||
|
||||
self.mediaDisplaySettingsDisposable = (self.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.mediaDisplaySettings])
|
||||
|> deliverOnMainQueue).start(next: { [weak self] sharedData in
|
||||
if let strongSelf = self {
|
||||
if let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.mediaDisplaySettings]?.get(MediaDisplaySettings.self) {
|
||||
let _ = strongSelf.currentMediaDisplaySettings.swap(settings)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
self.stickerSettingsDisposable = (self.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.stickerSettings])
|
||||
|> deliverOnMainQueue).start(next: { [weak self] sharedData in
|
||||
if let strongSelf = self {
|
||||
@ -895,6 +908,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
self.currentAutodownloadSettingsDisposable.dispose()
|
||||
self.inAppNotificationSettingsDisposable?.dispose()
|
||||
self.mediaInputSettingsDisposable?.dispose()
|
||||
self.mediaDisplaySettingsDisposable?.dispose()
|
||||
self.callDisposable?.dispose()
|
||||
self.groupCallDisposable?.dispose()
|
||||
self.callStateDisposable?.dispose()
|
||||
|
@ -0,0 +1,50 @@
|
||||
import Foundation
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import SwiftSignalKit
|
||||
|
||||
public struct MediaDisplaySettings: Codable, Equatable {
|
||||
public let showNextMediaOnTap: Bool
|
||||
|
||||
public static var defaultSettings: MediaDisplaySettings {
|
||||
return MediaDisplaySettings(showNextMediaOnTap: true)
|
||||
}
|
||||
|
||||
public init(showNextMediaOnTap: Bool) {
|
||||
self.showNextMediaOnTap = showNextMediaOnTap
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
self.showNextMediaOnTap = (try container.decode(Int32.self, forKey: "showNextMediaOnTap")) != 0
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
try container.encode((self.showNextMediaOnTap ? 1 : 0) as Int32, forKey: "showNextMediaOnTap")
|
||||
}
|
||||
|
||||
public static func ==(lhs: MediaDisplaySettings, rhs: MediaDisplaySettings) -> Bool {
|
||||
return lhs.showNextMediaOnTap == rhs.showNextMediaOnTap
|
||||
}
|
||||
|
||||
public func withUpdatedShowNextMediaOnTap(_ showNextMediaOnTap: Bool) -> MediaDisplaySettings {
|
||||
return MediaDisplaySettings(showNextMediaOnTap: showNextMediaOnTap)
|
||||
}
|
||||
}
|
||||
|
||||
public func updateMediaDisplaySettingsInteractively(accountManager: AccountManager<TelegramAccountManagerTypes>, _ f: @escaping (MediaDisplaySettings) -> MediaDisplaySettings) -> Signal<Void, NoError> {
|
||||
return accountManager.transaction { transaction -> Void in
|
||||
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.mediaDisplaySettings, { entry in
|
||||
let currentSettings: MediaDisplaySettings
|
||||
if let entry = entry?.get(MediaDisplaySettings.self) {
|
||||
currentSettings = entry
|
||||
} else {
|
||||
currentSettings = MediaDisplaySettings.defaultSettings
|
||||
}
|
||||
return PreferencesEntry(f(currentSettings))
|
||||
})
|
||||
}
|
||||
}
|
@ -39,6 +39,7 @@ private enum ApplicationSpecificSharedDataKeyValues: Int32 {
|
||||
case intentsSettings = 17
|
||||
case translationSettings = 18
|
||||
case drawingSettings = 19
|
||||
case mediaDisplaySettings = 20
|
||||
}
|
||||
|
||||
public struct ApplicationSpecificSharedDataKeys {
|
||||
@ -62,6 +63,7 @@ public struct ApplicationSpecificSharedDataKeys {
|
||||
public static let intentsSettings = applicationSpecificPreferencesKey(ApplicationSpecificSharedDataKeyValues.intentsSettings.rawValue)
|
||||
public static let translationSettings = applicationSpecificPreferencesKey(ApplicationSpecificSharedDataKeyValues.translationSettings.rawValue)
|
||||
public static let drawingSettings = applicationSpecificPreferencesKey(ApplicationSpecificSharedDataKeyValues.drawingSettings.rawValue)
|
||||
public static let mediaDisplaySettings = applicationSpecificPreferencesKey(ApplicationSpecificSharedDataKeyValues.mediaDisplaySettings.rawValue)
|
||||
}
|
||||
|
||||
private enum ApplicationSpecificItemCacheCollectionIdValues: Int8 {
|
||||
|
@ -11,6 +11,7 @@ import TelegramCore
|
||||
import TextFormat
|
||||
import Postbox
|
||||
import UrlEscaping
|
||||
import AccountContext
|
||||
|
||||
public protocol TooltipCustomContentNode: ASDisplayNode {
|
||||
func animateIn()
|
||||
@ -127,12 +128,11 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||
private let backgroundContainerNode: ASDisplayNode
|
||||
private let backgroundClipNode: ASDisplayNode
|
||||
private let backgroundMaskNode: ASDisplayNode
|
||||
private var effectView: UIView?
|
||||
private var effectNode: NavigationBackgroundNode?
|
||||
private var gradientNode: ASDisplayNode?
|
||||
private var arrowGradientNode: ASDisplayNode?
|
||||
private let arrowNode: ASImageNode
|
||||
private let arrowContainer: ASDisplayNode
|
||||
private var arrowEffectView: UIView?
|
||||
private let animatedStickerNode: AnimatedStickerNode
|
||||
private var downArrowsNode: DownArrowsIconNode?
|
||||
private let textNode: ImmediateTextNode
|
||||
@ -143,7 +143,7 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||
|
||||
private var validLayout: ContainerViewLayout?
|
||||
|
||||
init(account: Account, text: String, textEntities: [MessageTextEntity], style: TooltipScreen.Style, icon: TooltipScreen.Icon?, customContentNode: TooltipCustomContentNode? = nil, location: TooltipScreen.Location, displayDuration: TooltipScreen.DisplayDuration, inset: CGFloat = 13.0, shouldDismissOnTouch: @escaping (CGPoint) -> TooltipScreen.DismissOnTouch, requestDismiss: @escaping () -> Void, openActiveTextItem: ((TooltipActiveTextItem, TooltipActiveTextAction) -> Void)?) {
|
||||
init(account: Account, sharedContext: SharedAccountContext, text: String, textEntities: [MessageTextEntity], style: TooltipScreen.Style, icon: TooltipScreen.Icon?, customContentNode: TooltipCustomContentNode? = nil, location: TooltipScreen.Location, displayDuration: TooltipScreen.DisplayDuration, inset: CGFloat = 13.0, shouldDismissOnTouch: @escaping (CGPoint) -> TooltipScreen.DismissOnTouch, requestDismiss: @escaping () -> Void, openActiveTextItem: ((TooltipActiveTextItem, TooltipActiveTextAction) -> Void)?) {
|
||||
self.tooltipStyle = style
|
||||
self.icon = icon
|
||||
self.customContentNode = customContentNode
|
||||
@ -210,9 +210,16 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||
|
||||
self.arrowContainer = ASDisplayNode()
|
||||
|
||||
let theme = sharedContext.currentPresentationData.with { $0 }.theme
|
||||
let fontSize: CGFloat
|
||||
if case .top = location {
|
||||
self.effectView = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
|
||||
let backgroundColor: UIColor
|
||||
if theme.overallDarkAppearance {
|
||||
backgroundColor = theme.rootController.navigationBar.blurredBackgroundColor
|
||||
} else {
|
||||
backgroundColor = UIColor(rgb: 0x000000, alpha: 0.6)
|
||||
}
|
||||
self.effectNode = NavigationBackgroundNode(color: backgroundColor)
|
||||
self.backgroundMaskNode.addSubnode(self.backgroundClipNode)
|
||||
self.backgroundClipNode.clipsToBounds = true
|
||||
if case let .point(_, arrowPosition) = location, case .right = arrowPosition {
|
||||
@ -258,20 +265,28 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||
maskLayer.frame = CGRect(origin: CGPoint(), size: arrowSize)
|
||||
self.arrowContainer.layer.mask = maskLayer
|
||||
} else {
|
||||
let effect: UIBlurEffect
|
||||
if case .light = style {
|
||||
effect = UIBlurEffect(style: .light)
|
||||
var enableSaturation = true
|
||||
let backgroundColor: UIColor
|
||||
if case let .customBlur(color) = style {
|
||||
backgroundColor = color
|
||||
enableSaturation = false
|
||||
} else if case .light = style {
|
||||
backgroundColor = theme.rootController.navigationBar.blurredBackgroundColor
|
||||
} else {
|
||||
effect = UIBlurEffect(style: .dark)
|
||||
if theme.overallDarkAppearance {
|
||||
backgroundColor = theme.rootController.navigationBar.blurredBackgroundColor
|
||||
} else {
|
||||
backgroundColor = UIColor(rgb: 0x000000, alpha: 0.6)
|
||||
}
|
||||
}
|
||||
self.effectView = UIVisualEffectView(effect: effect)
|
||||
self.effectNode = NavigationBackgroundNode(color: backgroundColor, enableBlur: true, enableSaturation: enableSaturation)
|
||||
|
||||
self.backgroundMaskNode.addSubnode(self.backgroundClipNode)
|
||||
self.backgroundClipNode.clipsToBounds = true
|
||||
if case let .point(_, arrowPosition) = location, case .right = arrowPosition {
|
||||
self.backgroundClipNode.cornerRadius = 8.5
|
||||
} else {
|
||||
self.backgroundClipNode.cornerRadius = 14.0
|
||||
self.backgroundClipNode.cornerRadius = 12.5
|
||||
}
|
||||
if #available(iOS 13.0, *) {
|
||||
self.backgroundClipNode.layer.cornerCurve = .continuous
|
||||
@ -318,8 +333,8 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||
if let gradientNode = self.gradientNode {
|
||||
self.backgroundContainerNode.addSubnode(gradientNode)
|
||||
self.containerNode.addSubnode(self.arrowContainer)
|
||||
} else if let effectView = self.effectView {
|
||||
self.backgroundContainerNode.view.addSubview(effectView)
|
||||
} else if let effectNode = self.effectNode {
|
||||
self.backgroundContainerNode.addSubnode(effectNode)
|
||||
self.backgroundContainerNode.layer.mask = self.backgroundMaskNode.layer
|
||||
}
|
||||
self.containerNode.addSubnode(self.textNode)
|
||||
@ -430,7 +445,7 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||
|
||||
let backgroundHeight: CGFloat
|
||||
switch self.tooltipStyle {
|
||||
case .default, .gradient:
|
||||
case .default, .gradient, .customBlur:
|
||||
backgroundHeight = max(animationSize.height, textSize.height) + contentVerticalInset * 2.0
|
||||
case .light:
|
||||
backgroundHeight = max(28.0, max(animationSize.height, textSize.height) + 4.0 * 2.0)
|
||||
@ -472,8 +487,10 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||
transition.updateFrame(node: self.backgroundMaskNode, frame: CGRect(origin: CGPoint(), size: backgroundFrame.size).insetBy(dx: -10.0, dy: -10.0))
|
||||
transition.updateFrame(node: self.backgroundClipNode, frame: CGRect(origin: CGPoint(x: 10.0, y: 10.0), size: backgroundFrame.size))
|
||||
|
||||
if let effectView = self.effectView {
|
||||
transition.updateFrame(view: effectView, frame: CGRect(origin: CGPoint(), size: backgroundFrame.size).insetBy(dx: -10.0, dy: -10.0))
|
||||
if let effectNode = self.effectNode {
|
||||
let effectFrame = CGRect(origin: CGPoint(), size: backgroundFrame.size).insetBy(dx: -10.0, dy: -10.0)
|
||||
transition.updateFrame(node: effectNode, frame: effectFrame)
|
||||
effectNode.update(size: effectFrame.size, transition: transition)
|
||||
}
|
||||
if let gradientNode = self.gradientNode {
|
||||
transition.updateFrame(node: gradientNode, frame: CGRect(origin: CGPoint(), size: backgroundFrame.size))
|
||||
@ -501,7 +518,6 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||
|
||||
let arrowBounds = CGRect(origin: CGPoint(), size: arrowSize)
|
||||
self.arrowNode.frame = arrowBounds
|
||||
self.arrowEffectView?.frame = arrowBounds
|
||||
self.arrowGradientNode?.frame = CGRect(origin: CGPoint(x: -arrowFrame.minX + backgroundFrame.minX, y: 0.0), size: backgroundFrame.size)
|
||||
case .right:
|
||||
arrowFrame = CGRect(origin: CGPoint(x: backgroundFrame.width + arrowSize.height, y: rect.midY), size: CGSize(width: arrowSize.height, height: arrowSize.width))
|
||||
@ -512,12 +528,10 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||
|
||||
let arrowBounds = CGRect(origin: .zero, size: arrowSize)
|
||||
self.arrowNode.frame = arrowBounds
|
||||
self.arrowEffectView?.frame = arrowBounds
|
||||
self.arrowGradientNode?.frame = arrowBounds
|
||||
}
|
||||
} else {
|
||||
self.arrowNode.isHidden = true
|
||||
self.arrowEffectView?.isHidden = true
|
||||
}
|
||||
|
||||
transition.updateFrame(node: self.textNode, frame: CGRect(origin: CGPoint(x: contentInset + animationSize.width + animationSpacing, y: floor((backgroundHeight - textSize.height) / 2.0)), size: textSize))
|
||||
@ -672,10 +686,12 @@ public final class TooltipScreen: ViewController {
|
||||
public enum Style {
|
||||
case `default`
|
||||
case light
|
||||
case customBlur(UIColor)
|
||||
case gradient(UIColor, UIColor)
|
||||
}
|
||||
|
||||
private let account: Account
|
||||
private let sharedContext: SharedAccountContext
|
||||
public let text: String
|
||||
public let textEntities: [MessageTextEntity]
|
||||
private let style: TooltipScreen.Style
|
||||
@ -707,8 +723,9 @@ public final class TooltipScreen: ViewController {
|
||||
|
||||
public var alwaysVisible = false
|
||||
|
||||
public init(account: Account, text: String, textEntities: [MessageTextEntity] = [], style: TooltipScreen.Style = .default, icon: TooltipScreen.Icon?, customContentNode: TooltipCustomContentNode? = nil, location: TooltipScreen.Location, displayDuration: DisplayDuration = .default, inset: CGFloat = 13.0, shouldDismissOnTouch: @escaping (CGPoint) -> TooltipScreen.DismissOnTouch, openActiveTextItem: ((TooltipActiveTextItem, TooltipActiveTextAction) -> Void)? = nil) {
|
||||
public init(account: Account, sharedContext: SharedAccountContext, text: String, textEntities: [MessageTextEntity] = [], style: TooltipScreen.Style = .default, icon: TooltipScreen.Icon?, customContentNode: TooltipCustomContentNode? = nil, location: TooltipScreen.Location, displayDuration: DisplayDuration = .default, inset: CGFloat = 13.0, shouldDismissOnTouch: @escaping (CGPoint) -> TooltipScreen.DismissOnTouch, openActiveTextItem: ((TooltipActiveTextItem, TooltipActiveTextAction) -> Void)? = nil) {
|
||||
self.account = account
|
||||
self.sharedContext = sharedContext
|
||||
self.text = text
|
||||
self.textEntities = textEntities
|
||||
self.style = style
|
||||
@ -776,7 +793,7 @@ public final class TooltipScreen: ViewController {
|
||||
}
|
||||
|
||||
override public func loadDisplayNode() {
|
||||
self.displayNode = TooltipScreenNode(account: self.account, text: self.text, textEntities: self.textEntities, style: self.style, icon: self.icon, customContentNode: self.customContentNode, location: self.location, displayDuration: self.displayDuration, inset: self.inset, shouldDismissOnTouch: self.shouldDismissOnTouch, requestDismiss: { [weak self] in
|
||||
self.displayNode = TooltipScreenNode(account: self.account, sharedContext: self.sharedContext, text: self.text, textEntities: self.textEntities, style: self.style, icon: self.icon, customContentNode: self.customContentNode, location: self.location, displayDuration: self.displayDuration, inset: self.inset, shouldDismissOnTouch: self.shouldDismissOnTouch, requestDismiss: { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
@ -743,6 +743,7 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
|
||||
private var gradientBackgroundNode: GradientBackgroundNode?
|
||||
private var outgoingBubbleGradientBackgroundNode: GradientBackgroundNode?
|
||||
private let patternImageLayer: EffectImageLayer
|
||||
private let dimLayer: SimpleLayer
|
||||
private var isGeneratingPatternImage: Bool = false
|
||||
|
||||
private let bakedBackgroundView: UIImageView
|
||||
@ -862,6 +863,9 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
|
||||
self.bakedBackgroundView = UIImageView()
|
||||
self.bakedBackgroundView.isHidden = true
|
||||
|
||||
self.dimLayer = SimpleLayer()
|
||||
self.dimLayer.backgroundColor = UIColor.black.cgColor
|
||||
|
||||
super.init()
|
||||
|
||||
if #available(iOS 12.0, *) {
|
||||
@ -885,6 +889,8 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
|
||||
self.contentNode.frame = self.bounds
|
||||
self.addSubnode(self.contentNode)
|
||||
self.layer.addSublayer(self.patternImageLayer)
|
||||
|
||||
self.layer.addSublayer(self.dimLayer)
|
||||
}
|
||||
|
||||
deinit {
|
||||
@ -892,6 +898,19 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
|
||||
self.wallpaperDisposable.dispose()
|
||||
self.imageDisposable.dispose()
|
||||
}
|
||||
|
||||
private func updateDimming() {
|
||||
guard let wallpaper = self.wallpaper, let theme = self.bubbleTheme else {
|
||||
return
|
||||
}
|
||||
var dimAlpha: Float = 0.0
|
||||
if case let .file(file) = wallpaper, !file.isPattern {
|
||||
if let intensity = file.settings.intensity, intensity < 100, theme.overallDarkAppearance == true {
|
||||
dimAlpha = 1.0 - max(0.0, min(1.0, Float(intensity) / 100.0))
|
||||
}
|
||||
}
|
||||
self.dimLayer.opacity = dimAlpha
|
||||
}
|
||||
|
||||
func update(wallpaper: TelegramWallpaper) {
|
||||
if self.wallpaper == wallpaper {
|
||||
@ -915,7 +934,7 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
|
||||
gradientColors = file.settings.colors
|
||||
gradientAngle = file.settings.rotation ?? 0
|
||||
}
|
||||
|
||||
|
||||
var scheduleLoopingEvent = false
|
||||
if gradientColors.count >= 3 {
|
||||
let mappedColors = gradientColors.map { color -> UIColor in
|
||||
@ -1032,6 +1051,8 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
|
||||
self.animateEvent(transition: .animated(duration: 0.7, curve: .linear), extendAnimation: false)
|
||||
}
|
||||
}
|
||||
|
||||
self.updateDimming()
|
||||
}
|
||||
|
||||
func _internalUpdateIsSettingUpWallpaper() {
|
||||
@ -1304,6 +1325,8 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
|
||||
transition.updateFrame(node: outgoingBackgroundNode, frame: CGRect(origin: CGPoint(), size: size))
|
||||
outgoingBackgroundNode.update(rect: CGRect(origin: CGPoint(), size: size), within: size, transition: transition)
|
||||
}
|
||||
|
||||
transition.updateFrame(layer: self.dimLayer, frame: CGRect(origin: CGPoint(), size: size))
|
||||
|
||||
self.loadPatternForSizeIfNeeded(size: size, displayMode: displayMode, transition: transition)
|
||||
|
||||
@ -1378,6 +1401,7 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
|
||||
}
|
||||
|
||||
self.updateBubbles()
|
||||
self.updateDimming()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -144,7 +144,11 @@ public func wallpaperDatas(account: Account, accountManager: AccountManager<Tele
|
||||
return (thumbnailData, betterFullSizeData ?? fullSizeData, complete)
|
||||
})
|
||||
} else {
|
||||
return .single((thumbnailData, fullSizeData, complete))
|
||||
if thumbnailData == nil, let decodedThumbnailData = decodedThumbnailData {
|
||||
return .single((decodedThumbnailData, fullSizeData, complete))
|
||||
} else {
|
||||
return .single((thumbnailData, fullSizeData, complete))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -629,7 +629,7 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
||||
case "web_app_ready":
|
||||
self.animateTransitionIn()
|
||||
case "web_app_switch_inline_query":
|
||||
if controller.isInline, let json, let query = json["query"] as? String {
|
||||
if let json, let query = json["query"] as? String {
|
||||
if let chatTypes = json["chat_types"] as? [String], !chatTypes.isEmpty {
|
||||
var requestPeerTypes: [ReplyMarkupButtonRequestPeerType] = []
|
||||
for type in chatTypes {
|
||||
|
287
submodules/WebUI/Sources/WebAppOpenConfirmationController.swift
Normal file
287
submodules/WebUI/Sources/WebAppOpenConfirmationController.swift
Normal file
@ -0,0 +1,287 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import SwiftSignalKit
|
||||
import AsyncDisplayKit
|
||||
import Display
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import TelegramPresentationData
|
||||
import TelegramUIPreferences
|
||||
import AccountContext
|
||||
import AppBundle
|
||||
import AvatarNode
|
||||
|
||||
private final class WebAppLaunchConfirmationAlertContentNode: AlertContentNode {
|
||||
private let strings: PresentationStrings
|
||||
private let title: String
|
||||
private let text: String
|
||||
private let showMore: Bool
|
||||
|
||||
private let titleNode: ImmediateTextNode
|
||||
private let textNode: ASTextNode
|
||||
private let avatarNode: AvatarNode
|
||||
|
||||
private let moreButton: HighlightableButtonNode
|
||||
private let arrowNode: ASImageNode
|
||||
|
||||
private let actionNodesSeparator: ASDisplayNode
|
||||
private let actionNodes: [TextAlertContentActionNode]
|
||||
private let actionVerticalSeparators: [ASDisplayNode]
|
||||
|
||||
private var validLayout: CGSize?
|
||||
|
||||
private let morePressed: () -> Void
|
||||
|
||||
override var dismissOnOutsideTap: Bool {
|
||||
return self.isUserInteractionEnabled
|
||||
}
|
||||
|
||||
init(context: AccountContext, theme: AlertControllerTheme, ptheme: PresentationTheme, strings: PresentationStrings, peer: EnginePeer, title: String, text: String, showMore: Bool, actions: [TextAlertAction], morePressed: @escaping () -> Void) {
|
||||
self.strings = strings
|
||||
self.title = title
|
||||
self.text = text
|
||||
self.showMore = showMore
|
||||
self.morePressed = morePressed
|
||||
|
||||
self.titleNode = ImmediateTextNode()
|
||||
self.titleNode.displaysAsynchronously = false
|
||||
self.titleNode.maximumNumberOfLines = 1
|
||||
self.titleNode.textAlignment = .center
|
||||
|
||||
self.textNode = ASTextNode()
|
||||
self.textNode.displaysAsynchronously = false
|
||||
self.textNode.maximumNumberOfLines = 0
|
||||
|
||||
self.avatarNode = AvatarNode(font: avatarPlaceholderFont(size: 26.0))
|
||||
|
||||
self.moreButton = HighlightableButtonNode()
|
||||
|
||||
self.arrowNode = ASImageNode()
|
||||
self.arrowNode.displaysAsynchronously = false
|
||||
self.arrowNode.displayWithoutProcessing = true
|
||||
self.arrowNode.isHidden = !showMore
|
||||
self.arrowNode.contentMode = .scaleAspectFit
|
||||
|
||||
self.actionNodesSeparator = ASDisplayNode()
|
||||
self.actionNodesSeparator.isLayerBacked = true
|
||||
|
||||
self.actionNodes = actions.map { action -> TextAlertContentActionNode in
|
||||
return TextAlertContentActionNode(theme: theme, action: action)
|
||||
}
|
||||
|
||||
var actionVerticalSeparators: [ASDisplayNode] = []
|
||||
if actions.count > 1 {
|
||||
for _ in 0 ..< actions.count - 1 {
|
||||
let separatorNode = ASDisplayNode()
|
||||
separatorNode.isLayerBacked = true
|
||||
actionVerticalSeparators.append(separatorNode)
|
||||
}
|
||||
}
|
||||
self.actionVerticalSeparators = actionVerticalSeparators
|
||||
|
||||
super.init()
|
||||
|
||||
self.addSubnode(self.titleNode)
|
||||
self.addSubnode(self.textNode)
|
||||
self.addSubnode(self.avatarNode)
|
||||
self.addSubnode(self.moreButton)
|
||||
self.moreButton.addSubnode(self.arrowNode)
|
||||
|
||||
self.addSubnode(self.actionNodesSeparator)
|
||||
|
||||
for actionNode in self.actionNodes {
|
||||
self.addSubnode(actionNode)
|
||||
}
|
||||
|
||||
for separatorNode in self.actionVerticalSeparators {
|
||||
self.addSubnode(separatorNode)
|
||||
}
|
||||
|
||||
self.updateTheme(theme)
|
||||
|
||||
self.avatarNode.setPeer(context: context, theme: ptheme, peer: peer)
|
||||
|
||||
self.moreButton.addTarget(self, action: #selector(self.moreButtonPressed), forControlEvents: .touchUpInside)
|
||||
}
|
||||
|
||||
@objc private func moreButtonPressed() {
|
||||
self.morePressed()
|
||||
}
|
||||
|
||||
override func updateTheme(_ theme: AlertControllerTheme) {
|
||||
self.titleNode.attributedText = NSAttributedString(string: self.title, font: Font.semibold(17.0), textColor: theme.primaryColor, paragraphAlignment: .center)
|
||||
self.textNode.attributedText = NSAttributedString(string: self.text, font: Font.regular(13.0), textColor: theme.primaryColor, paragraphAlignment: .center)
|
||||
|
||||
self.moreButton.setAttributedTitle(NSAttributedString(string: self.strings.WebApp_LaunchMoreInfo, font: Font.regular(13.0), textColor: theme.accentColor), for: .normal)
|
||||
self.arrowNode.image = generateTintedImage(image: UIImage(bundleImageName: "Peer Info/AlertArrow"), color: theme.accentColor)
|
||||
|
||||
self.actionNodesSeparator.backgroundColor = theme.separatorColor
|
||||
for actionNode in self.actionNodes {
|
||||
actionNode.updateTheme(theme)
|
||||
}
|
||||
for separatorNode in self.actionVerticalSeparators {
|
||||
separatorNode.backgroundColor = theme.separatorColor
|
||||
}
|
||||
|
||||
if let size = self.validLayout {
|
||||
_ = self.updateLayout(size: size, transition: .immediate)
|
||||
}
|
||||
}
|
||||
|
||||
override func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
|
||||
var size = size
|
||||
size.width = min(size.width, 270.0)
|
||||
|
||||
self.validLayout = size
|
||||
|
||||
var origin: CGPoint = CGPoint(x: 0.0, y: 20.0)
|
||||
|
||||
let avatarSize = CGSize(width: 60.0, height: 60.0)
|
||||
self.avatarNode.updateSize(size: avatarSize)
|
||||
|
||||
let avatarFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - avatarSize.width) / 2.0), y: origin.y), size: avatarSize)
|
||||
transition.updateFrame(node: self.avatarNode, frame: avatarFrame)
|
||||
|
||||
origin.y += avatarSize.height + 17.0
|
||||
|
||||
if let arrowImage = self.arrowNode.image {
|
||||
let arrowFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - arrowImage.size.width) / 2.0), y: origin.y + floorToScreenPixels((avatarSize.height - arrowImage.size.height) / 2.0)), size: arrowImage.size)
|
||||
transition.updateFrame(node: self.arrowNode, frame: arrowFrame)
|
||||
}
|
||||
|
||||
let titleSize = self.titleNode.updateLayout(CGSize(width: size.width - 32.0, height: size.height))
|
||||
transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - titleSize.width) / 2.0), y: origin.y), size: titleSize))
|
||||
origin.y += titleSize.height + 6.0
|
||||
|
||||
if self.showMore {
|
||||
let moreButtonSize = self.moreButton.measure(CGSize(width: size.width - 32.0, height: size.height))
|
||||
transition.updateFrame(node: self.moreButton, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - moreButtonSize.width) / 2.0) - 5.0, y: origin.y), size: moreButtonSize))
|
||||
transition.updateFrame(node: self.arrowNode, frame: CGRect(origin: CGPoint(x: moreButtonSize.width + 3.0, y: 4.0), size: CGSize(width: 9.0, height: 9.0)))
|
||||
origin.y += moreButtonSize.height + 22.0
|
||||
}
|
||||
|
||||
let textSize = self.textNode.measure(CGSize(width: size.width - 32.0, height: size.height))
|
||||
transition.updateFrame(node: self.textNode, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - textSize.width) / 2.0), y: origin.y), size: textSize))
|
||||
|
||||
let actionButtonHeight: CGFloat = 44.0
|
||||
var minActionsWidth: CGFloat = 0.0
|
||||
let maxActionWidth: CGFloat = floor(size.width / CGFloat(self.actionNodes.count))
|
||||
let actionTitleInsets: CGFloat = 8.0
|
||||
|
||||
var effectiveActionLayout = TextAlertContentActionLayout.horizontal
|
||||
for actionNode in self.actionNodes {
|
||||
let actionTitleSize = actionNode.titleNode.updateLayout(CGSize(width: maxActionWidth, height: actionButtonHeight))
|
||||
if case .horizontal = effectiveActionLayout, actionTitleSize.height > actionButtonHeight * 0.6667 {
|
||||
effectiveActionLayout = .vertical
|
||||
}
|
||||
switch effectiveActionLayout {
|
||||
case .horizontal:
|
||||
minActionsWidth += actionTitleSize.width + actionTitleInsets
|
||||
case .vertical:
|
||||
minActionsWidth = max(minActionsWidth, actionTitleSize.width + actionTitleInsets)
|
||||
}
|
||||
}
|
||||
|
||||
let insets = UIEdgeInsets(top: 18.0, left: 18.0, bottom: 18.0, right: 18.0)
|
||||
|
||||
let contentWidth = max(size.width, minActionsWidth)
|
||||
|
||||
var actionsHeight: CGFloat = 0.0
|
||||
switch effectiveActionLayout {
|
||||
case .horizontal:
|
||||
actionsHeight = actionButtonHeight
|
||||
case .vertical:
|
||||
actionsHeight = actionButtonHeight * CGFloat(self.actionNodes.count)
|
||||
}
|
||||
|
||||
var resultSize = CGSize(width: contentWidth, height: avatarSize.height + titleSize.height + textSize.height + actionsHeight + 25.0 + insets.top + insets.bottom)
|
||||
if self.showMore {
|
||||
resultSize.height += 37.0
|
||||
}
|
||||
|
||||
transition.updateFrame(node: self.actionNodesSeparator, frame: CGRect(origin: CGPoint(x: 0.0, y: resultSize.height - actionsHeight - UIScreenPixel), size: CGSize(width: resultSize.width, height: UIScreenPixel)))
|
||||
|
||||
var actionOffset: CGFloat = 0.0
|
||||
let actionWidth: CGFloat = floor(resultSize.width / CGFloat(self.actionNodes.count))
|
||||
var separatorIndex = -1
|
||||
var nodeIndex = 0
|
||||
for actionNode in self.actionNodes {
|
||||
if separatorIndex >= 0 {
|
||||
let separatorNode = self.actionVerticalSeparators[separatorIndex]
|
||||
switch effectiveActionLayout {
|
||||
case .horizontal:
|
||||
transition.updateFrame(node: separatorNode, frame: CGRect(origin: CGPoint(x: actionOffset - UIScreenPixel, y: resultSize.height - actionsHeight), size: CGSize(width: UIScreenPixel, height: actionsHeight - UIScreenPixel)))
|
||||
case .vertical:
|
||||
transition.updateFrame(node: separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: resultSize.height - actionsHeight + actionOffset - UIScreenPixel), size: CGSize(width: resultSize.width, height: UIScreenPixel)))
|
||||
}
|
||||
}
|
||||
separatorIndex += 1
|
||||
|
||||
let currentActionWidth: CGFloat
|
||||
switch effectiveActionLayout {
|
||||
case .horizontal:
|
||||
if nodeIndex == self.actionNodes.count - 1 {
|
||||
currentActionWidth = resultSize.width - actionOffset
|
||||
} else {
|
||||
currentActionWidth = actionWidth
|
||||
}
|
||||
case .vertical:
|
||||
currentActionWidth = resultSize.width
|
||||
}
|
||||
|
||||
let actionNodeFrame: CGRect
|
||||
switch effectiveActionLayout {
|
||||
case .horizontal:
|
||||
actionNodeFrame = CGRect(origin: CGPoint(x: actionOffset, y: resultSize.height - actionsHeight), size: CGSize(width: currentActionWidth, height: actionButtonHeight))
|
||||
actionOffset += currentActionWidth
|
||||
case .vertical:
|
||||
actionNodeFrame = CGRect(origin: CGPoint(x: 0.0, y: resultSize.height - actionsHeight + actionOffset), size: CGSize(width: currentActionWidth, height: actionButtonHeight))
|
||||
actionOffset += actionButtonHeight
|
||||
}
|
||||
|
||||
transition.updateFrame(node: actionNode, frame: actionNodeFrame)
|
||||
|
||||
nodeIndex += 1
|
||||
}
|
||||
|
||||
return resultSize
|
||||
}
|
||||
}
|
||||
|
||||
public func webAppLaunchConfirmationController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, peer: EnginePeer, commit: @escaping () -> Void, showMore: (() -> Void)?) -> AlertController {
|
||||
let theme = defaultDarkColorPresentationTheme
|
||||
let presentationData: PresentationData
|
||||
if let updatedPresentationData {
|
||||
presentationData = updatedPresentationData.initial
|
||||
} else {
|
||||
presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
}
|
||||
let strings = presentationData.strings
|
||||
|
||||
var dismissImpl: ((Bool) -> Void)?
|
||||
var contentNode: WebAppLaunchConfirmationAlertContentNode?
|
||||
let actions: [TextAlertAction] = [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {
|
||||
dismissImpl?(true)
|
||||
}), TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {
|
||||
dismissImpl?(true)
|
||||
commit()
|
||||
})]
|
||||
|
||||
let title = peer.compactDisplayTitle
|
||||
let text = presentationData.strings.WebApp_LaunchConfirmation
|
||||
|
||||
contentNode = WebAppLaunchConfirmationAlertContentNode(context: context, theme: AlertControllerTheme(presentationData: presentationData), ptheme: theme, strings: strings, peer: peer, title: title, text: text, showMore: showMore != nil, actions: actions, morePressed: {
|
||||
dismissImpl?(true)
|
||||
showMore?()
|
||||
})
|
||||
|
||||
let controller = AlertController(theme: AlertControllerTheme(presentationData: presentationData), contentNode: contentNode!)
|
||||
dismissImpl = { [weak controller] animated in
|
||||
if animated {
|
||||
controller?.dismissAnimated()
|
||||
} else {
|
||||
controller?.dismiss()
|
||||
}
|
||||
}
|
||||
return controller
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user