Chat wallpaper improvements

This commit is contained in:
Ilya Laktyushin 2023-04-07 17:39:24 +04:00
parent e4e810ae29
commit 97e0e96552
24 changed files with 1134 additions and 134 deletions

View File

@ -9158,3 +9158,6 @@ 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.";

View File

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

View File

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

View File

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

View File

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

View File

@ -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, _):
@ -196,7 +196,7 @@ 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, _):
@ -276,7 +276,25 @@ 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)!
}
if let brightness, abs(brightness) > 0.01 {
if let updatedImage = generateImage(croppedImage.size, contextGenerator: { size, context in
let bounds = CGRect(origin: .zero, size: size)
if let cgImage = croppedImage.cgImage {
context.draw(cgImage, in: bounds)
}
if brightness > 0.0 {
context.setFillColor(UIColor(rgb: 0xffffff, alpha: brightness).cgColor)
context.setBlendMode(.overlay)
} else {
context.setFillColor(UIColor(rgb: 0x000000, alpha: brightness * -1.0).cgColor)
}
context.fill(bounds)
}) {
croppedImage = updatedImage
}
}
let thumbnailDimensions = finalCropRect.size.fitted(CGSize(width: 320.0, height: 320.0))

View File

@ -152,7 +152,7 @@ final class ThemeColorsGridControllerNode: ASDisplayNode {
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)
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: {

View File

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

View File

@ -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,9 +999,10 @@ 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
@ -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))
}

View File

@ -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> {
@ -453,7 +453,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 +611,7 @@ public class WallpaperGalleryController: ViewController {
break
}
strongSelf.apply?(entry, options, centralItemNode.cropRect)
strongSelf.apply?(entry, options, centralItemNode.cropRect, centralItemNode.brightness)
}
}
}

View File

