mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-05 05:51:42 +00:00
Wallpaper fixes
This commit is contained in:
parent
4e46f2f90e
commit
c3b974f6e0
@ -3157,11 +3157,11 @@
|
|||||||
09F664CF21EBCFB900AB7E26 /* WallpaperCropNode.swift */,
|
09F664CF21EBCFB900AB7E26 /* WallpaperCropNode.swift */,
|
||||||
09DD5D5121ED175300D7007A /* WallpaperColorPickerNode.swift */,
|
09DD5D5121ED175300D7007A /* WallpaperColorPickerNode.swift */,
|
||||||
0900678C21ED5EA800530762 /* WallpaperColorPanelNode.swift */,
|
0900678C21ED5EA800530762 /* WallpaperColorPanelNode.swift */,
|
||||||
|
0910B0F021FB3DE100F8F87D /* WallpaperPatternPanelNode.swift */,
|
||||||
091417F121EF4E5D00C8325A /* WallpaperGalleryController.swift */,
|
091417F121EF4E5D00C8325A /* WallpaperGalleryController.swift */,
|
||||||
09749BCC21F23139008FDDE9 /* WallpaperGalleryDecorationNode.swift */,
|
09749BCC21F23139008FDDE9 /* WallpaperGalleryDecorationNode.swift */,
|
||||||
091417F321EF4F5F00C8325A /* WallpaperGalleryItem.swift */,
|
091417F321EF4F5F00C8325A /* WallpaperGalleryItem.swift */,
|
||||||
D05174AA1EAA5B4700A1BF36 /* WallpaperGalleryToolbarNode.swift */,
|
D05174AA1EAA5B4700A1BF36 /* WallpaperGalleryToolbarNode.swift */,
|
||||||
0910B0F021FB3DE100F8F87D /* WallpaperPatternPanelNode.swift */,
|
|
||||||
);
|
);
|
||||||
name = Themes;
|
name = Themes;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
|||||||
@ -164,7 +164,7 @@ func serviceColor(with color: UIColor) -> UIColor {
|
|||||||
var brightness: CGFloat = 0.0
|
var brightness: CGFloat = 0.0
|
||||||
var alpha: CGFloat = 0.0
|
var alpha: CGFloat = 0.0
|
||||||
if color.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha) {
|
if color.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha) {
|
||||||
if saturation > 0.0 || brightness < 1.0 {
|
if saturation > 0.0 {
|
||||||
saturation = min(1.0, saturation + 0.05 + 0.1 * (1.0 - saturation))
|
saturation = min(1.0, saturation + 0.05 + 0.1 * (1.0 - saturation))
|
||||||
}
|
}
|
||||||
brightness = max(0.0, brightness * 0.65)
|
brightness = max(0.0, brightness * 0.65)
|
||||||
|
|||||||
@ -416,7 +416,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if case let .file(file, patternColor) = wallpaper.content {
|
if case let .file(file, _) = wallpaper.content {
|
||||||
updatedFetchControls = FetchControls(fetch: { manual in
|
updatedFetchControls = FetchControls(fetch: { manual in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.fetchDisposable.set(messageMediaFileInteractiveFetched(account: account, message: message, file: file, userInitiated: manual).start())
|
strongSelf.fetchDisposable.set(messageMediaFileInteractiveFetched(account: account, message: message, file: file, userInitiated: manual).start())
|
||||||
|
|||||||
@ -2740,76 +2740,6 @@ func playerAlbumArt(postbox: Postbox, fileReference: FileMediaReference?, albumA
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func photoWallpaper(postbox: Postbox, photoLibraryResource: PhotoLibraryMediaResource) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
|
|
||||||
let thumbnail = fetchPhotoLibraryImage(localIdentifier: photoLibraryResource.localIdentifier, thumbnail: true)
|
|
||||||
let fullSize = fetchPhotoLibraryImage(localIdentifier: photoLibraryResource.localIdentifier, thumbnail: false)
|
|
||||||
|
|
||||||
return (thumbnail |> then(fullSize))
|
|
||||||
|> map { result in
|
|
||||||
var sourceImage = result?.0
|
|
||||||
let isThumbnail = result?.1 ?? false
|
|
||||||
|
|
||||||
return { arguments in
|
|
||||||
let context = DrawingContext(size: arguments.drawingSize, scale: 1.0, clear: true)
|
|
||||||
|
|
||||||
let dimensions = sourceImage?.size
|
|
||||||
|
|
||||||
if let thumbnailImage = sourceImage?.cgImage, isThumbnail {
|
|
||||||
var fittedSize = arguments.imageSize
|
|
||||||
if abs(fittedSize.width - arguments.boundingSize.width).isLessThanOrEqualTo(CGFloat(1.0)) {
|
|
||||||
fittedSize.width = arguments.boundingSize.width
|
|
||||||
}
|
|
||||||
if abs(fittedSize.height - arguments.boundingSize.height).isLessThanOrEqualTo(CGFloat(1.0)) {
|
|
||||||
fittedSize.height = arguments.boundingSize.height
|
|
||||||
}
|
|
||||||
|
|
||||||
let thumbnailSize = CGSize(width: thumbnailImage.width, height: thumbnailImage.height)
|
|
||||||
|
|
||||||
let initialThumbnailContextFittingSize = fittedSize.fitted(CGSize(width: 100.0, height: 100.0))
|
|
||||||
|
|
||||||
let thumbnailContextSize = thumbnailSize.aspectFitted(initialThumbnailContextFittingSize)
|
|
||||||
let thumbnailContext = DrawingContext(size: thumbnailContextSize, scale: 1.0)
|
|
||||||
thumbnailContext.withFlippedContext { c in
|
|
||||||
c.interpolationQuality = .none
|
|
||||||
c.draw(thumbnailImage, in: CGRect(origin: CGPoint(), size: thumbnailContextSize))
|
|
||||||
}
|
|
||||||
telegramFastBlur(Int32(thumbnailContextSize.width), Int32(thumbnailContextSize.height), Int32(thumbnailContext.bytesPerRow), thumbnailContext.bytes)
|
|
||||||
|
|
||||||
var thumbnailContextFittingSize = CGSize(width: floor(arguments.drawingSize.width * 0.5), height: floor(arguments.drawingSize.width * 0.5))
|
|
||||||
if thumbnailContextFittingSize.width < 150.0 || thumbnailContextFittingSize.height < 150.0 {
|
|
||||||
thumbnailContextFittingSize = thumbnailContextFittingSize.aspectFilled(CGSize(width: 150.0, height: 150.0))
|
|
||||||
}
|
|
||||||
|
|
||||||
if thumbnailContextFittingSize.width > thumbnailContextSize.width {
|
|
||||||
let additionalContextSize = thumbnailContextFittingSize
|
|
||||||
let additionalBlurContext = DrawingContext(size: additionalContextSize, scale: 1.0)
|
|
||||||
additionalBlurContext.withFlippedContext { c in
|
|
||||||
c.interpolationQuality = .default
|
|
||||||
if let image = thumbnailContext.generateImage()?.cgImage {
|
|
||||||
c.draw(image, in: CGRect(origin: CGPoint(), size: additionalContextSize))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
telegramFastBlur(Int32(additionalContextSize.width), Int32(additionalContextSize.height), Int32(additionalBlurContext.bytesPerRow), additionalBlurContext.bytes)
|
|
||||||
sourceImage = additionalBlurContext.generateImage()
|
|
||||||
} else {
|
|
||||||
sourceImage = thumbnailContext.generateImage()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
context.withFlippedContext { c in
|
|
||||||
c.setBlendMode(.copy)
|
|
||||||
if let sourceImage = sourceImage, let cgImage = sourceImage.cgImage, let dimensions = dimensions {
|
|
||||||
let imageSize = dimensions.aspectFilled(arguments.drawingRect.size)
|
|
||||||
let fittedRect = CGRect(origin: CGPoint(x: floor((arguments.drawingRect.size.width - imageSize.width) / 2.0), y: floor((arguments.drawingRect.size.height - imageSize.height) / 2.0)), size: imageSize)
|
|
||||||
c.draw(cgImage, in: fittedRect)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return context
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func securePhoto(account: Account, resource: TelegramMediaResource, accessContext: SecureIdAccessContext) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
|
func securePhoto(account: Account, resource: TelegramMediaResource, accessContext: SecureIdAccessContext) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
|
||||||
return securePhotoInternal(account: account, resource: resource, accessContext: accessContext) |> map { $0.1 }
|
return securePhotoInternal(account: account, resource: resource, accessContext: accessContext) |> map { $0.1 }
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -180,7 +180,7 @@ public struct PresentationThemeSettings: PreferencesEntry {
|
|||||||
switch self.chatWallpaper {
|
switch self.chatWallpaper {
|
||||||
case let .image(representations, _):
|
case let .image(representations, _):
|
||||||
return representations.map { $0.resource.id }
|
return representations.map { $0.resource.id }
|
||||||
case let .file(_, _, _, _, _, _, file, _):
|
case let .file(_, _, _, _, _, _, _, file, _):
|
||||||
var resources: [MediaResourceId] = []
|
var resources: [MediaResourceId] = []
|
||||||
resources.append(file.resource.id)
|
resources.append(file.resource.id)
|
||||||
resources.append(contentsOf: file.previewRepresentations.map { $0.resource.id })
|
resources.append(contentsOf: file.previewRepresentations.map { $0.resource.id })
|
||||||
|
|||||||
Binary file not shown.
@ -45,6 +45,15 @@ final class SearchDisplayController {
|
|||||||
self?.searchBar.prefixString = prefix
|
self?.searchBar.prefixString = prefix
|
||||||
self?.searchBar.text = query
|
self?.searchBar.text = query
|
||||||
}
|
}
|
||||||
|
self.contentNode.setPlaceholder = { [weak self] string in
|
||||||
|
guard string != self?.searchBar.placeholderString?.string else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if let mutableAttributedString = self?.searchBar.placeholderString?.mutableCopy() as? NSMutableAttributedString {
|
||||||
|
mutableAttributedString.mutableString.setString(string)
|
||||||
|
self?.searchBar.placeholderString = mutableAttributedString
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.isSearchingDisposable = (contentNode.isSearching
|
self.isSearchingDisposable = (contentNode.isSearching
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] value in
|
|> deliverOnMainQueue).start(next: { [weak self] value in
|
||||||
|
|||||||
@ -7,6 +7,7 @@ class SearchDisplayControllerContentNode: ASDisplayNode {
|
|||||||
final var dismissInput: (() -> Void)?
|
final var dismissInput: (() -> Void)?
|
||||||
final var cancel: (() -> Void)?
|
final var cancel: (() -> Void)?
|
||||||
final var setQuery: ((NSAttributedString?, String) -> Void)?
|
final var setQuery: ((NSAttributedString?, String) -> Void)?
|
||||||
|
final var setPlaceholder: ((String) -> Void)?
|
||||||
|
|
||||||
var isSearching: Signal<Bool, NoError> {
|
var isSearching: Signal<Bool, NoError> {
|
||||||
return .single(false)
|
return .single(false)
|
||||||
|
|||||||
@ -246,6 +246,40 @@ final class ThemeGridController: ViewController {
|
|||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.shareWallpapers(wallpapers)
|
strongSelf.shareWallpapers(wallpapers)
|
||||||
}
|
}
|
||||||
|
}, resetWallpapers: { [weak self] in
|
||||||
|
if let strongSelf = self {
|
||||||
|
let actionSheet = ActionSheetController(presentationTheme: strongSelf.presentationData.theme)
|
||||||
|
let items: [ActionSheetItem] = [
|
||||||
|
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Wallpaper_ResetWallpapersConfirmation, color: .destructive, action: { [weak self, weak actionSheet] in
|
||||||
|
actionSheet?.dismissAnimated()
|
||||||
|
|
||||||
|
if let strongSelf = self {
|
||||||
|
strongSelf.scrollToTop?()
|
||||||
|
|
||||||
|
let controller = OverlayStatusController(theme: strongSelf.presentationData.theme, strings: strongSelf.presentationData.strings, type: .loading(cancelled: nil))
|
||||||
|
strongSelf.present(controller, in: .window(.root))
|
||||||
|
|
||||||
|
let _ = resetWallpapers(account: strongSelf.account).start(completed: { [weak self, weak controller] in
|
||||||
|
let _ = (telegramWallpapers(postbox: strongSelf.account.postbox, network: strongSelf.account.network)
|
||||||
|
|> deliverOnMainQueue).start(completed: { [weak self, weak controller] in
|
||||||
|
controller?.dismiss()
|
||||||
|
if let strongSelf = self {
|
||||||
|
strongSelf.controllerNode.updateWallpapers()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
]
|
||||||
|
actionSheet.setItemGroups([ActionSheetItemGroup(items: items),
|
||||||
|
ActionSheetItemGroup(items: [
|
||||||
|
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, action: { [weak actionSheet] in
|
||||||
|
actionSheet?.dismissAnimated()
|
||||||
|
})
|
||||||
|
])
|
||||||
|
])
|
||||||
|
strongSelf.present(actionSheet, in: .window(.root))
|
||||||
|
}
|
||||||
}, popViewController: { [weak self] in
|
}, popViewController: { [weak self] in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
let _ = (strongSelf.navigationController as? NavigationController)?.popViewController(animated: true)
|
let _ = (strongSelf.navigationController as? NavigationController)?.popViewController(animated: true)
|
||||||
@ -346,6 +380,17 @@ final class ThemeGridController: ViewController {
|
|||||||
|
|
||||||
let account = self.account
|
let account = self.account
|
||||||
let updateWallpaper: (TelegramWallpaper) -> Void = { [weak self] wallpaper in
|
let updateWallpaper: (TelegramWallpaper) -> Void = { [weak self] wallpaper in
|
||||||
|
var resource: MediaResource?
|
||||||
|
if case let .image(representations, _) = wallpaper, let representation = largestImageRepresentation(representations) {
|
||||||
|
resource = representation.resource
|
||||||
|
} else if case let .file(file) = wallpaper {
|
||||||
|
resource = file.file.resource
|
||||||
|
}
|
||||||
|
|
||||||
|
if let resource = resource {
|
||||||
|
let _ = account.postbox.mediaBox.cachedResourceRepresentation(resource, representation: CachedScaledImageRepresentation(size: CGSize(width: 720.0, height: 720.0), mode: .aspectFit), complete: true, fetch: true).start(completed: {})
|
||||||
|
}
|
||||||
|
|
||||||
let _ = (updatePresentationThemeSettingsInteractively(postbox: account.postbox, { current in
|
let _ = (updatePresentationThemeSettingsInteractively(postbox: account.postbox, { current in
|
||||||
var themeSpecificChatWallpapers = current.themeSpecificChatWallpapers
|
var themeSpecificChatWallpapers = current.themeSpecificChatWallpapers
|
||||||
themeSpecificChatWallpapers[current.theme.index] = wallpaper
|
themeSpecificChatWallpapers[current.theme.index] = wallpaper
|
||||||
@ -366,7 +411,7 @@ final class ThemeGridController: ViewController {
|
|||||||
|
|
||||||
let _ = uploadWallpaper(account: account, resource: resource).start(next: { status in
|
let _ = uploadWallpaper(account: account, resource: resource).start(next: { status in
|
||||||
if case let .complete(wallpaper) = status {
|
if case let .complete(wallpaper) = status {
|
||||||
if mode.contains(.blur), case let .file(_, _, _, _, _, _, file, _) = wallpaper {
|
if mode.contains(.blur), case let .file(_, _, _, _, _, _, _, file, _) = wallpaper {
|
||||||
let _ = account.postbox.mediaBox.cachedResourceRepresentation(file.resource, representation: CachedBlurredWallpaperRepresentation(), complete: true, fetch: true).start(completed: {
|
let _ = account.postbox.mediaBox.cachedResourceRepresentation(file.resource, representation: CachedBlurredWallpaperRepresentation(), complete: true, fetch: true).start(completed: {
|
||||||
updateWallpaper(wallpaper)
|
updateWallpaper(wallpaper)
|
||||||
})
|
})
|
||||||
@ -377,6 +422,7 @@ final class ThemeGridController: ViewController {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if mode.contains(.blur) {
|
if mode.contains(.blur) {
|
||||||
let _ = account.postbox.mediaBox.cachedResourceRepresentation(resource, representation: CachedBlurredWallpaperRepresentation(), complete: true, fetch: true).start(completed: {
|
let _ = account.postbox.mediaBox.cachedResourceRepresentation(resource, representation: CachedBlurredWallpaperRepresentation(), complete: true, fetch: true).start(completed: {
|
||||||
apply()
|
apply()
|
||||||
@ -395,7 +441,7 @@ final class ThemeGridController: ViewController {
|
|||||||
for wallpaper in wallpapers {
|
for wallpaper in wallpapers {
|
||||||
var item: String?
|
var item: String?
|
||||||
switch wallpaper {
|
switch wallpaper {
|
||||||
case let .file(_, _, _, _, isPattern, slug, _, settings):
|
case let .file(_, _, _, _, isPattern, _, slug, _, settings):
|
||||||
var options: [String] = []
|
var options: [String] = []
|
||||||
if isPattern {
|
if isPattern {
|
||||||
if let color = settings.color {
|
if let color = settings.color {
|
||||||
|
|||||||
@ -25,8 +25,8 @@ private func areWallpapersEqual(_ lhs: TelegramWallpaper, _ rhs: TelegramWallpap
|
|||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case let .file(_, _, _, _, _, lhsSlug, _, lhsSettings):
|
case let .file(_, _, _, _, _, _, lhsSlug, _, lhsSettings):
|
||||||
if case let .file(_, _, _, _, _, rhsSlug, _, rhsSettings) = rhs, lhsSlug == rhsSlug, lhsSettings.color == rhsSettings.color && lhsSettings.intensity == rhsSettings.intensity {
|
if case let .file(_, _, _, _, _, _, rhsSlug, _, rhsSettings) = rhs, lhsSlug == rhsSlug, lhsSettings.color == rhsSettings.color && lhsSettings.intensity == rhsSettings.intensity {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
@ -90,15 +90,15 @@ private struct ThemeGridControllerEntry: Comparable, Identifiable {
|
|||||||
case .builtin:
|
case .builtin:
|
||||||
return 0
|
return 0
|
||||||
case let .color(color):
|
case let .color(color):
|
||||||
return (Int64(0) << 32) | Int64(bitPattern: UInt64(UInt32(bitPattern: color)))
|
return (Int64(1) << 32) | Int64(bitPattern: UInt64(UInt32(bitPattern: color)))
|
||||||
case let .file(id, _, _, _, _, _, _, settings):
|
case let .file(id, _, _, _, _, _, _, _, settings):
|
||||||
var hash: Int = id.hashValue
|
var hash: Int = id.hashValue
|
||||||
hash = hash &* 31 &+ (settings.color?.hashValue ?? 0)
|
hash = hash &* 31 &+ (settings.color?.hashValue ?? 0)
|
||||||
hash = hash &* 31 &+ (settings.intensity?.hashValue ?? 0)
|
hash = hash &* 31 &+ (settings.intensity?.hashValue ?? 0)
|
||||||
return (Int64(1) << 32) | Int64(hash)
|
return (Int64(2) << 32) | Int64(hash)
|
||||||
case let .image(representations, _):
|
case let .image(representations, _):
|
||||||
if let largest = largestImageRepresentation(representations) {
|
if let largest = largestImageRepresentation(representations) {
|
||||||
return (Int64(2) << 32) | Int64(largest.resource.id.hashValue)
|
return (Int64(3) << 32) | Int64(largest.resource.id.hashValue)
|
||||||
} else {
|
} else {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@ -157,43 +157,6 @@ private func selectedWallpapers(entries: [ThemeGridControllerEntry]?, state: The
|
|||||||
return wallpapers
|
return wallpapers
|
||||||
}
|
}
|
||||||
|
|
||||||
private func isDarkWallpaper(_ wallpaper: TelegramWallpaper) -> Bool {
|
|
||||||
if case let .file(file) = wallpaper {
|
|
||||||
if let data = file.file.immediateThumbnailData {
|
|
||||||
let options = NSMutableDictionary()
|
|
||||||
options.setValue(1 as NSNumber, forKey: kCGImageSourceThumbnailMaxPixelSize as String)
|
|
||||||
options.setValue(true as NSNumber, forKey: kCGImageSourceCreateThumbnailFromImageAlways as String)
|
|
||||||
|
|
||||||
let thumbnailData = decodeTinyThumbnail(data: data)
|
|
||||||
if let thumbnailData = thumbnailData, let imageSource = CGImageSourceCreateWithData(thumbnailData as CFData, nil), let image = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options as CFDictionary) {
|
|
||||||
let pixelData = image.dataProvider!.data
|
|
||||||
let data: UnsafePointer<UInt8> = CFDataGetBytePtr(pixelData)
|
|
||||||
|
|
||||||
let point = CGPoint()
|
|
||||||
let pixelInfo: Int = ((Int(image.width) * Int(point.y)) + Int(point.x)) * 4
|
|
||||||
let r = CGFloat(data[pixelInfo+1]) / CGFloat(255.0)
|
|
||||||
let g = CGFloat(data[pixelInfo+2]) / CGFloat(255.0)
|
|
||||||
let b = CGFloat(data[pixelInfo+3]) / CGFloat(255.0)
|
|
||||||
|
|
||||||
let color = UIColor(red: r, green: g, blue: b, alpha: 1.0)
|
|
||||||
|
|
||||||
var hue: CGFloat = 0.0
|
|
||||||
var saturation: CGFloat = 0.0
|
|
||||||
var brightness: CGFloat = 0.0
|
|
||||||
var alpha: CGFloat = 0.0
|
|
||||||
if color.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha) {
|
|
||||||
if brightness > 0.5 {
|
|
||||||
return false
|
|
||||||
} else {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
final class ThemeGridControllerNode: ASDisplayNode {
|
final class ThemeGridControllerNode: ASDisplayNode {
|
||||||
private let account: Account
|
private let account: Account
|
||||||
private var presentationData: PresentationData
|
private var presentationData: PresentationData
|
||||||
@ -203,6 +166,8 @@ final class ThemeGridControllerNode: ASDisplayNode {
|
|||||||
private let presentGallery: () -> Void
|
private let presentGallery: () -> Void
|
||||||
private let presentColors: () -> Void
|
private let presentColors: () -> Void
|
||||||
private let emptyStateUpdated: (Bool) -> Void
|
private let emptyStateUpdated: (Bool) -> Void
|
||||||
|
private let resetWallpapers: () -> Void
|
||||||
|
|
||||||
var requestDeactivateSearch: (() -> Void)?
|
var requestDeactivateSearch: (() -> Void)?
|
||||||
|
|
||||||
let ready = ValuePromise<Bool>()
|
let ready = ValuePromise<Bool>()
|
||||||
@ -210,15 +175,19 @@ final class ThemeGridControllerNode: ASDisplayNode {
|
|||||||
|
|
||||||
private var backgroundNode: ASDisplayNode
|
private var backgroundNode: ASDisplayNode
|
||||||
private var separatorNode: ASDisplayNode
|
private var separatorNode: ASDisplayNode
|
||||||
|
private var bottomBackgroundNode: ASDisplayNode
|
||||||
|
private var bottomSeparatorNode: ASDisplayNode
|
||||||
|
|
||||||
private let colorItemNode: ItemListActionItemNode
|
private let colorItemNode: ItemListActionItemNode
|
||||||
private var colorItem: ItemListActionItem
|
private var colorItem: ItemListActionItem
|
||||||
|
|
||||||
private let galleryItemNode: ItemListActionItemNode
|
private let galleryItemNode: ItemListActionItemNode
|
||||||
private var galleryItem: ItemListActionItem
|
private var galleryItem: ItemListActionItem
|
||||||
|
|
||||||
private let descriptionItemNode: ItemListTextItemNode
|
private let descriptionItemNode: ItemListTextItemNode
|
||||||
private var descriptionItem: ItemListTextItem
|
private var descriptionItem: ItemListTextItem
|
||||||
|
private let resetItemNode: ItemListActionItemNode
|
||||||
|
private var resetItem: ItemListActionItem
|
||||||
|
private let resetDescriptionItemNode: ItemListTextItemNode
|
||||||
|
private var resetDescriptionItem: ItemListTextItem
|
||||||
|
|
||||||
private var selectionPanel: ThemeGridSelectionPanelNode?
|
private var selectionPanel: ThemeGridSelectionPanelNode?
|
||||||
private var selectionPanelSeparatorNode: ASDisplayNode?
|
private var selectionPanelSeparatorNode: ASDisplayNode?
|
||||||
@ -240,13 +209,14 @@ final class ThemeGridControllerNode: ASDisplayNode {
|
|||||||
|
|
||||||
private var disposable: Disposable?
|
private var disposable: Disposable?
|
||||||
|
|
||||||
init(account: Account, presentationData: PresentationData, presentPreviewController: @escaping (WallpaperListSource) -> Void, presentGallery: @escaping () -> Void, presentColors: @escaping () -> Void, emptyStateUpdated: @escaping (Bool) -> Void, deleteWallpapers: @escaping ([TelegramWallpaper], @escaping () -> Void) -> Void, shareWallpapers: @escaping ([TelegramWallpaper]) -> Void, popViewController: @escaping () -> Void) {
|
init(account: Account, presentationData: PresentationData, presentPreviewController: @escaping (WallpaperListSource) -> Void, presentGallery: @escaping () -> Void, presentColors: @escaping () -> Void, emptyStateUpdated: @escaping (Bool) -> Void, deleteWallpapers: @escaping ([TelegramWallpaper], @escaping () -> Void) -> Void, shareWallpapers: @escaping ([TelegramWallpaper]) -> Void, resetWallpapers: @escaping () -> Void, popViewController: @escaping () -> Void) {
|
||||||
self.account = account
|
self.account = account
|
||||||
self.presentationData = presentationData
|
self.presentationData = presentationData
|
||||||
self.presentPreviewController = presentPreviewController
|
self.presentPreviewController = presentPreviewController
|
||||||
self.presentGallery = presentGallery
|
self.presentGallery = presentGallery
|
||||||
self.presentColors = presentColors
|
self.presentColors = presentColors
|
||||||
self.emptyStateUpdated = emptyStateUpdated
|
self.emptyStateUpdated = emptyStateUpdated
|
||||||
|
self.resetWallpapers = resetWallpapers
|
||||||
|
|
||||||
self.gridNode = GridNode()
|
self.gridNode = GridNode()
|
||||||
self.gridNode.showVerticalScrollIndicator = true
|
self.gridNode.showVerticalScrollIndicator = true
|
||||||
@ -257,6 +227,12 @@ final class ThemeGridControllerNode: ASDisplayNode {
|
|||||||
self.separatorNode = ASDisplayNode()
|
self.separatorNode = ASDisplayNode()
|
||||||
self.separatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor
|
self.separatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor
|
||||||
|
|
||||||
|
self.bottomBackgroundNode = ASDisplayNode()
|
||||||
|
self.bottomBackgroundNode.backgroundColor = presentationData.theme.list.blocksBackgroundColor
|
||||||
|
|
||||||
|
self.bottomSeparatorNode = ASDisplayNode()
|
||||||
|
self.bottomSeparatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor
|
||||||
|
|
||||||
self.colorItemNode = ItemListActionItemNode()
|
self.colorItemNode = ItemListActionItemNode()
|
||||||
self.colorItem = ItemListActionItem(theme: presentationData.theme, title: presentationData.strings.Wallpaper_SetColor, kind: .generic, alignment: .natural, sectionId: 0, style: .blocks, action: {
|
self.colorItem = ItemListActionItem(theme: presentationData.theme, title: presentationData.strings.Wallpaper_SetColor, kind: .generic, alignment: .natural, sectionId: 0, style: .blocks, action: {
|
||||||
presentColors()
|
presentColors()
|
||||||
@ -267,6 +243,12 @@ final class ThemeGridControllerNode: ASDisplayNode {
|
|||||||
})
|
})
|
||||||
self.descriptionItemNode = ItemListTextItemNode()
|
self.descriptionItemNode = ItemListTextItemNode()
|
||||||
self.descriptionItem = ItemListTextItem(theme: presentationData.theme, text: .plain(presentationData.strings.Wallpaper_SetCustomBackgroundInfo), sectionId: 0)
|
self.descriptionItem = ItemListTextItem(theme: presentationData.theme, text: .plain(presentationData.strings.Wallpaper_SetCustomBackgroundInfo), sectionId: 0)
|
||||||
|
self.resetItemNode = ItemListActionItemNode()
|
||||||
|
self.resetItem = ItemListActionItem(theme: presentationData.theme, title: presentationData.strings.Wallpaper_ResetWallpapers, kind: .generic, alignment: .natural, sectionId: 0, style: .blocks, action: {
|
||||||
|
resetWallpapers()
|
||||||
|
})
|
||||||
|
self.resetDescriptionItemNode = ItemListTextItemNode()
|
||||||
|
self.resetDescriptionItem = ItemListTextItem(theme: presentationData.theme, text: .plain(presentationData.strings.Wallpaper_ResetWallpapersInfo), sectionId: 0)
|
||||||
|
|
||||||
self.currentState = ThemeGridControllerNodeState(editing: false, selectedIndices: Set())
|
self.currentState = ThemeGridControllerNodeState(editing: false, selectedIndices: Set())
|
||||||
self.statePromise = ValuePromise(self.currentState, ignoreRepeated: true)
|
self.statePromise = ValuePromise(self.currentState, ignoreRepeated: true)
|
||||||
@ -288,9 +270,13 @@ final class ThemeGridControllerNode: ASDisplayNode {
|
|||||||
|
|
||||||
self.gridNode.addSubnode(self.backgroundNode)
|
self.gridNode.addSubnode(self.backgroundNode)
|
||||||
self.gridNode.addSubnode(self.separatorNode)
|
self.gridNode.addSubnode(self.separatorNode)
|
||||||
|
self.gridNode.addSubnode(self.bottomBackgroundNode)
|
||||||
|
self.gridNode.addSubnode(self.bottomSeparatorNode)
|
||||||
self.gridNode.addSubnode(self.colorItemNode)
|
self.gridNode.addSubnode(self.colorItemNode)
|
||||||
self.gridNode.addSubnode(self.galleryItemNode)
|
self.gridNode.addSubnode(self.galleryItemNode)
|
||||||
self.gridNode.addSubnode(self.descriptionItemNode)
|
self.gridNode.addSubnode(self.descriptionItemNode)
|
||||||
|
self.gridNode.addSubnode(self.resetItemNode)
|
||||||
|
self.gridNode.addSubnode(self.resetDescriptionItemNode)
|
||||||
self.addSubnode(self.gridNode)
|
self.addSubnode(self.gridNode)
|
||||||
|
|
||||||
let previousEntries = Atomic<[ThemeGridControllerEntry]?>(value: nil)
|
let previousEntries = Atomic<[ThemeGridControllerEntry]?>(value: nil)
|
||||||
@ -357,7 +343,7 @@ final class ThemeGridControllerNode: ASDisplayNode {
|
|||||||
if presentationData.theme.overallDarkAppearance {
|
if presentationData.theme.overallDarkAppearance {
|
||||||
var darkWallpapers: [TelegramWallpaper] = []
|
var darkWallpapers: [TelegramWallpaper] = []
|
||||||
for wallpaper in wallpapers {
|
for wallpaper in wallpapers {
|
||||||
if isDarkWallpaper(wallpaper) {
|
if case let .file(file) = wallpaper, file.isDark {
|
||||||
darkWallpapers.append(wallpaper)
|
darkWallpapers.append(wallpaper)
|
||||||
} else {
|
} else {
|
||||||
sortedWallpapers.append(wallpaper)
|
sortedWallpapers.append(wallpaper)
|
||||||
@ -409,6 +395,8 @@ final class ThemeGridControllerNode: ASDisplayNode {
|
|||||||
highlightedNode = strongSelf.colorItemNode
|
highlightedNode = strongSelf.colorItemNode
|
||||||
} else if strongSelf.galleryItemNode.frame.contains(point) {
|
} else if strongSelf.galleryItemNode.frame.contains(point) {
|
||||||
highlightedNode = strongSelf.galleryItemNode
|
highlightedNode = strongSelf.galleryItemNode
|
||||||
|
} else if strongSelf.resetItemNode.frame.contains(point) {
|
||||||
|
highlightedNode = strongSelf.resetItemNode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -417,10 +405,31 @@ final class ThemeGridControllerNode: ASDisplayNode {
|
|||||||
} else {
|
} else {
|
||||||
strongSelf.colorItemNode.setHighlighted(false, at: CGPoint(), animated: true)
|
strongSelf.colorItemNode.setHighlighted(false, at: CGPoint(), animated: true)
|
||||||
strongSelf.galleryItemNode.setHighlighted(false, at: CGPoint(), animated: true)
|
strongSelf.galleryItemNode.setHighlighted(false, at: CGPoint(), animated: true)
|
||||||
|
strongSelf.resetItemNode.setHighlighted(false, at: CGPoint(), animated: true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.gridNode.view.addGestureRecognizer(tapRecognizer)
|
self.gridNode.view.addGestureRecognizer(tapRecognizer)
|
||||||
|
|
||||||
|
self.gridNode.presentationLayoutUpdated = { [weak self] gridLayout, transition in
|
||||||
|
if let strongSelf = self, let (layout, _) = strongSelf.validLayout {
|
||||||
|
transition.updateFrame(node: strongSelf.bottomBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: gridLayout.contentSize.height), size: CGSize(width: layout.size.width, height: 500.0)))
|
||||||
|
transition.updateFrame(node: strongSelf.bottomSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: gridLayout.contentSize.height), size: CGSize(width: layout.size.width, height: UIScreenPixel)))
|
||||||
|
|
||||||
|
let params = ListViewItemLayoutParams(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right)
|
||||||
|
|
||||||
|
let makeResetLayout = strongSelf.resetItemNode.asyncLayout()
|
||||||
|
let makeResetDescriptionLayout = strongSelf.resetDescriptionItemNode.asyncLayout()
|
||||||
|
let (resetLayout, resetApply) = makeResetLayout(strongSelf.resetItem, params, ItemListNeighbors(top: .none, bottom: .sameSection(alwaysPlain: true)))
|
||||||
|
let (resetDescriptionLayout, resetDescriptionApply) = makeResetDescriptionLayout(strongSelf.resetDescriptionItem, params, ItemListNeighbors(top: .none, bottom: .none))
|
||||||
|
|
||||||
|
resetApply()
|
||||||
|
resetDescriptionApply()
|
||||||
|
|
||||||
|
transition.updateFrame(node: strongSelf.resetItemNode, frame: CGRect(origin: CGPoint(x: 0.0, y: gridLayout.contentSize.height + 35.0), size: resetLayout.contentSize))
|
||||||
|
transition.updateFrame(node: strongSelf.resetDescriptionItemNode, frame: CGRect(origin: CGPoint(x: 0.0, y: gridLayout.contentSize.height + 35.0 + resetLayout.contentSize.height), size: resetDescriptionLayout.contentSize))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc private func tapAction(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) {
|
@objc private func tapAction(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) {
|
||||||
@ -433,6 +442,8 @@ final class ThemeGridControllerNode: ASDisplayNode {
|
|||||||
self.colorItem.action()
|
self.colorItem.action()
|
||||||
} else if self.galleryItemNode.frame.contains(location) {
|
} else if self.galleryItemNode.frame.contains(location) {
|
||||||
self.galleryItem.action()
|
self.galleryItem.action()
|
||||||
|
} else if self.resetItemNode.frame.contains(location) {
|
||||||
|
self.resetItem.action()
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
@ -460,6 +471,10 @@ final class ThemeGridControllerNode: ASDisplayNode {
|
|||||||
self?.presentGallery()
|
self?.presentGallery()
|
||||||
})
|
})
|
||||||
self.descriptionItem = ItemListTextItem(theme: presentationData.theme, text: .plain(presentationData.strings.Wallpaper_SetCustomBackgroundInfo), sectionId: 0)
|
self.descriptionItem = ItemListTextItem(theme: presentationData.theme, text: .plain(presentationData.strings.Wallpaper_SetCustomBackgroundInfo), sectionId: 0)
|
||||||
|
self.resetItem = ItemListActionItem(theme: presentationData.theme, title: presentationData.strings.Wallpaper_ResetWallpapers, kind: .generic, alignment: .natural, sectionId: 0, style: .blocks, action: { [weak self] in
|
||||||
|
self?.resetWallpapers()
|
||||||
|
})
|
||||||
|
self.resetDescriptionItem = ItemListTextItem(theme: presentationData.theme, text: .plain(presentationData.strings.Wallpaper_ResetWallpapersInfo), sectionId: 0)
|
||||||
|
|
||||||
if let (layout, navigationBarHeight) = self.validLayout {
|
if let (layout, navigationBarHeight) = self.validLayout {
|
||||||
self.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate)
|
self.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate)
|
||||||
@ -519,7 +534,7 @@ final class ThemeGridControllerNode: ASDisplayNode {
|
|||||||
insets.top += navigationBarHeight
|
insets.top += navigationBarHeight
|
||||||
insets.left = layout.safeInsets.left
|
insets.left = layout.safeInsets.left
|
||||||
insets.right = layout.safeInsets.right
|
insets.right = layout.safeInsets.right
|
||||||
let scrollIndicatorInsets = insets
|
var scrollIndicatorInsets = insets
|
||||||
|
|
||||||
let minSpacing: CGFloat = 8.0
|
let minSpacing: CGFloat = 8.0
|
||||||
let referenceImageSize: CGSize
|
let referenceImageSize: CGSize
|
||||||
@ -563,9 +578,10 @@ final class ThemeGridControllerNode: ASDisplayNode {
|
|||||||
insets.top += spacing + buttonInset
|
insets.top += spacing + buttonInset
|
||||||
|
|
||||||
if self.currentState.editing {
|
if self.currentState.editing {
|
||||||
|
let panelHeight: CGFloat
|
||||||
if let selectionPanel = self.selectionPanel {
|
if let selectionPanel = self.selectionPanel {
|
||||||
selectionPanel.selectedIndices = self.currentState.selectedIndices
|
selectionPanel.selectedIndices = self.currentState.selectedIndices
|
||||||
let panelHeight = selectionPanel.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, maxHeight: 0.0, transition: transition, metrics: layout.metrics)
|
panelHeight = selectionPanel.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, maxHeight: 0.0, transition: transition, metrics: layout.metrics)
|
||||||
transition.updateFrame(node: selectionPanel, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - insets.bottom - panelHeight), size: CGSize(width: layout.size.width, height: panelHeight)))
|
transition.updateFrame(node: selectionPanel, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - insets.bottom - panelHeight), size: CGSize(width: layout.size.width, height: panelHeight)))
|
||||||
if let selectionPanelSeparatorNode = self.selectionPanelSeparatorNode {
|
if let selectionPanelSeparatorNode = self.selectionPanelSeparatorNode {
|
||||||
transition.updateFrame(node: selectionPanelSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - insets.bottom - panelHeight), size: CGSize(width: layout.size.width, height: UIScreenPixel)))
|
transition.updateFrame(node: selectionPanelSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - insets.bottom - panelHeight), size: CGSize(width: layout.size.width, height: UIScreenPixel)))
|
||||||
@ -584,7 +600,7 @@ final class ThemeGridControllerNode: ASDisplayNode {
|
|||||||
selectionPanel.backgroundColor = self.presentationData.theme.chat.inputPanel.panelBackgroundColor
|
selectionPanel.backgroundColor = self.presentationData.theme.chat.inputPanel.panelBackgroundColor
|
||||||
selectionPanel.controllerInteraction = self.controllerInteraction
|
selectionPanel.controllerInteraction = self.controllerInteraction
|
||||||
selectionPanel.selectedIndices = self.currentState.selectedIndices
|
selectionPanel.selectedIndices = self.currentState.selectedIndices
|
||||||
let panelHeight = selectionPanel.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, maxHeight: 0.0, transition: .immediate, metrics: layout.metrics)
|
panelHeight = selectionPanel.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, maxHeight: 0.0, transition: .immediate, metrics: layout.metrics)
|
||||||
self.selectionPanel = selectionPanel
|
self.selectionPanel = selectionPanel
|
||||||
self.addSubnode(selectionPanel)
|
self.addSubnode(selectionPanel)
|
||||||
|
|
||||||
@ -601,6 +617,9 @@ final class ThemeGridControllerNode: ASDisplayNode {
|
|||||||
transition.updateFrame(node: selectionPanelBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - insets.bottom - panelHeight), size: CGSize(width: layout.size.width, height: insets.bottom + panelHeight)))
|
transition.updateFrame(node: selectionPanelBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - insets.bottom - panelHeight), size: CGSize(width: layout.size.width, height: insets.bottom + panelHeight)))
|
||||||
transition.updateFrame(node: selectionPanelSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - insets.bottom - panelHeight), size: CGSize(width: layout.size.width, height: UIScreenPixel)))
|
transition.updateFrame(node: selectionPanelSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - insets.bottom - panelHeight), size: CGSize(width: layout.size.width, height: UIScreenPixel)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
insets.bottom += panelHeight
|
||||||
|
scrollIndicatorInsets.bottom += panelHeight
|
||||||
} else if let selectionPanel = self.selectionPanel {
|
} else if let selectionPanel = self.selectionPanel {
|
||||||
self.selectionPanel = nil
|
self.selectionPanel = nil
|
||||||
transition.updateFrame(node: selectionPanel, frame: selectionPanel.frame.offsetBy(dx: 0.0, dy: selectionPanel.bounds.size.height + insets.bottom), completion: { [weak selectionPanel] _ in
|
transition.updateFrame(node: selectionPanel, frame: selectionPanel.frame.offsetBy(dx: 0.0, dy: selectionPanel.bounds.size.height + insets.bottom), completion: { [weak selectionPanel] _ in
|
||||||
@ -618,10 +637,13 @@ final class ThemeGridControllerNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let makeResetDescriptionLayout = self.resetDescriptionItemNode.asyncLayout()
|
||||||
|
let (resetDescriptionLayout, _) = makeResetDescriptionLayout(self.resetDescriptionItem, params, ItemListNeighbors(top: .none, bottom: .none))
|
||||||
|
insets.bottom += buttonHeight + 35.0 + resetDescriptionLayout.contentSize.height + 32.0
|
||||||
|
|
||||||
self.gridNode.frame = CGRect(x: 0.0, y: 0.0, width: layout.size.width, height: layout.size.height)
|
self.gridNode.frame = CGRect(x: 0.0, y: 0.0, width: layout.size.width, height: layout.size.height)
|
||||||
self.gridNode.transaction(GridNodeTransaction(deleteItems: [], insertItems: [], updateItems: [], scrollToItem: nil, updateLayout: GridNodeUpdateLayout(layout: GridNodeLayout(size: layout.size, insets: insets, scrollIndicatorInsets: scrollIndicatorInsets, preloadSize: 300.0, type: .fixed(itemSize: imageSize, fillWidth: nil, lineSpacing: spacing, itemSpacing: nil)), transition: transition), itemTransition: .immediate, stationaryItems: .none, updateFirstIndexInSectionOffset: nil), completion: { _ in })
|
self.gridNode.transaction(GridNodeTransaction(deleteItems: [], insertItems: [], updateItems: [], scrollToItem: nil, updateLayout: GridNodeUpdateLayout(layout: GridNodeLayout(size: layout.size, insets: insets, scrollIndicatorInsets: scrollIndicatorInsets, preloadSize: 300.0, type: .fixed(itemSize: imageSize, fillWidth: nil, lineSpacing: spacing, itemSpacing: nil)), transition: transition), itemTransition: .immediate, stationaryItems: .none, updateFirstIndexInSectionOffset: nil), completion: { _ in })
|
||||||
|
|
||||||
|
|
||||||
if !hadValidLayout {
|
if !hadValidLayout {
|
||||||
self.dequeueTransitions()
|
self.dequeueTransitions()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -345,7 +345,6 @@ final class ThemeGridSearchContentNode: SearchDisplayControllerContentNode {
|
|||||||
self.recentListNode.verticalScrollIndicatorColor = self.presentationData.theme.list.scrollIndicatorColor
|
self.recentListNode.verticalScrollIndicatorColor = self.presentationData.theme.list.scrollIndicatorColor
|
||||||
self.gridNode = GridNode()
|
self.gridNode = GridNode()
|
||||||
|
|
||||||
|
|
||||||
self.emptyResultsTitleNode = ImmediateTextNode()
|
self.emptyResultsTitleNode = ImmediateTextNode()
|
||||||
self.emptyResultsTitleNode.attributedText = NSAttributedString(string: self.presentationData.strings.SharedMedia_SearchNoResults, font: Font.semibold(17.0), textColor: self.presentationData.theme.list.freeTextColor)
|
self.emptyResultsTitleNode.attributedText = NSAttributedString(string: self.presentationData.strings.SharedMedia_SearchNoResults, font: Font.semibold(17.0), textColor: self.presentationData.theme.list.freeTextColor)
|
||||||
self.emptyResultsTitleNode.textAlignment = .center
|
self.emptyResultsTitleNode.textAlignment = .center
|
||||||
@ -589,18 +588,22 @@ final class ThemeGridSearchContentNode: SearchDisplayControllerContentNode {
|
|||||||
if updateInterface {
|
if updateInterface {
|
||||||
let prefix: NSAttributedString?
|
let prefix: NSAttributedString?
|
||||||
let text: String
|
let text: String
|
||||||
|
let placeholder: String
|
||||||
switch query {
|
switch query {
|
||||||
case let .generic(query):
|
case let .generic(query):
|
||||||
prefix = nil
|
prefix = nil
|
||||||
text = query
|
text = query
|
||||||
|
placeholder = self.presentationData.strings.Wallpaper_Search
|
||||||
case let .color(color, query):
|
case let .color(color, query):
|
||||||
let prefixString = NSMutableAttributedString()
|
let prefixString = NSMutableAttributedString()
|
||||||
prefixString.append(NSAttributedString(string: self.presentationData.strings.WallpaperSearch_ColorPrefix, font: Font.regular(17.0), textColor: self.presentationData.theme.rootController.activeNavigationSearchBar.inputTextColor))
|
prefixString.append(NSAttributedString(string: self.presentationData.strings.WallpaperSearch_ColorPrefix, font: Font.regular(17.0), textColor: self.presentationData.theme.rootController.activeNavigationSearchBar.inputTextColor))
|
||||||
prefixString.append(NSAttributedString(string: "\(color.localizedString(strings: self.presentationData.strings)) ", font: Font.regular(17.0), textColor: self.presentationData.theme.rootController.activeNavigationSearchBar.accentColor))
|
prefixString.append(NSAttributedString(string: "\(color.localizedString(strings: self.presentationData.strings)) ", font: Font.regular(17.0), textColor: self.presentationData.theme.rootController.activeNavigationSearchBar.accentColor))
|
||||||
prefix = prefixString
|
prefix = prefixString
|
||||||
text = query
|
text = query
|
||||||
|
placeholder = self.presentationData.strings.Wallpaper_SearchShort
|
||||||
}
|
}
|
||||||
self.setQuery?(prefix, text)
|
self.setQuery?(prefix, text)
|
||||||
|
self.setPlaceholder?(placeholder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,12 +24,12 @@ final class ThrottledValue<T: Equatable> {
|
|||||||
guard self.value != value else {
|
guard self.value != value else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
self.timer?.invalidate()
|
||||||
let timestamp = CACurrentMediaTime()
|
let timestamp = CACurrentMediaTime()
|
||||||
if timestamp > self.previousSetTimestamp + self.interval {
|
if timestamp > self.previousSetTimestamp + self.interval {
|
||||||
self.previousSetTimestamp = timestamp
|
self.previousSetTimestamp = timestamp
|
||||||
self.valuePromise.set(value)
|
self.valuePromise.set(value)
|
||||||
} else {
|
} else {
|
||||||
self.timer?.invalidate()
|
|
||||||
let timer = SwiftSignalKit.Timer(timeout: self.interval, repeat: false, completion: { [weak self] in
|
let timer = SwiftSignalKit.Timer(timeout: self.interval, repeat: false, completion: { [weak self] in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.valuePromise.set(strongSelf.value)
|
strongSelf.valuePromise.set(strongSelf.value)
|
||||||
|
|||||||
@ -51,21 +51,8 @@ final class WallpaperColorPanelNode: ASDisplayNode, UITextFieldDelegate {
|
|||||||
self.setColor(newValue)
|
self.setColor(newValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var intensity: Int32 {
|
|
||||||
get {
|
|
||||||
return self.colorPickerNode.intensity
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
self.colorPickerNode.intensity = newValue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var colorChanged: ((UIColor, Int32?, Bool) -> Void)?
|
|
||||||
|
|
||||||
var adjustingPattern: Bool = false {
|
var colorChanged: ((UIColor, Bool) -> Void)?
|
||||||
didSet {
|
|
||||||
self.colorPickerNode.adjustingPattern = self.adjustingPattern
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
init(theme: PresentationTheme, strings: PresentationStrings) {
|
init(theme: PresentationTheme, strings: PresentationStrings) {
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
@ -110,16 +97,6 @@ final class WallpaperColorPanelNode: ASDisplayNode, UITextFieldDelegate {
|
|||||||
self.colorPickerNode.colorChangeEnded = { [weak self] color in
|
self.colorPickerNode.colorChangeEnded = { [weak self] color in
|
||||||
self?.setColor(color, updatePicker: false, ended: true)
|
self?.setColor(color, updatePicker: false, ended: true)
|
||||||
}
|
}
|
||||||
self.colorPickerNode.intensityChanged = { [weak self] value in
|
|
||||||
if let strongSelf = self {
|
|
||||||
strongSelf.colorChanged?(strongSelf.color, value, false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.colorPickerNode.intensityChangeEnded = { [weak self] value in
|
|
||||||
if let strongSelf = self {
|
|
||||||
strongSelf.colorChanged?(strongSelf.color, value, true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override func didLoad() {
|
override func didLoad() {
|
||||||
@ -142,7 +119,7 @@ final class WallpaperColorPanelNode: ASDisplayNode, UITextFieldDelegate {
|
|||||||
if updatePicker {
|
if updatePicker {
|
||||||
self.colorPickerNode.color = color
|
self.colorPickerNode.color = color
|
||||||
}
|
}
|
||||||
self.colorChanged?(color, self.intensity, ended)
|
self.colorChanged?(color, ended)
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateLayout(size: CGSize, keyboardHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
func updateLayout(size: CGSize, keyboardHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||||
|
|||||||
@ -15,18 +15,6 @@ private let shadowImage: UIImage = {
|
|||||||
})!
|
})!
|
||||||
}()
|
}()
|
||||||
|
|
||||||
private let smallShadowImage: UIImage = {
|
|
||||||
return generateImage(CGSize(width: 24.0, height: 24.0), opaque: false, scale: nil, rotatedContext: { size, context in
|
|
||||||
context.setBlendMode(.clear)
|
|
||||||
context.setFillColor(UIColor.clear.cgColor)
|
|
||||||
context.fill(CGRect(origin: CGPoint(), size: size))
|
|
||||||
context.setBlendMode(.normal)
|
|
||||||
context.setShadow(offset: CGSize(width: 0.0, height: 1.5), blur: 4.5, color: UIColor(rgb: 0x000000, alpha: 0.65).cgColor)
|
|
||||||
context.setFillColor(UIColor(rgb: 0x000000, alpha: 0.5).cgColor)
|
|
||||||
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: 3.0 + UIScreenPixel, dy: 3.0 + UIScreenPixel))
|
|
||||||
})!
|
|
||||||
}()
|
|
||||||
|
|
||||||
private let pointerImage: UIImage = {
|
private let pointerImage: UIImage = {
|
||||||
return generateImage(CGSize(width: 12.0, height: 42.0), opaque: false, scale: nil, rotatedContext: { size, context in
|
return generateImage(CGSize(width: 12.0, height: 42.0), opaque: false, scale: nil, rotatedContext: { size, context in
|
||||||
context.setBlendMode(.clear)
|
context.setBlendMode(.clear)
|
||||||
@ -68,19 +56,6 @@ private final class HSVParameter: NSObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class IntensitySliderParameter: NSObject {
|
|
||||||
let bordered: Bool
|
|
||||||
let min: HSVParameter
|
|
||||||
let max: HSVParameter
|
|
||||||
|
|
||||||
init(bordered: Bool, min: HSVParameter, max: HSVParameter) {
|
|
||||||
self.bordered = bordered
|
|
||||||
self.min = min
|
|
||||||
self.max = max
|
|
||||||
super.init()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final class WallpaperColorKnobNode: ASDisplayNode {
|
private final class WallpaperColorKnobNode: ASDisplayNode {
|
||||||
var hsv: (CGFloat, CGFloat, CGFloat) = (0.0, 0.0, 1.0) {
|
var hsv: (CGFloat, CGFloat, CGFloat) = (0.0, 0.0, 1.0) {
|
||||||
didSet {
|
didSet {
|
||||||
@ -114,8 +89,7 @@ private final class WallpaperColorKnobNode: ASDisplayNode {
|
|||||||
context.fill(bounds)
|
context.fill(bounds)
|
||||||
}
|
}
|
||||||
|
|
||||||
let image = bounds.width > 30.0 ? shadowImage : smallShadowImage
|
context.draw(shadowImage.cgImage!, in: bounds)
|
||||||
context.draw(image.cgImage!, in: bounds)
|
|
||||||
|
|
||||||
context.setBlendMode(.normal)
|
context.setBlendMode(.normal)
|
||||||
context.setFillColor(UIColor.white.cgColor)
|
context.setFillColor(UIColor.white.cgColor)
|
||||||
@ -214,176 +188,9 @@ private final class WallpaperColorBrightnessNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final class WallpaperIntensitySliderNode: ASDisplayNode {
|
|
||||||
private let bordered: Bool
|
|
||||||
var extrema: ((CGFloat, CGFloat, CGFloat), (CGFloat, CGFloat, CGFloat)) = ((0.0, 1.0, 0.0), (0.0, 1.0, 1.0)) {
|
|
||||||
didSet {
|
|
||||||
self.setNeedsDisplay()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
init(bordered: Bool) {
|
|
||||||
self.bordered = bordered
|
|
||||||
|
|
||||||
super.init()
|
|
||||||
|
|
||||||
self.isOpaque = bordered
|
|
||||||
self.displaysAsynchronously = false
|
|
||||||
}
|
|
||||||
|
|
||||||
override func drawParameters(forAsyncLayer layer: _ASDisplayLayer) -> NSObjectProtocol? {
|
|
||||||
return IntensitySliderParameter(bordered: self.bordered, min: HSVParameter(hue: self.extrema.0.0, saturation: self.extrema.0.1, value: self.extrema.0.2), max: HSVParameter(hue: self.extrema.1.0, saturation: self.extrema.1.1, value: self.extrema.1.2))
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc override class func draw(_ bounds: CGRect, withParameters parameters: Any?, isCancelled: () -> Bool, isRasterizing: Bool) {
|
|
||||||
guard let parameters = parameters as? IntensitySliderParameter else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
let context = UIGraphicsGetCurrentContext()!
|
|
||||||
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
|
||||||
|
|
||||||
if parameters.bordered {
|
|
||||||
context.setFillColor(UIColor(white: parameters.min.value, alpha: 1.0).cgColor)
|
|
||||||
context.fill(bounds)
|
|
||||||
|
|
||||||
let path = UIBezierPath(roundedRect: bounds, cornerRadius: bounds.height / 2.0)
|
|
||||||
context.addPath(path.cgPath)
|
|
||||||
context.setFillColor(UIColor.white.cgColor)
|
|
||||||
context.fillPath()
|
|
||||||
} else if !isRasterizing {
|
|
||||||
context.setBlendMode(.copy)
|
|
||||||
context.setFillColor(UIColor.clear.cgColor)
|
|
||||||
context.fill(bounds)
|
|
||||||
context.setBlendMode(.normal)
|
|
||||||
}
|
|
||||||
|
|
||||||
let innerPath = UIBezierPath(roundedRect: bounds.insetBy(dx: 1.0, dy: 1.0), cornerRadius: bounds.height / 2.0)
|
|
||||||
context.addPath(innerPath.cgPath)
|
|
||||||
context.clip()
|
|
||||||
|
|
||||||
let minColor = UIColor(hue: parameters.min.hue, saturation: parameters.min.saturation, brightness: parameters.min.value, alpha: 1.0)
|
|
||||||
let maxColor = UIColor(hue: parameters.max.hue, saturation: parameters.max.saturation, brightness: parameters.max.value, alpha: 1.0)
|
|
||||||
let colors = [minColor.cgColor, maxColor.cgColor]
|
|
||||||
var locations: [CGFloat] = [0.0, 1.0]
|
|
||||||
let gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: &locations)!
|
|
||||||
context.drawLinearGradient(gradient, start: CGPoint(), end: CGPoint(x: bounds.width, y: 0.0), options: CGGradientDrawingOptions())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final class WallpaperIntensityPickerNode: ASDisplayNode {
|
|
||||||
private let labelNode: ASTextNode
|
|
||||||
private let sliderNode: WallpaperIntensitySliderNode
|
|
||||||
private let knobNode: WallpaperColorKnobNode
|
|
||||||
|
|
||||||
var valueChanged: ((CGFloat) -> Void)?
|
|
||||||
var valueChangeEnded: ((CGFloat) -> Void)?
|
|
||||||
|
|
||||||
var value: CGFloat = 0.0 {
|
|
||||||
didSet {
|
|
||||||
self.setNeedsLayout()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var intensity: Int32 {
|
|
||||||
return Int32(self.value * 100.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
private var bordered: Bool
|
|
||||||
|
|
||||||
init(theme: PresentationTheme?, title: String, bordered: Bool) {
|
|
||||||
self.bordered = bordered
|
|
||||||
self.labelNode = ASTextNode()
|
|
||||||
var color: UIColor = .black
|
|
||||||
if let theme = theme {
|
|
||||||
color = theme.rootController.navigationBar.primaryTextColor
|
|
||||||
}
|
|
||||||
self.labelNode.attributedText = NSAttributedString(string: title, font: Font.regular(14.0), textColor: color)
|
|
||||||
self.sliderNode = WallpaperIntensitySliderNode(bordered: bordered)
|
|
||||||
self.sliderNode.hitTestSlop = UIEdgeInsetsMake(-16.0, -16.0, -16.0, -16.0)
|
|
||||||
self.knobNode = WallpaperColorKnobNode()
|
|
||||||
|
|
||||||
super.init()
|
|
||||||
|
|
||||||
self.addSubnode(self.labelNode)
|
|
||||||
self.addSubnode(self.sliderNode)
|
|
||||||
self.addSubnode(self.knobNode)
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateExtrema(min: (CGFloat, CGFloat, CGFloat), max: (CGFloat, CGFloat, CGFloat)) {
|
|
||||||
self.sliderNode.extrema = (min, max)
|
|
||||||
self.update()
|
|
||||||
}
|
|
||||||
|
|
||||||
private func update() {
|
|
||||||
let extrema = self.sliderNode.extrema
|
|
||||||
let hsv = (extrema.0.0 + (extrema.1.0 - extrema.0.0) * self.value, extrema.0.1 + (extrema.1.1 - extrema.0.1) * self.value, extrema.0.2 + (extrema.1.2 - extrema.0.2) * self.value)
|
|
||||||
self.knobNode.hsv = hsv
|
|
||||||
}
|
|
||||||
|
|
||||||
override func didLoad() {
|
|
||||||
super.didLoad()
|
|
||||||
|
|
||||||
let panRecognizer = UIPanGestureRecognizer(target: self, action: #selector(WallpaperIntensityPickerNode.pan))
|
|
||||||
self.sliderNode.view.addGestureRecognizer(panRecognizer)
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc private func pan(_ recognizer: UIPanGestureRecognizer) {
|
|
||||||
let size = self.bounds.size
|
|
||||||
|
|
||||||
let previousValue = self.value
|
|
||||||
|
|
||||||
let transition = recognizer.translation(in: recognizer.view)
|
|
||||||
let width: CGFloat = size.width - 5.0 * 2.0
|
|
||||||
let newValue = max(0.0, min(1.0, self.value + transition.x / width))
|
|
||||||
self.value = newValue
|
|
||||||
|
|
||||||
var ended = false
|
|
||||||
switch recognizer.state {
|
|
||||||
case .changed:
|
|
||||||
self.updateKnobLayout(size: size)
|
|
||||||
recognizer.setTranslation(CGPoint(), in: recognizer.view)
|
|
||||||
case .ended:
|
|
||||||
self.updateKnobLayout(size: size)
|
|
||||||
ended = true
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.value != previousValue || ended {
|
|
||||||
if ended {
|
|
||||||
self.valueChangeEnded?(self.value)
|
|
||||||
} else {
|
|
||||||
self.valueChanged?(self.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateKnobLayout(size: CGSize) {
|
|
||||||
let knobSize = CGSize(width: 24.0, height: 24.0)
|
|
||||||
|
|
||||||
let inset: CGFloat = 5.0
|
|
||||||
let knobFrame = CGRect(x: inset - knobSize.width / 2.0 + (size.width - inset * 2.0) * self.value, y: 17.0, width: knobSize.width, height: knobSize.height)
|
|
||||||
self.knobNode.frame = knobFrame
|
|
||||||
self.update()
|
|
||||||
}
|
|
||||||
|
|
||||||
override func layout() {
|
|
||||||
super.layout()
|
|
||||||
|
|
||||||
let labelSize = self.labelNode.measure(self.bounds.size)
|
|
||||||
self.labelNode.frame = CGRect(origin: CGPoint(), size: labelSize)
|
|
||||||
|
|
||||||
self.sliderNode.frame = CGRect(x: 0.0, y: 27.0, width: self.bounds.width, height: 4.0)
|
|
||||||
self.updateKnobLayout(size: self.bounds.size)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final class WallpaperColorPickerNode: ASDisplayNode {
|
final class WallpaperColorPickerNode: ASDisplayNode {
|
||||||
private let brightnessNode: WallpaperColorBrightnessNode
|
private let brightnessNode: WallpaperColorBrightnessNode
|
||||||
private let brightnessKnobNode: ASImageNode
|
private let brightnessKnobNode: ASImageNode
|
||||||
|
|
||||||
private let intensityNode: WallpaperIntensityPickerNode
|
|
||||||
|
|
||||||
private let colorNode: WallpaperColorHueSaturationNode
|
private let colorNode: WallpaperColorHueSaturationNode
|
||||||
private let colorKnobNode: WallpaperColorKnobNode
|
private let colorKnobNode: WallpaperColorKnobNode
|
||||||
|
|
||||||
@ -415,27 +222,6 @@ final class WallpaperColorPickerNode: ASDisplayNode {
|
|||||||
var colorChanged: ((UIColor) -> Void)?
|
var colorChanged: ((UIColor) -> Void)?
|
||||||
var colorChangeEnded: ((UIColor) -> Void)?
|
var colorChangeEnded: ((UIColor) -> Void)?
|
||||||
|
|
||||||
var intensity: Int32 {
|
|
||||||
get {
|
|
||||||
return self.intensityNode.intensity
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
self.intensityNode.value = CGFloat(newValue) / 100.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var intensityChanged: ((Int32) -> Void)?
|
|
||||||
var intensityChangeEnded: ((Int32) -> Void)?
|
|
||||||
|
|
||||||
var adjustingPattern: Bool = false {
|
|
||||||
didSet {
|
|
||||||
let value = self.adjustingPattern
|
|
||||||
self.brightnessNode.isHidden = value
|
|
||||||
self.brightnessKnobNode.isHidden = value
|
|
||||||
self.intensityNode.isHidden = !value
|
|
||||||
self.setNeedsLayout()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
init(strings: PresentationStrings) {
|
init(strings: PresentationStrings) {
|
||||||
self.brightnessNode = WallpaperColorBrightnessNode()
|
self.brightnessNode = WallpaperColorBrightnessNode()
|
||||||
self.brightnessNode.hitTestSlop = UIEdgeInsetsMake(-16.0, -16.0, -16.0, -16.0)
|
self.brightnessNode.hitTestSlop = UIEdgeInsetsMake(-16.0, -16.0, -16.0, -16.0)
|
||||||
@ -445,10 +231,6 @@ final class WallpaperColorPickerNode: ASDisplayNode {
|
|||||||
self.colorNode.hitTestSlop = UIEdgeInsetsMake(-16.0, -16.0, -16.0, -16.0)
|
self.colorNode.hitTestSlop = UIEdgeInsetsMake(-16.0, -16.0, -16.0, -16.0)
|
||||||
self.colorKnobNode = WallpaperColorKnobNode()
|
self.colorKnobNode = WallpaperColorKnobNode()
|
||||||
|
|
||||||
|
|
||||||
self.intensityNode = WallpaperIntensityPickerNode(theme: nil, title: strings.WallpaperPreview_PatternIntensity, bordered: true)
|
|
||||||
self.intensityNode.isHidden = true
|
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
self.backgroundColor = .white
|
self.backgroundColor = .white
|
||||||
@ -457,35 +239,6 @@ final class WallpaperColorPickerNode: ASDisplayNode {
|
|||||||
self.addSubnode(self.brightnessKnobNode)
|
self.addSubnode(self.brightnessKnobNode)
|
||||||
self.addSubnode(self.colorNode)
|
self.addSubnode(self.colorNode)
|
||||||
self.addSubnode(self.colorKnobNode)
|
self.addSubnode(self.colorKnobNode)
|
||||||
self.addSubnode(self.intensityNode)
|
|
||||||
|
|
||||||
let valueChanged: (CGFloat, Bool) -> Void = { [weak self] value, ended in
|
|
||||||
if let strongSelf = self {
|
|
||||||
let previousColor = strongSelf.color
|
|
||||||
strongSelf.colorHSV.2 = 1.0 - value
|
|
||||||
|
|
||||||
if strongSelf.color != previousColor || ended {
|
|
||||||
strongSelf.update()
|
|
||||||
if ended {
|
|
||||||
strongSelf.colorChangeEnded?(strongSelf.color)
|
|
||||||
} else {
|
|
||||||
strongSelf.colorChanged?(strongSelf.color)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.intensityNode.valueChanged = { [weak self] value in
|
|
||||||
if let strongSelf = self {
|
|
||||||
strongSelf.intensityChanged?(Int32(value * 100.0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.intensityNode.valueChangeEnded = { [weak self] value in
|
|
||||||
if let strongSelf = self {
|
|
||||||
strongSelf.intensityChangeEnded?(Int32(value * 100.0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.update()
|
self.update()
|
||||||
}
|
}
|
||||||
@ -504,24 +257,16 @@ final class WallpaperColorPickerNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func update() {
|
private func update() {
|
||||||
if self.adjustingPattern {
|
|
||||||
self.backgroundColor = .white
|
|
||||||
} else {
|
|
||||||
self.backgroundColor = UIColor(white: self.colorHSV.2, alpha: 1.0)
|
self.backgroundColor = UIColor(white: self.colorHSV.2, alpha: 1.0)
|
||||||
}
|
|
||||||
self.colorNode.value = self.colorHSV.2
|
self.colorNode.value = self.colorHSV.2
|
||||||
self.brightnessNode.hsv = self.colorHSV
|
self.brightnessNode.hsv = self.colorHSV
|
||||||
self.colorKnobNode.hsv = self.colorHSV
|
self.colorKnobNode.hsv = self.colorHSV
|
||||||
|
|
||||||
let min = self.colorHSV
|
|
||||||
let max = patternColor(for: self.color, intensity: 1.0).hsv
|
|
||||||
self.intensityNode.updateExtrema(min: min, max: max)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateKnobLayout(size: CGSize, panningColor: Bool, transition: ContainedViewLayoutTransition) {
|
func updateKnobLayout(size: CGSize, panningColor: Bool, transition: ContainedViewLayoutTransition) {
|
||||||
let knobSize = CGSize(width: 45.0, height: 45.0)
|
let knobSize = CGSize(width: 45.0, height: 45.0)
|
||||||
|
|
||||||
let colorHeight = self.adjustingPattern ? size.height - 116.0 : size.height - 66.0
|
let colorHeight = size.height - 66.0
|
||||||
var colorKnobFrame = CGRect(x: -knobSize.width / 2.0 + size.width * self.colorHSV.0, y: -knobSize.height / 2.0 + (colorHeight * (1.0 - self.colorHSV.1)), width: knobSize.width, height: knobSize.height)
|
var colorKnobFrame = CGRect(x: -knobSize.width / 2.0 + size.width * self.colorHSV.0, y: -knobSize.height / 2.0 + (colorHeight * (1.0 - self.colorHSV.1)), width: knobSize.width, height: knobSize.height)
|
||||||
var origin = colorKnobFrame.origin
|
var origin = colorKnobFrame.origin
|
||||||
if !panningColor {
|
if !panningColor {
|
||||||
@ -541,15 +286,12 @@ final class WallpaperColorPickerNode: ASDisplayNode {
|
|||||||
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||||
self.validLayout = size
|
self.validLayout = size
|
||||||
|
|
||||||
let colorHeight = self.adjustingPattern ? size.height - 116.0 : size.height - 66.0
|
let colorHeight = size.height - 66.0
|
||||||
transition.updateFrame(node: self.colorNode, frame: CGRect(x: 0.0, y: 0.0, width: size.width, height: colorHeight))
|
transition.updateFrame(node: self.colorNode, frame: CGRect(x: 0.0, y: 0.0, width: size.width, height: colorHeight))
|
||||||
|
|
||||||
let inset: CGFloat = 42.0
|
let inset: CGFloat = 42.0
|
||||||
transition.updateFrame(node: self.brightnessNode, frame: CGRect(x: inset, y: size.height - 55.0, width: size.width - inset * 2.0, height: 29.0))
|
transition.updateFrame(node: self.brightnessNode, frame: CGRect(x: inset, y: size.height - 55.0, width: size.width - inset * 2.0, height: 29.0))
|
||||||
|
|
||||||
let slidersInset: CGFloat = 24.0
|
|
||||||
transition.updateFrame(node: self.intensityNode, frame: CGRect(x: slidersInset, y: size.height - 54.0, width: size.width - slidersInset * 2.0, height: 50.0))
|
|
||||||
|
|
||||||
self.updateKnobLayout(size: size, panningColor: false, transition: .immediate)
|
self.updateKnobLayout(size: size, panningColor: false, transition: .immediate)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -558,7 +300,7 @@ final class WallpaperColorPickerNode: ASDisplayNode {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let colorHeight = self.adjustingPattern ? size.height - 116.0 : size.height - 66.0
|
let colorHeight = size.height - 66.0
|
||||||
|
|
||||||
let location = recognizer.location(in: recognizer.view)
|
let location = recognizer.location(in: recognizer.view)
|
||||||
let newHue = max(0.0, min(1.0, location.x / size.width))
|
let newHue = max(0.0, min(1.0, location.x / size.width))
|
||||||
@ -579,7 +321,7 @@ final class WallpaperColorPickerNode: ASDisplayNode {
|
|||||||
|
|
||||||
let previousColor = self.color
|
let previousColor = self.color
|
||||||
|
|
||||||
let colorHeight = self.adjustingPattern ? size.height - 116.0 : size.height - 66.0
|
let colorHeight = size.height - 66.0
|
||||||
|
|
||||||
let location = recognizer.location(in: recognizer.view)
|
let location = recognizer.location(in: recognizer.view)
|
||||||
let transition = recognizer.translation(in: recognizer.view)
|
let transition = recognizer.translation(in: recognizer.view)
|
||||||
|
|||||||
@ -91,7 +91,7 @@ private func updatedFileWallpaper(id: Int64? = nil, accessHash: Int64? = nil, sl
|
|||||||
intensityValue = 50
|
intensityValue = 50
|
||||||
}
|
}
|
||||||
|
|
||||||
return .file(id: id ?? 0, accessHash: accessHash ?? 0, isCreator: false, isDefault: false, isPattern: isPattern, slug: slug, file: file, settings: WallpaperSettings(blur: false, motion: false, color: colorValue, intensity: intensityValue))
|
return .file(id: id ?? 0, accessHash: accessHash ?? 0, isCreator: false, isDefault: false, isPattern: isPattern, isDark: false, slug: slug, file: file, settings: WallpaperSettings(blur: false, motion: false, color: colorValue, intensity: intensityValue))
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct WallpaperPatternTransition: Equatable {
|
private struct WallpaperPatternTransition: Equatable {
|
||||||
@ -318,9 +318,9 @@ class WallpaperGalleryController: ViewController {
|
|||||||
self.galleryNode.addSubnode(overlayNode)
|
self.galleryNode.addSubnode(overlayNode)
|
||||||
|
|
||||||
let colorPanelNode = WallpaperColorPanelNode(theme: presentationData.theme, strings: presentationData.strings)
|
let colorPanelNode = WallpaperColorPanelNode(theme: presentationData.theme, strings: presentationData.strings)
|
||||||
colorPanelNode.colorChanged = { [weak self] color, intensity, ended in
|
colorPanelNode.colorChanged = { [weak self] color, ended in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.updateEntries(color: color, intensity: intensity, preview: !ended)
|
strongSelf.updateEntries(color: color, preview: !ended)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if case let .customColor(colorValue) = self.source, let color = colorValue {
|
if case let .customColor(colorValue) = self.source, let color = colorValue {
|
||||||
@ -344,6 +344,18 @@ class WallpaperGalleryController: ViewController {
|
|||||||
let entry = strongSelf.entries[centralItemNode.index]
|
let entry = strongSelf.entries[centralItemNode.index]
|
||||||
switch entry {
|
switch entry {
|
||||||
case let .wallpaper(wallpaper):
|
case let .wallpaper(wallpaper):
|
||||||
|
var resource: MediaResource?
|
||||||
|
switch wallpaper {
|
||||||
|
case let .file(file):
|
||||||
|
resource = file.file.resource
|
||||||
|
case let .image(representations, _):
|
||||||
|
if let largestSize = largestImageRepresentation(representations) {
|
||||||
|
resource = largestSize.resource
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
let completion: () -> Void = {
|
let completion: () -> Void = {
|
||||||
let _ = (updatePresentationThemeSettingsInteractively(postbox: strongSelf.account.postbox, { current in
|
let _ = (updatePresentationThemeSettingsInteractively(postbox: strongSelf.account.postbox, { current in
|
||||||
var themeSpecificChatWallpapers = current.themeSpecificChatWallpapers
|
var themeSpecificChatWallpapers = current.themeSpecificChatWallpapers
|
||||||
@ -360,18 +372,6 @@ class WallpaperGalleryController: ViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if options.contains(.blur) {
|
if options.contains(.blur) {
|
||||||
var resource: MediaResource?
|
|
||||||
switch wallpaper {
|
|
||||||
case let .file(file):
|
|
||||||
resource = file.file.resource
|
|
||||||
case let .image(representations, _):
|
|
||||||
if let largestSize = largestImageRepresentation(representations) {
|
|
||||||
resource = largestSize.resource
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if let resource = resource {
|
if let resource = resource {
|
||||||
let _ = strongSelf.account.postbox.mediaBox.cachedResourceRepresentation(resource, representation: CachedBlurredWallpaperRepresentation(), complete: true, fetch: true).start(completed: {
|
let _ = strongSelf.account.postbox.mediaBox.cachedResourceRepresentation(resource, representation: CachedBlurredWallpaperRepresentation(), complete: true, fetch: true).start(completed: {
|
||||||
completion()
|
completion()
|
||||||
@ -439,17 +439,6 @@ class WallpaperGalleryController: ViewController {
|
|||||||
strongSelf.containerLayoutUpdated(layout, transition: .animated(duration: 0.3, curve: .spring))
|
strongSelf.containerLayoutUpdated(layout, transition: .animated(duration: 0.3, curve: .spring))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
node.requestColorPanel = { [weak self] color in
|
|
||||||
if let strongSelf = self, let (layout, _) = strongSelf.validLayout {
|
|
||||||
strongSelf.colorPanelEnabled = true
|
|
||||||
strongSelf.colorPanelNode?.adjustingPattern = true
|
|
||||||
strongSelf.colorPanelNode?.intensity = 40
|
|
||||||
strongSelf.colorPanelNode?.color = color
|
|
||||||
strongSelf.galleryNode.scrollView.isScrollEnabled = false
|
|
||||||
strongSelf.galleryNode.pager.isScrollEnabled = false
|
|
||||||
strongSelf.containerLayoutUpdated(layout, transition: .animated(duration: 0.3, curve: .spring))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let (layout, bottomInset) = self.validLayout {
|
if let (layout, bottomInset) = self.validLayout {
|
||||||
self.updateMessagesLayout(layout: layout, bottomInset: bottomInset, transition: .immediate)
|
self.updateMessagesLayout(layout: layout, bottomInset: bottomInset, transition: .immediate)
|
||||||
@ -457,7 +446,7 @@ class WallpaperGalleryController: ViewController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updateEntries(color: UIColor, intensity: Int32? = nil, preview: Bool = false) {
|
private func updateEntries(color: UIColor, preview: Bool = false) {
|
||||||
guard self.validLayout != nil, let centralEntryIndex = self.galleryNode.pager.centralItemNode()?.index else {
|
guard self.validLayout != nil, let centralEntryIndex = self.galleryNode.pager.centralItemNode()?.index else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -469,12 +458,6 @@ class WallpaperGalleryController: ViewController {
|
|||||||
switch wallpaper {
|
switch wallpaper {
|
||||||
case .color:
|
case .color:
|
||||||
currentEntry = .wallpaper(.color(Int32(color.rgb)))
|
currentEntry = .wallpaper(.color(Int32(color.rgb)))
|
||||||
case let .file(file):
|
|
||||||
if file.isPattern {
|
|
||||||
let newSettings = WallpaperSettings(blur: file.settings.blur, motion: file.settings.motion, color: Int32(bitPattern: color.rgb), intensity: intensity)
|
|
||||||
let newWallpaper = TelegramWallpaper.file(id: file.id, accessHash: file.accessHash, isCreator: file.isCreator, isDefault: file.isDefault, isPattern: file.isPattern, slug: file.slug, file: file.file, settings: newSettings)
|
|
||||||
currentEntry = .wallpaper(newWallpaper)
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -502,7 +485,7 @@ class WallpaperGalleryController: ViewController {
|
|||||||
if let entryColor = entryColor {
|
if let entryColor = entryColor {
|
||||||
if case let .file(file) = pattern {
|
if case let .file(file) = pattern {
|
||||||
let newSettings = WallpaperSettings(blur: file.settings.blur, motion: file.settings.motion, color: entryColor, intensity: intensity)
|
let newSettings = WallpaperSettings(blur: file.settings.blur, motion: file.settings.motion, color: entryColor, intensity: intensity)
|
||||||
let newWallpaper = TelegramWallpaper.file(id: file.id, accessHash: file.accessHash, isCreator: file.isCreator, isDefault: file.isDefault, isPattern: file.isPattern, slug: file.slug, file: file.file, settings: newSettings)
|
let newWallpaper = TelegramWallpaper.file(id: file.id, accessHash: file.accessHash, isCreator: file.isCreator, isDefault: file.isDefault, isPattern: file.isPattern, isDark: file.isDark, slug: file.slug, file: file.file, settings: newSettings)
|
||||||
updatedEntries.append(.wallpaper(newWallpaper))
|
updatedEntries.append(.wallpaper(newWallpaper))
|
||||||
} else {
|
} else {
|
||||||
let newWallpaper = TelegramWallpaper.color(entryColor)
|
let newWallpaper = TelegramWallpaper.color(entryColor)
|
||||||
@ -690,7 +673,7 @@ class WallpaperGalleryController: ViewController {
|
|||||||
|
|
||||||
var controller: ShareController?
|
var controller: ShareController?
|
||||||
switch wallpaper {
|
switch wallpaper {
|
||||||
case let .file(_, _, _, _, isPattern, slug, _, settings):
|
case let .file(_, _, _, _, isPattern, _, slug, _, settings):
|
||||||
var options: [String] = []
|
var options: [String] = []
|
||||||
if (itemNode.options.contains(.blur) && !isPattern) {
|
if (itemNode.options.contains(.blur) && !isPattern) {
|
||||||
if (itemNode.options.contains(.motion)) {
|
if (itemNode.options.contains(.motion)) {
|
||||||
|
|||||||
@ -6,34 +6,6 @@ import Postbox
|
|||||||
import TelegramCore
|
import TelegramCore
|
||||||
import LegacyComponents
|
import LegacyComponents
|
||||||
|
|
||||||
private class WallpaperMotionEffect: UIInterpolatingMotionEffect {
|
|
||||||
var previousValue: CGFloat?
|
|
||||||
|
|
||||||
override func keyPathsAndRelativeValues(forViewerOffset viewerOffset: UIOffset) -> [String : Any]? {
|
|
||||||
var motionAmplitude: CGFloat = 0.0
|
|
||||||
switch self.type {
|
|
||||||
case .tiltAlongHorizontalAxis:
|
|
||||||
motionAmplitude = viewerOffset.horizontal
|
|
||||||
case .tiltAlongVerticalAxis:
|
|
||||||
motionAmplitude = viewerOffset.vertical
|
|
||||||
}
|
|
||||||
|
|
||||||
if (motionAmplitude > 0) {
|
|
||||||
guard let max = (self.maximumRelativeValue as? CGFloat) else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
let value = max * motionAmplitude
|
|
||||||
return [self.keyPath: value]
|
|
||||||
} else {
|
|
||||||
guard let min = (self.minimumRelativeValue as? CGFloat) else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
let value = -(min) * motionAmplitude
|
|
||||||
return [self.keyPath: value]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct WallpaperGalleryItemArguments {
|
struct WallpaperGalleryItemArguments {
|
||||||
let colorPreview: Bool
|
let colorPreview: Bool
|
||||||
let isColorsList: Bool
|
let isColorsList: Bool
|
||||||
@ -87,14 +59,12 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
|||||||
let wrapperNode: ASDisplayNode
|
let wrapperNode: ASDisplayNode
|
||||||
let imageNode: TransformImageNode
|
let imageNode: TransformImageNode
|
||||||
private let statusNode: RadialStatusNode
|
private let statusNode: RadialStatusNode
|
||||||
private let progressNode: ASTextNode
|
|
||||||
private let blurredNode: BlurredImageNode
|
private let blurredNode: BlurredImageNode
|
||||||
let cropNode: WallpaperCropNode
|
let cropNode: WallpaperCropNode
|
||||||
|
|
||||||
private var blurButtonNode: WallpaperOptionButtonNode
|
private var blurButtonNode: WallpaperOptionButtonNode
|
||||||
private var motionButtonNode: WallpaperOptionButtonNode
|
private var motionButtonNode: WallpaperOptionButtonNode
|
||||||
private var patternButtonNode: WallpaperOptionButtonNode
|
private var patternButtonNode: WallpaperOptionButtonNode
|
||||||
private var colorButtonNode: WallpaperOptionButtonNode
|
|
||||||
|
|
||||||
fileprivate let _ready = Promise<Void>()
|
fileprivate let _ready = Promise<Void>()
|
||||||
private let fetchDisposable = MetaDisposable()
|
private let fetchDisposable = MetaDisposable()
|
||||||
@ -106,7 +76,6 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
|||||||
let actionButton = Promise<UIBarButtonItem?>(nil)
|
let actionButton = Promise<UIBarButtonItem?>(nil)
|
||||||
var action: (() -> Void)?
|
var action: (() -> Void)?
|
||||||
var requestPatternPanel: ((Bool) -> Void)?
|
var requestPatternPanel: ((Bool) -> Void)?
|
||||||
var requestColorPanel: ((UIColor) -> Void)?
|
|
||||||
|
|
||||||
private var validLayout: ContainerViewLayout?
|
private var validLayout: ContainerViewLayout?
|
||||||
private var validOffset: CGFloat?
|
private var validOffset: CGFloat?
|
||||||
@ -121,16 +90,13 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
|||||||
self.statusNode = RadialStatusNode(backgroundNodeColor: UIColor(white: 0.0, alpha: 0.6))
|
self.statusNode = RadialStatusNode(backgroundNodeColor: UIColor(white: 0.0, alpha: 0.6))
|
||||||
self.statusNode.frame = CGRect(x: 0.0, y: 0.0, width: progressDiameter, height: progressDiameter)
|
self.statusNode.frame = CGRect(x: 0.0, y: 0.0, width: progressDiameter, height: progressDiameter)
|
||||||
self.statusNode.isUserInteractionEnabled = false
|
self.statusNode.isUserInteractionEnabled = false
|
||||||
self.progressNode = ASTextNode()
|
|
||||||
|
|
||||||
self.blurredNode = BlurredImageNode()
|
self.blurredNode = BlurredImageNode()
|
||||||
|
|
||||||
let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
|
let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
|
||||||
self.blurButtonNode = WallpaperOptionButtonNode(title: presentationData.strings.WallpaperPreview_Blurred, value: .check(false))
|
self.blurButtonNode = WallpaperOptionButtonNode(title: presentationData.strings.WallpaperPreview_Blurred, value: .check(false))
|
||||||
self.motionButtonNode = WallpaperOptionButtonNode(title: presentationData.strings.WallpaperPreview_Motion, value: .check(false))
|
self.motionButtonNode = WallpaperOptionButtonNode(title: presentationData.strings.WallpaperPreview_Motion, value: .check(false))
|
||||||
|
|
||||||
self.patternButtonNode = WallpaperOptionButtonNode(title: presentationData.strings.WallpaperPreview_Pattern, value: .check(false))
|
self.patternButtonNode = WallpaperOptionButtonNode(title: presentationData.strings.WallpaperPreview_Pattern, value: .check(false))
|
||||||
self.colorButtonNode = WallpaperOptionButtonNode(title: presentationData.strings.WallpaperPreview_Color, value: .color(false, .white))
|
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
@ -146,17 +112,14 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
|||||||
|
|
||||||
self.addSubnode(self.wrapperNode)
|
self.addSubnode(self.wrapperNode)
|
||||||
self.addSubnode(self.statusNode)
|
self.addSubnode(self.statusNode)
|
||||||
self.addSubnode(self.progressNode)
|
|
||||||
|
|
||||||
self.addSubnode(self.blurButtonNode)
|
self.addSubnode(self.blurButtonNode)
|
||||||
self.addSubnode(self.motionButtonNode)
|
self.addSubnode(self.motionButtonNode)
|
||||||
self.addSubnode(self.patternButtonNode)
|
self.addSubnode(self.patternButtonNode)
|
||||||
self.addSubnode(self.colorButtonNode)
|
|
||||||
|
|
||||||
self.blurButtonNode.addTarget(self, action: #selector(self.toggleBlur), forControlEvents: .touchUpInside)
|
self.blurButtonNode.addTarget(self, action: #selector(self.toggleBlur), forControlEvents: .touchUpInside)
|
||||||
self.motionButtonNode.addTarget(self, action: #selector(self.toggleMotion), forControlEvents: .touchUpInside)
|
self.motionButtonNode.addTarget(self, action: #selector(self.toggleMotion), forControlEvents: .touchUpInside)
|
||||||
self.patternButtonNode.addTarget(self, action: #selector(self.togglePattern), forControlEvents: .touchUpInside)
|
self.patternButtonNode.addTarget(self, action: #selector(self.togglePattern), forControlEvents: .touchUpInside)
|
||||||
self.colorButtonNode.addTarget(self, action: #selector(self.toggleColor), forControlEvents: .touchUpInside)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
@ -265,7 +228,6 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
|||||||
patternColor = UIColor(rgb: UInt32(bitPattern: color), alpha: patternIntensity)
|
patternColor = UIColor(rgb: UInt32(bitPattern: color), alpha: patternIntensity)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.colorButtonNode.color = patternColor.withAlphaComponent(1.0)
|
|
||||||
self.backgroundColor = patternColor.withAlphaComponent(1.0)
|
self.backgroundColor = patternColor.withAlphaComponent(1.0)
|
||||||
|
|
||||||
if let previousEntry = previousEntry, case let .wallpaper(wallpaper) = previousEntry, case let .file(previousFile) = wallpaper, file.id == previousFile.id && (file.settings.color != previousFile.settings.color || file.settings.intensity != previousFile.settings.intensity) && self.colorPreview == self.arguments.colorPreview {
|
if let previousEntry = previousEntry, case let .wallpaper(wallpaper) = previousEntry, case let .file(previousFile) = wallpaper, file.id == previousFile.id && (file.settings.color != previousFile.settings.color || file.settings.intensity != previousFile.settings.intensity) && self.colorPreview == self.arguments.colorPreview {
|
||||||
@ -418,21 +380,17 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
|||||||
case let .Fetching(_, progress):
|
case let .Fetching(_, progress):
|
||||||
let adjustedProgress = max(progress, 0.027)
|
let adjustedProgress = max(progress, 0.027)
|
||||||
state = .progress(color: statusForegroundColor, lineWidth: nil, value: CGFloat(adjustedProgress), cancelEnabled: false)
|
state = .progress(color: statusForegroundColor, lineWidth: nil, value: CGFloat(adjustedProgress), cancelEnabled: false)
|
||||||
strongSelf.progressNode.attributedText = NSAttributedString(string: "\(Int(progress * 100))%", font: Font.medium(13), textColor: .white, paragraphAlignment: .center)
|
|
||||||
case .Local:
|
case .Local:
|
||||||
state = .none
|
state = .none
|
||||||
strongSelf.progressNode.attributedText = nil
|
|
||||||
local = true
|
local = true
|
||||||
case .Remote:
|
case .Remote:
|
||||||
state = .progress(color: statusForegroundColor, lineWidth: nil, value: 0.027, cancelEnabled: false)
|
state = .progress(color: statusForegroundColor, lineWidth: nil, value: 0.027, cancelEnabled: false)
|
||||||
strongSelf.progressNode.attributedText = nil
|
|
||||||
}
|
}
|
||||||
strongSelf.statusNode.transitionToState(state, completion: {})
|
strongSelf.statusNode.transitionToState(state, completion: {})
|
||||||
|
|
||||||
strongSelf.blurButtonNode.setEnabled(local)
|
strongSelf.blurButtonNode.setEnabled(local)
|
||||||
strongSelf.motionButtonNode.setEnabled(local)
|
strongSelf.motionButtonNode.setEnabled(local)
|
||||||
strongSelf.patternButtonNode.setEnabled(local)
|
strongSelf.patternButtonNode.setEnabled(local)
|
||||||
strongSelf.colorButtonNode.setEnabled(local)
|
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
@ -444,7 +402,6 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
|||||||
|> deliverOnMainQueue).start(next: { [weak self] color in
|
|> deliverOnMainQueue).start(next: { [weak self] color in
|
||||||
self?.statusNode.backgroundNodeColor = color
|
self?.statusNode.backgroundNodeColor = color
|
||||||
self?.patternButtonNode.buttonColor = color
|
self?.patternButtonNode.buttonColor = color
|
||||||
self?.colorButtonNode.buttonColor = color
|
|
||||||
self?.blurButtonNode.buttonColor = color
|
self?.blurButtonNode.buttonColor = color
|
||||||
self?.motionButtonNode.buttonColor = color
|
self?.motionButtonNode.buttonColor = color
|
||||||
}))
|
}))
|
||||||
@ -568,21 +525,6 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
|||||||
self.requestPatternPanel?(value)
|
self.requestPatternPanel?(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
var isColorEnabled: Bool {
|
|
||||||
return self.colorButtonNode.isSelected
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc func toggleColor() {
|
|
||||||
let value = !self.colorButtonNode.isSelected
|
|
||||||
self.colorButtonNode.setSelected(value, animated: true)
|
|
||||||
|
|
||||||
if let color = self.colorButtonNode.color {
|
|
||||||
self.requestColorPanel?(color)
|
|
||||||
|
|
||||||
self.preparePatternEditing()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func preparePatternEditing() {
|
private func preparePatternEditing() {
|
||||||
if let entry = self.entry, case let .wallpaper(wallpaper) = entry, case let .file(file) = wallpaper {
|
if let entry = self.entry, case let .wallpaper(wallpaper) = entry, case let .file(file) = wallpaper {
|
||||||
if let size = file.file.dimensions?.fitted(CGSize(width: 1280.0, height: 1280.0)) {
|
if let size = file.file.dimensions?.fitted(CGSize(width: 1280.0, height: 1280.0)) {
|
||||||
@ -593,11 +535,11 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
|||||||
|
|
||||||
func setMotionEnabled(_ enabled: Bool, animated: Bool) {
|
func setMotionEnabled(_ enabled: Bool, animated: Bool) {
|
||||||
if enabled {
|
if enabled {
|
||||||
let horizontal = WallpaperMotionEffect(keyPath: "center.x", type: .tiltAlongHorizontalAxis)
|
let horizontal = UIInterpolatingMotionEffect(keyPath: "center.x", type: .tiltAlongHorizontalAxis)
|
||||||
horizontal.minimumRelativeValue = motionAmount
|
horizontal.minimumRelativeValue = motionAmount
|
||||||
horizontal.maximumRelativeValue = -motionAmount
|
horizontal.maximumRelativeValue = -motionAmount
|
||||||
|
|
||||||
let vertical = WallpaperMotionEffect(keyPath: "center.y", type: .tiltAlongVerticalAxis)
|
let vertical = UIInterpolatingMotionEffect(keyPath: "center.y", type: .tiltAlongVerticalAxis)
|
||||||
vertical.minimumRelativeValue = motionAmount
|
vertical.minimumRelativeValue = motionAmount
|
||||||
vertical.maximumRelativeValue = -motionAmount
|
vertical.maximumRelativeValue = -motionAmount
|
||||||
|
|
||||||
@ -640,11 +582,10 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
|||||||
|
|
||||||
func updateButtonsLayout(layout: ContainerViewLayout, offset: CGPoint, transition: ContainedViewLayoutTransition) {
|
func updateButtonsLayout(layout: ContainerViewLayout, offset: CGPoint, transition: ContainedViewLayoutTransition) {
|
||||||
let patternButtonSize = self.patternButtonNode.measure(layout.size)
|
let patternButtonSize = self.patternButtonNode.measure(layout.size)
|
||||||
let colorButtonSize = self.colorButtonNode.measure(layout.size)
|
|
||||||
let blurButtonSize = self.blurButtonNode.measure(layout.size)
|
let blurButtonSize = self.blurButtonNode.measure(layout.size)
|
||||||
let motionButtonSize = self.motionButtonNode.measure(layout.size)
|
let motionButtonSize = self.motionButtonNode.measure(layout.size)
|
||||||
|
|
||||||
let maxButtonWidth = max(patternButtonSize.width, max(colorButtonSize.width, max(blurButtonSize.width, motionButtonSize.width)))
|
let maxButtonWidth = max(patternButtonSize.width, max(blurButtonSize.width, motionButtonSize.width))
|
||||||
let buttonSize = CGSize(width: maxButtonWidth, height: 30.0)
|
let buttonSize = CGSize(width: maxButtonWidth, height: 30.0)
|
||||||
let alpha = 1.0 - min(1.0, max(0.0, abs(offset.y) / 50.0))
|
let alpha = 1.0 - min(1.0, max(0.0, abs(offset.y) / 50.0))
|
||||||
|
|
||||||
@ -654,17 +595,12 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let leftButtonFrame = CGRect(origin: CGPoint(x: floor(layout.size.width / 2.0 - buttonSize.width - 10.0) + offset.x, y: layout.size.height - 49.0 - layout.intrinsicInsets.bottom - 54.0 + offset.y + additionalYOffset), size: buttonSize)
|
let leftButtonFrame = CGRect(origin: CGPoint(x: floor(layout.size.width / 2.0 - buttonSize.width - 10.0) + offset.x, y: layout.size.height - 49.0 - layout.intrinsicInsets.bottom - 54.0 + offset.y + additionalYOffset), size: buttonSize)
|
||||||
|
|
||||||
let centerButtonFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - buttonSize.width) / 2.0) + offset.x, y: layout.size.height - 49.0 - layout.intrinsicInsets.bottom - 54.0 + offset.y + additionalYOffset), size: buttonSize)
|
let centerButtonFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - buttonSize.width) / 2.0) + offset.x, y: layout.size.height - 49.0 - layout.intrinsicInsets.bottom - 54.0 + offset.y + additionalYOffset), size: buttonSize)
|
||||||
|
|
||||||
let rightButtonFrame = CGRect(origin: CGPoint(x: ceil(layout.size.width / 2.0 + 10.0) + offset.x, y: layout.size.height - 49.0 - layout.intrinsicInsets.bottom - 54.0 + offset.y + additionalYOffset), size: buttonSize)
|
let rightButtonFrame = CGRect(origin: CGPoint(x: ceil(layout.size.width / 2.0 + 10.0) + offset.x, y: layout.size.height - 49.0 - layout.intrinsicInsets.bottom - 54.0 + offset.y + additionalYOffset), size: buttonSize)
|
||||||
|
|
||||||
var patternAlpha: CGFloat = 0.0
|
var patternAlpha: CGFloat = 0.0
|
||||||
var patternFrame = centerButtonFrame
|
var patternFrame = centerButtonFrame
|
||||||
|
|
||||||
var colorAlpha: CGFloat = 0.0
|
|
||||||
var colorFrame = centerButtonFrame
|
|
||||||
|
|
||||||
var blurAlpha: CGFloat = 0.0
|
var blurAlpha: CGFloat = 0.0
|
||||||
var blurFrame = centerButtonFrame
|
var blurFrame = centerButtonFrame
|
||||||
|
|
||||||
@ -673,7 +609,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
|||||||
|
|
||||||
if let entry = self.entry {
|
if let entry = self.entry {
|
||||||
switch entry {
|
switch entry {
|
||||||
case let .asset(_):
|
case .asset:
|
||||||
blurAlpha = 1.0
|
blurAlpha = 1.0
|
||||||
blurFrame = leftButtonFrame
|
blurFrame = leftButtonFrame
|
||||||
motionAlpha = 1.0
|
motionAlpha = 1.0
|
||||||
@ -709,10 +645,6 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
|||||||
}
|
}
|
||||||
motionFrame = rightButtonFrame
|
motionFrame = rightButtonFrame
|
||||||
}
|
}
|
||||||
// if !self.arguments.isColorsList || self.patternButtonNode.isSelected {
|
|
||||||
// motionAlpha = 1.0
|
|
||||||
// motionFrame = rightButtonFrame
|
|
||||||
// }
|
|
||||||
} else {
|
} else {
|
||||||
blurAlpha = 1.0
|
blurAlpha = 1.0
|
||||||
blurFrame = leftButtonFrame
|
blurFrame = leftButtonFrame
|
||||||
@ -726,9 +658,6 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
|||||||
transition.updateFrame(node: self.patternButtonNode, frame: patternFrame)
|
transition.updateFrame(node: self.patternButtonNode, frame: patternFrame)
|
||||||
transition.updateAlpha(node: self.patternButtonNode, alpha: patternAlpha * alpha)
|
transition.updateAlpha(node: self.patternButtonNode, alpha: patternAlpha * alpha)
|
||||||
|
|
||||||
transition.updateFrame(node: self.colorButtonNode, frame: colorFrame)
|
|
||||||
transition.updateAlpha(node: self.colorButtonNode, alpha: colorAlpha * alpha)
|
|
||||||
|
|
||||||
transition.updateFrame(node: self.blurButtonNode, frame: blurFrame)
|
transition.updateFrame(node: self.blurButtonNode, frame: blurFrame)
|
||||||
transition.updateAlpha(node: self.blurButtonNode, alpha: blurAlpha * alpha)
|
transition.updateAlpha(node: self.blurButtonNode, alpha: blurAlpha * alpha)
|
||||||
|
|
||||||
@ -768,8 +697,6 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.statusNode.frame = CGRect(x: layout.safeInsets.left + floorToScreenPixels((layout.size.width - layout.safeInsets.left - layout.safeInsets.right - progressDiameter) / 2.0), y: floorToScreenPixels((layout.size.height + additionalYOffset - progressDiameter) / 2.0), width: progressDiameter, height: progressDiameter)
|
self.statusNode.frame = CGRect(x: layout.safeInsets.left + floorToScreenPixels((layout.size.width - layout.safeInsets.left - layout.safeInsets.right - progressDiameter) / 2.0), y: floorToScreenPixels((layout.size.height + additionalYOffset - progressDiameter) / 2.0), width: progressDiameter, height: progressDiameter)
|
||||||
self.progressNode.frame = CGRect(x: layout.safeInsets.left + floorToScreenPixels((layout.size.width - layout.safeInsets.left - layout.safeInsets.right - progressDiameter) / 2.0), y: floorToScreenPixels((layout.size.height + additionalYOffset - 15.0) / 2.0), width: progressDiameter, height: progressDiameter)
|
|
||||||
|
|
||||||
|
|
||||||
self.updateButtonsLayout(layout: layout, offset: CGPoint(x: offset, y: 0.0), transition: transition)
|
self.updateButtonsLayout(layout: layout, offset: CGPoint(x: offset, y: 0.0), transition: transition)
|
||||||
|
|
||||||
|
|||||||
@ -75,7 +75,7 @@ final class WallpaperPatternPanelNode: ASDisplayNode {
|
|||||||
var updatedWallpaper = wallpaper
|
var updatedWallpaper = wallpaper
|
||||||
if case let .file(file) = updatedWallpaper {
|
if case let .file(file) = updatedWallpaper {
|
||||||
let settings = WallpaperSettings(blur: false, motion: false, color: 0xd6e2ee, intensity: 100)
|
let settings = WallpaperSettings(blur: false, motion: false, color: 0xd6e2ee, intensity: 100)
|
||||||
updatedWallpaper = .file(id: file.id, accessHash: file.accessHash, isCreator: file.isCreator, isDefault: file.isDefault, isPattern: file.isPattern, slug: file.slug, file: file.file, settings: settings)
|
updatedWallpaper = .file(id: file.id, accessHash: file.accessHash, isCreator: file.isCreator, isDefault: file.isDefault, isPattern: file.isPattern, isDark: file.isDark, slug: file.slug, file: file.file, settings: settings)
|
||||||
}
|
}
|
||||||
|
|
||||||
node.setWallpaper(account: account, wallpaper: updatedWallpaper, selected: selected, size: itemSize)
|
node.setWallpaper(account: account, wallpaper: updatedWallpaper, selected: selected, size: itemSize)
|
||||||
@ -116,7 +116,6 @@ final class WallpaperPatternPanelNode: ASDisplayNode {
|
|||||||
self.scrollNode.view.alwaysBounceHorizontal = true
|
self.scrollNode.view.alwaysBounceHorizontal = true
|
||||||
|
|
||||||
let sliderView = TGPhotoEditorSliderView()
|
let sliderView = TGPhotoEditorSliderView()
|
||||||
//sliderView.enablePanHandling = true
|
|
||||||
sliderView.trackCornerRadius = 1.0
|
sliderView.trackCornerRadius = 1.0
|
||||||
sliderView.lineSize = 2.0
|
sliderView.lineSize = 2.0
|
||||||
sliderView.minimumValue = 0.0
|
sliderView.minimumValue = 0.0
|
||||||
|
|||||||
@ -11,8 +11,29 @@ private func wallpaperDatas(account: Account, fileReference: FileMediaReference?
|
|||||||
let maybeFullSize: Signal<MediaResourceData, NoError>
|
let maybeFullSize: Signal<MediaResourceData, NoError>
|
||||||
if thumbnail, let file = fileReference?.media {
|
if thumbnail, let file = fileReference?.media {
|
||||||
maybeFullSize = account.postbox.mediaBox.cachedResourceRepresentation(file.resource, representation: CachedScaledImageRepresentation(size: CGSize(width: 720.0, height: 720.0), mode: .aspectFit), complete: false, fetch: false)
|
maybeFullSize = account.postbox.mediaBox.cachedResourceRepresentation(file.resource, representation: CachedScaledImageRepresentation(size: CGSize(width: 720.0, height: 720.0), mode: .aspectFit), complete: false, fetch: false)
|
||||||
|
|> mapToSignal { maybeData -> Signal<MediaResourceData, NoError> in
|
||||||
|
if maybeData.complete {
|
||||||
|
return .single(maybeData)
|
||||||
} else {
|
} else {
|
||||||
maybeFullSize = account.postbox.mediaBox.resourceData(largestRepresentation.resource)
|
return account.postbox.mediaBox.resourceData(file.resource)
|
||||||
|
|> mapToSignal { maybeData -> Signal<MediaResourceData, NoError> in
|
||||||
|
if maybeData.complete {
|
||||||
|
return account.postbox.mediaBox.cachedResourceRepresentation(file.resource, representation: CachedScaledImageRepresentation(size: CGSize(width: 720.0, height: 720.0), mode: .aspectFit), complete: false, fetch: true)
|
||||||
|
} else {
|
||||||
|
return .single(maybeData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
maybeFullSize = account.postbox.mediaBox.cachedResourceRepresentation(largestRepresentation.resource, representation: CachedScaledImageRepresentation(size: CGSize(width: 720.0, height: 720.0), mode: .aspectFit), complete: false, fetch: false)
|
||||||
|
|> mapToSignal { maybeData -> Signal<MediaResourceData, NoError> in
|
||||||
|
if maybeData.complete {
|
||||||
|
return .single(maybeData)
|
||||||
|
} else {
|
||||||
|
return account.postbox.mediaBox.resourceData(largestRepresentation.resource)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let decodedThumbnailData = fileReference?.media.immediateThumbnailData.flatMap(decodeTinyThumbnail)
|
let decodedThumbnailData = fileReference?.media.immediateThumbnailData.flatMap(decodeTinyThumbnail)
|
||||||
|
|
||||||
@ -300,8 +321,14 @@ private func patternWallpaperDatas(account: Account, representations: [ImageRepr
|
|||||||
}
|
}
|
||||||
|
|
||||||
func patternWallpaperImage(account: Account, representations: [ImageRepresentationWithReference], mode: PatternWallpaperDrawMode, autoFetchFullSize: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
|
func patternWallpaperImage(account: Account, representations: [ImageRepresentationWithReference], mode: PatternWallpaperDrawMode, autoFetchFullSize: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
|
||||||
let signal = patternWallpaperDatas(account: account, representations: representations, mode: mode, autoFetchFullSize: autoFetchFullSize)
|
|
||||||
|
|
||||||
|
return patternWallpaperDatas(account: account, representations: representations, mode: mode, autoFetchFullSize: autoFetchFullSize)
|
||||||
|
|> mapToSignal { (thumbnailData, fullSizeData, fullSizeComplete) in
|
||||||
|
return patternWallpaperImageInternal(thumbnailData: thumbnailData, fullSizeData: fullSizeData, fullSizeComplete: fullSizeComplete, mode: mode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func patternWallpaperImageInternal(thumbnailData: Data?, fullSizeData: Data?, fullSizeComplete: Bool, mode: PatternWallpaperDrawMode) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
|
||||||
var prominent = false
|
var prominent = false
|
||||||
if case .thumbnail = mode {
|
if case .thumbnail = mode {
|
||||||
prominent = true
|
prominent = true
|
||||||
@ -309,10 +336,10 @@ func patternWallpaperImage(account: Account, representations: [ImageRepresentati
|
|||||||
|
|
||||||
var scale: CGFloat = 0.0
|
var scale: CGFloat = 0.0
|
||||||
if case .fastScreen = mode {
|
if case .fastScreen = mode {
|
||||||
scale = 1.0 //max(1.0, UIScreenScale - 1.0)
|
scale = 1.0
|
||||||
}
|
}
|
||||||
|
|
||||||
return signal
|
return .single((thumbnailData, fullSizeData, fullSizeComplete))
|
||||||
|> map { (thumbnailData, fullSizeData, fullSizeComplete) in
|
|> map { (thumbnailData, fullSizeData, fullSizeComplete) in
|
||||||
return { arguments in
|
return { arguments in
|
||||||
let drawingRect = arguments.drawingRect
|
let drawingRect = arguments.drawingRect
|
||||||
@ -382,7 +409,7 @@ func patternColor(for color: UIColor, intensity: CGFloat, prominent: Bool = fals
|
|||||||
var saturation: CGFloat = 0.0
|
var saturation: CGFloat = 0.0
|
||||||
var brightness: CGFloat = 0.0
|
var brightness: CGFloat = 0.0
|
||||||
if color.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: nil) {
|
if color.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: nil) {
|
||||||
if saturation > 0.0 || (brightness < 1.0 && brightness > 0.0) {
|
if saturation > 0.0 {
|
||||||
saturation = min(1.0, saturation + 0.05 + 0.1 * (1.0 - saturation))
|
saturation = min(1.0, saturation + 0.05 + 0.1 * (1.0 - saturation))
|
||||||
}
|
}
|
||||||
if brightness > 0.5 {
|
if brightness > 0.5 {
|
||||||
@ -452,3 +479,73 @@ func settingsBuiltinWallpaperImage(account: Account) -> Signal<(TransformImageAr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func photoWallpaper(postbox: Postbox, photoLibraryResource: PhotoLibraryMediaResource) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
|
||||||
|
let thumbnail = fetchPhotoLibraryImage(localIdentifier: photoLibraryResource.localIdentifier, thumbnail: true)
|
||||||
|
let fullSize = fetchPhotoLibraryImage(localIdentifier: photoLibraryResource.localIdentifier, thumbnail: false)
|
||||||
|
|
||||||
|
return (thumbnail |> then(fullSize))
|
||||||
|
|> map { result in
|
||||||
|
var sourceImage = result?.0
|
||||||
|
let isThumbnail = result?.1 ?? false
|
||||||
|
|
||||||
|
return { arguments in
|
||||||
|
let context = DrawingContext(size: arguments.drawingSize, scale: 1.0, clear: true)
|
||||||
|
|
||||||
|
let dimensions = sourceImage?.size
|
||||||
|
|
||||||
|
if let thumbnailImage = sourceImage?.cgImage, isThumbnail {
|
||||||
|
var fittedSize = arguments.imageSize
|
||||||
|
if abs(fittedSize.width - arguments.boundingSize.width).isLessThanOrEqualTo(CGFloat(1.0)) {
|
||||||
|
fittedSize.width = arguments.boundingSize.width
|
||||||
|
}
|
||||||
|
if abs(fittedSize.height - arguments.boundingSize.height).isLessThanOrEqualTo(CGFloat(1.0)) {
|
||||||
|
fittedSize.height = arguments.boundingSize.height
|
||||||
|
}
|
||||||
|
|
||||||
|
let thumbnailSize = CGSize(width: thumbnailImage.width, height: thumbnailImage.height)
|
||||||
|
|
||||||
|
let initialThumbnailContextFittingSize = fittedSize.fitted(CGSize(width: 100.0, height: 100.0))
|
||||||
|
|
||||||
|
let thumbnailContextSize = thumbnailSize.aspectFitted(initialThumbnailContextFittingSize)
|
||||||
|
let thumbnailContext = DrawingContext(size: thumbnailContextSize, scale: 1.0)
|
||||||
|
thumbnailContext.withFlippedContext { c in
|
||||||
|
c.interpolationQuality = .none
|
||||||
|
c.draw(thumbnailImage, in: CGRect(origin: CGPoint(), size: thumbnailContextSize))
|
||||||
|
}
|
||||||
|
telegramFastBlur(Int32(thumbnailContextSize.width), Int32(thumbnailContextSize.height), Int32(thumbnailContext.bytesPerRow), thumbnailContext.bytes)
|
||||||
|
|
||||||
|
var thumbnailContextFittingSize = CGSize(width: floor(arguments.drawingSize.width * 0.5), height: floor(arguments.drawingSize.width * 0.5))
|
||||||
|
if thumbnailContextFittingSize.width < 150.0 || thumbnailContextFittingSize.height < 150.0 {
|
||||||
|
thumbnailContextFittingSize = thumbnailContextFittingSize.aspectFilled(CGSize(width: 150.0, height: 150.0))
|
||||||
|
}
|
||||||
|
|
||||||
|
if thumbnailContextFittingSize.width > thumbnailContextSize.width {
|
||||||
|
let additionalContextSize = thumbnailContextFittingSize
|
||||||
|
let additionalBlurContext = DrawingContext(size: additionalContextSize, scale: 1.0)
|
||||||
|
additionalBlurContext.withFlippedContext { c in
|
||||||
|
c.interpolationQuality = .default
|
||||||
|
if let image = thumbnailContext.generateImage()?.cgImage {
|
||||||
|
c.draw(image, in: CGRect(origin: CGPoint(), size: additionalContextSize))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
telegramFastBlur(Int32(additionalContextSize.width), Int32(additionalContextSize.height), Int32(additionalBlurContext.bytesPerRow), additionalBlurContext.bytes)
|
||||||
|
sourceImage = additionalBlurContext.generateImage()
|
||||||
|
} else {
|
||||||
|
sourceImage = thumbnailContext.generateImage()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
context.withFlippedContext { c in
|
||||||
|
c.setBlendMode(.copy)
|
||||||
|
if let sourceImage = sourceImage, let cgImage = sourceImage.cgImage, let dimensions = dimensions {
|
||||||
|
let imageSize = dimensions.aspectFilled(arguments.drawingRect.size)
|
||||||
|
let fittedRect = CGRect(origin: CGPoint(x: floor((arguments.drawingRect.size.width - imageSize.width) / 2.0), y: floor((arguments.drawingRect.size.height - imageSize.height) / 2.0)), size: imageSize)
|
||||||
|
c.draw(cgImage, in: fittedRect)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return context
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user