@ -95,23 +95,27 @@ 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 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()
@ -149,6 +153,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
self.statusNode.isUserInteractionEnabled = false
self.blurredNode = BlurredImageNode()
self.brightnessNode = ASDisplayNode()
self.messagesContainerNode = ASDisplayNode()
self.messagesContainerNode.transform = CATransform3DMakeScale(1.0, -1.0, 1.0)
@ -161,10 +166,17 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
self.patternButtonNode = WallpaperOptionButtonNode(title: self.presentationData.strings.WallpaperPreview_Pattern, value: .check(false))
self.patternButtonNode.setEnabled(false)
self.serviceBackgroundNode = NavigationBackgroundNode(color: UIColor(rgb: 0x000000, alpha: 0.35))
var sliderValueChangedImpl: ((CGFloat) -> Void)?
self.sliderNode = WallpaperSliderNode(minValue: 0.0, maxValue: 1.0, value: 0.5, 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: false)
self.shareButtonNode = WallpaperNavigationButtonNode(content: .icon(image: UIImage(bundleImageName: "Chat/Links/Share"), size: CGSize(width: 28.0, height: 28.0)), dark: false)
self.playButtonPlayImage = generateImage(CGSize(width: 48.0, height: 48.0), rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
@ -193,7 +205,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 +229,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,9 +237,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.imageNode.addSubnode(self.brightnessNode)
self.blurButtonNode.addTarget(self, action: #selector(self.toggleBlur), forControlEvents: .touchUpInside)
self.motionButtonNode.addTarget(self, action: #selector(self.toggleMotion), forControlEvents: .touchUpInside)
self.patternButtonNode.addTarget(self, action: #selector(self.togglePattern), forControlEvents: .touchUpInside)
@ -234,6 +250,24 @@ 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)
sliderValueChangedImpl = { [weak self] value in
if let self {
let value = (value - 0.5) * 2.0
if value < 0.0 {
self.brightnessNode.backgroundColor = UIColor(rgb: 0x000000)
self.brightnessNode.layer.compositingFilter = nil
self.brightnessNode.alpha = value * -1.0
} else if value > 0.0 {
self.brightnessNode.backgroundColor = UIColor(rgb: 0xffffff)
self.brightnessNode.layer.compositingFilter = "overlayBlendMode"
self.brightnessNode.alpha = value
} else {
self.brightnessNode.layer.compositingFilter = nil
self.brightnessNode.alpha = 0.0
}
}
}
}
deinit {
@ -255,6 +289,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 - 0.5) * 2.0
default:
return nil
}
}
override func ready() -> Signal<Void, NoError> {
return self._ready.get()
}
@ -721,7 +767,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 +778,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 +955,15 @@ 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:
additionalYOffset -= 44.0
default:
break
}
}
let buttonSpacing: CGFloat = 18.0
@ -944,6 +988,10 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
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)
let sliderFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - sliderSize.width) / 2.0) + offset.x, y: layout.size.height - toolbarHeight - layout.intrinsicInsets.bottom - 52.0 + offset.y), size: sliderSize)
var sliderIsHidden = true
let cancelSize = self.cancelButtonNode.measure(layout.size)
let cancelFrame = CGRect(origin: CGPoint(x: 16.0 + offset.x, y: 16.0), size: cancelSize)
@ -958,11 +1006,13 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
blurFrame = leftButtonFrame
motionAlpha = 1.0
motionFrame = rightButtonFrame
sliderIsHidden = false
case .contextResult:
blurAlpha = 1.0
blurFrame = leftButtonFrame
motionAlpha = 1.0
motionFrame = rightButtonFrame
sliderIsHidden = false
case let .wallpaper(wallpaper, _):
switch wallpaper {
case .builtin:
@ -1047,16 +1097,16 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
transition.updateAlpha(node: self.playButtonNode, alpha: playAlpha * alpha)
transition.updateSublayerTransformScale(node: self.playButtonNode, scale: max(0.1, playAlpha))
transition.updateFrame(node: self.sliderNode, frame: sliderFrame)
self.sliderNode.updateLayout(size: sliderFrame.size)
self.sliderNode.isHidden = sliderIsHidden
transition.updateFrame(node: self.cancelButtonNode, frame: cancelFrame)
transition.updateFrame(node: self.shareButtonNode, frame: shareFrame)
}
private func updateMessagesLayout(layout: ContainerViewLayout, offset: CGPoint, transition: ContainedViewLayoutTransition) {
let bottomInset: CGFloat = 132.0
if self.patternButtonNode.isSelected || self.colorsButtonNode.isSelected {
//bottomInset = 350.0
}
var bottomInset: CGFloat = 132.0
var items: [ListViewItem] = []
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(1))
@ -1125,6 +1175,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
case .asset, .contextResult:
topMessageText = presentationData.strings.WallpaperPreview_CropTopText
bottomMessageText = presentationData.strings.WallpaperPreview_CropBottomText
bottomInset += 44.0
case .customColor:
topMessageText = presentationData.strings.WallpaperPreview_CustomColorTopText
bottomMessageText = presentationData.strings.WallpaperPreview_CustomColorBottomText
@ -1188,6 +1239,14 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
self.messageNodes = messageNodes
}
if let _ = serviceMessageText, let messageNodes = self.messageNodes, let node = messageNodes.last {
if let backgroundNode = node.subnodes?.first?.subnodes?.first?.subnodes?.first?.subnodes?.first {
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)
}
}
let alpha = 1.0 - min(1.0, max(0.0, abs(offset.y) / 50.0))
if let messageNodes = self.messageNodes {
@ -1237,6 +1296,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
}
self.blurredNode.frame = self.imageNode.bounds
}
self.brightnessNode.frame = self.imageNode.bounds
let additionalYOffset: CGFloat = 0.0

View File

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

View File

@ -34,6 +34,61 @@ 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
override init() {
self.backgroundNode = NavigationBackgroundNode(color: UIColor(rgb: 0x333333, alpha: 0.3), enableBlur: true, enableSaturation: false)
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)
@ -42,7 +97,7 @@ final class WallpaperNavigationButtonNode: HighlightTrackingButtonNode {
private let content: Content
private let backgroundNode: WallpaperLightButtonBackgroundNode
private let backgroundNode: ASDisplayNode
private let iconNode: ASImageNode
@ -52,10 +107,14 @@ final class WallpaperNavigationButtonNode: HighlightTrackingButtonNode {
self.iconNode.image = generateTintedImage(image: image, color: .white)
}
init(content: Content) {
init(content: Content, dark: Bool) {
self.content = content
self.backgroundNode = WallpaperLightButtonBackgroundNode()
if dark {
self.backgroundNode = WallpaperOptionBackgroundNode()
} else {
self.backgroundNode = WallpaperLightButtonBackgroundNode()
}
self.iconNode = ASImageNode()
self.iconNode.displaysAsynchronously = false
@ -94,11 +153,6 @@ final class WallpaperNavigationButtonNode: 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)
// }
}
}
@ -119,7 +173,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
@ -132,7 +190,7 @@ final class WallpaperNavigationButtonNode: HighlightTrackingButtonNode {
final class WallpaperOptionButtonNode: HighlightTrackingButtonNode {
private let backgroundNode: NavigationBackgroundNode
private let backgroundNode: WallpaperOptionBackgroundNode
private let checkNode: CheckNode
private let colorNode: ASImageNode
@ -172,8 +230,7 @@ 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 +243,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 +262,7 @@ final class WallpaperOptionButtonNode: HighlightTrackingButtonNode {
}
self.addSubnode(self.backgroundNode)
self.addSubnode(self.checkNode)
self.addSubnode(self.textNode)
self.addSubnode(self.colorNode)
@ -227,11 +288,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 +378,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 +396,147 @@ 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)
}
func updateLayout(size: CGSize, 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 = (self.value - self.minValue) / range
let foregroundFrame = CGRect(origin: CGPoint(), size: CGSize(width: value * size.width, height: size.height))
transition.updateFrameAdditive(node: self.foregroundNode, frame: foregroundFrame)
transition.updateFrameAdditive(node: self.foregroundLightNode, frame: foregroundFrame)
}
@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 == 2.0 && previousValue != 2.0 {
self.hapticFeedback.impact(.soft)
} else if self.value == 1.0 && previousValue != 1.0 {
self.hapticFeedback.impact(.soft)
} else if self.value == 2.5 && previousValue != 2.5 {
self.hapticFeedback.impact(.soft)
} else if self.value == 0.05 && previousValue != 0.05 {
self.hapticFeedback.impact(.soft)
}
if abs(previousValue - self.value) >= 0.001 {
self.valueChanged(self.value, false)
}
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)
}
}

View File

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

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "brightness_max.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View 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

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "brightness_min.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View 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

View File

@ -845,7 +845,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, wallpaper: nil)
|> deliverOnMainQueue).start(completed: { [weak wallpaperPreviewController] in
wallpaperPreviewController?.dismiss()
@ -4264,12 +4264,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
@ -17173,7 +17172,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 +17229,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, 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 +17276,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)
}
@ -18535,9 +18555,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
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
controller.apply = { [weak self] wallpaper, options, cropRect, brightness in
if let strongSelf = self {
uploadCustomPeerWallpaper(context: strongSelf.context, wallpaper: wallpaper, mode: options, cropRect: cropRect, brightnessMultiplier: nil, peerId: peerId, completion: {
uploadCustomPeerWallpaper(context: strongSelf.context, wallpaper: wallpaper, mode: options, cropRect: cropRect, brightness: brightness, peerId: peerId, completion: {
dismissControllers()
})
}

View File

@ -398,7 +398,7 @@ 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, [:] as CFDictionary)
let colorQuality: Float = 0.5
@ -447,7 +447,7 @@ private func fetchCachedBlurredWallpaperRepresentation(account: Account, resourc
let path = NSTemporaryDirectory() + "\(Int64.random(in: Int64.min ... Int64.max))"
let 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, [:] as CFDictionary)
let colorQuality: Float = 0.5

View File

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

View File

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

View File

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

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