This commit is contained in:
Ilya Laktyushin 2019-01-17 22:05:49 +04:00
parent 1270d99fc2
commit a43f219f13
39 changed files with 1877 additions and 1246 deletions

View File

@ -6,12 +6,12 @@
},
{
"idiom" : "universal",
"filename" : "SearchBarIconLight@2x.png",
"filename" : "IconSearch@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "SearchBarIconLight@3x.png",
"filename" : "IconSearch@3x.png",
"scale" : "3x"
}
],

Binary file not shown.

After

Width:  |  Height:  |  Size: 964 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 330 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 476 B

View File

@ -57,6 +57,8 @@
096C98C021787C6700C211FF /* TGBridgeAudioEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 096C98BC21787C6600C211FF /* TGBridgeAudioEncoder.h */; };
096C98C121787C6700C211FF /* TGBridgeAudioDecoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 096C98BD21787C6700C211FF /* TGBridgeAudioDecoder.h */; };
096C98C221787C6700C211FF /* TGBridgeAudioDecoder.mm in Sources */ = {isa = PBXBuildFile; fileRef = 096C98BE21787C6700C211FF /* TGBridgeAudioDecoder.mm */; };
09749BC321F0DFFD008FDDE9 /* StickersChatInputContextPanelNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09749BC221F0DFFD008FDDE9 /* StickersChatInputContextPanelNode.swift */; };
09749BC521F0E024008FDDE9 /* StickersChatInputPanelItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09749BC421F0E024008FDDE9 /* StickersChatInputPanelItem.swift */; };
09797873210633CD0077D77F /* InstantPageSettingsButtonItemNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09797872210633CD0077D77F /* InstantPageSettingsButtonItemNode.swift */; };
0979787C210642CB0077D77F /* WebEmbedPlayerNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0979787B210642CB0077D77F /* WebEmbedPlayerNode.swift */; };
0979787E210646C00077D77F /* YoutubeEmbedImplementation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0979787D210646C00077D77F /* YoutubeEmbedImplementation.swift */; };
@ -1182,6 +1184,8 @@
096C98BC21787C6600C211FF /* TGBridgeAudioEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TGBridgeAudioEncoder.h; sourceTree = "<group>"; };
096C98BD21787C6700C211FF /* TGBridgeAudioDecoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TGBridgeAudioDecoder.h; sourceTree = "<group>"; };
096C98BE21787C6700C211FF /* TGBridgeAudioDecoder.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = TGBridgeAudioDecoder.mm; sourceTree = "<group>"; };
09749BC221F0DFFD008FDDE9 /* StickersChatInputContextPanelNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StickersChatInputContextPanelNode.swift; sourceTree = "<group>"; };
09749BC421F0E024008FDDE9 /* StickersChatInputPanelItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StickersChatInputPanelItem.swift; sourceTree = "<group>"; };
09797872210633CD0077D77F /* InstantPageSettingsButtonItemNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstantPageSettingsButtonItemNode.swift; sourceTree = "<group>"; };
0979787B210642CB0077D77F /* WebEmbedPlayerNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebEmbedPlayerNode.swift; sourceTree = "<group>"; };
0979787D210646C00077D77F /* YoutubeEmbedImplementation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YoutubeEmbedImplementation.swift; sourceTree = "<group>"; };
@ -2912,6 +2916,8 @@
children = (
D049EAE11E447AD500A2CD3A /* HorizontalStickersChatContextPanelNode.swift */,
D049EAE31E44949F00A2CD3A /* HorizontalStickerGridItem.swift */,
09749BC221F0DFFD008FDDE9 /* StickersChatInputContextPanelNode.swift */,
09749BC421F0E024008FDDE9 /* StickersChatInputPanelItem.swift */,
);
name = Stickers;
sourceTree = "<group>";
@ -5168,6 +5174,7 @@
092F36902157AB46001A9F49 /* ItemListCallListItem.swift in Sources */,
D0EC6CC61EB9F58800EBF1C3 /* PresenceStrings.swift in Sources */,
D0EC6CC71EB9F58800EBF1C3 /* PeerNotificationSoundStrings.swift in Sources */,
09749BC321F0DFFD008FDDE9 /* StickersChatInputContextPanelNode.swift in Sources */,
D01C06C01FBF118A001561AB /* MessageUtils.swift in Sources */,
D0104F281F47171F004E4881 /* InstantPageGalleryController.swift in Sources */,
D0EC6CC81EB9F58800EBF1C3 /* ProgressiveImage.swift in Sources */,
@ -5724,6 +5731,7 @@
D0EEE9A12165585F001292A6 /* DocumentPreviewController.swift in Sources */,
D0EC6DCE1EB9F58900EBF1C3 /* HorizontalStickersChatContextPanelNode.swift in Sources */,
D0BCC3D2203F0A6C008126C2 /* StringForMessageTimestampStatus.swift in Sources */,
09749BC521F0E024008FDDE9 /* StickersChatInputPanelItem.swift in Sources */,
D0EC6DCF1EB9F58900EBF1C3 /* HorizontalStickerGridItem.swift in Sources */,
D0EC6DD01EB9F58900EBF1C3 /* HashtagChatInputContextPanelNode.swift in Sources */,
09B4EE5621A8149C00847FA6 /* PermissionInfoItem.swift in Sources */,

View File

@ -5350,6 +5350,8 @@ public final class ChatController: TelegramController, KeyShortcutResponder, Gal
}
private func openUrl(_ url: String, concealed: Bool) {
self.commitPurposefulAction()
let openImpl: () -> Void = { [weak self] in
guard let strongSelf = self else {
return

View File

@ -181,9 +181,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.controller = controller
self.backgroundNode = ChatBackgroundNode()
//self.backgroundNode.isLayerBacked = true
self.backgroundNode.displaysAsynchronously = false
//self.backgroundNode.clipsToBounds = true
self.titleAccessoryPanelContainer = ChatControllerTitlePanelNodeContainer()
self.titleAccessoryPanelContainer.clipsToBounds = true

View File

@ -996,7 +996,8 @@ public class ChatListController: TelegramController, KeyShortcutResponder, UIVie
markAllChatsAsReadInteractively(transaction: transaction, viewTracker: account.viewTracker)
}
}
let _ = signal.start(completed: { [weak self] in
let _ = (signal
|> deliverOnMainQueue).start(completed: { [weak self] in
self?.donePressed()
})
} else if !peerIds.isEmpty {
@ -1034,7 +1035,8 @@ public class ChatListController: TelegramController, KeyShortcutResponder, UIVie
progressDisposable.dispose()
}
}
let _ = signal.start(completed: {
let _ = (signal
|> deliverOnMainQueue).start(completed: {
self?.donePressed()
})
}))

View File

@ -507,7 +507,7 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
switch status {
case let .fetchStatus(fetchStatus):
switch fetchStatus {
case let .Fetching(isActive, progress):
case let .Fetching(_, progress):
let adjustedProgress = max(progress, 0.027)
state = .progress(color: bubbleTheme.mediaOverlayControlForegroundColor, lineWidth: nil, value: CGFloat(adjustedProgress), cancelEnabled: true)
case .Local:

View File

@ -641,6 +641,16 @@ private func preparedContactListNodeTransition(account: Account, from fromEntrie
break
}
}
} else {
outer: for entry in toEntries {
switch entry {
case .sort:
shouldFixScroll = true
break outer
default:
break
}
}
}
var scrollToItem: ListViewScrollToItem?

View File

@ -103,18 +103,22 @@ func fetchPhotoLibraryResource(localIdentifier: String) -> Signal<MediaResourceD
}
}
func fetchPhotoLibraryImage(localIdentifier: String) -> Signal<(UIImage, Bool)?, NoError> {
func fetchPhotoLibraryImage(localIdentifier: String, thumbnail: Bool) -> Signal<(UIImage, Bool)?, NoError> {
return Signal { subscriber in
let fetchResult = PHAsset.fetchAssets(withLocalIdentifiers: [localIdentifier], options: nil)
let requestId = Atomic<RequestId>(value: RequestId())
if fetchResult.count != 0 {
let asset = fetchResult.object(at: 0)
let option = PHImageRequestOptions()
option.deliveryMode = .opportunistic
option.deliveryMode = .highQualityFormat
if thumbnail {
option.resizeMode = .fast
}
option.isNetworkAccessAllowed = true
option.isSynchronous = false
let requestIdValue = PHImageManager.default().requestImage(for: asset, targetSize: PHImageManagerMaximumSize, contentMode: .aspectFill, options: option, resultHandler: { (image, info) -> Void in
let targetSize: CGSize = thumbnail ? CGSize(width: 128.0, height: 128.0) : PHImageManagerMaximumSize
let requestIdValue = PHImageManager.default().requestImage(for: asset, targetSize: targetSize, contentMode: .aspectFill, options: option, resultHandler: { (image, info) -> Void in
Queue.concurrentDefaultQueue().async {
requestId.with { current -> Void in
if !current.invalidated {
@ -123,15 +127,8 @@ func fetchPhotoLibraryImage(localIdentifier: String) -> Signal<(UIImage, Bool)?,
}
}
if let image = image {
var isThumbnail = true
if let info = info, let degraded = info[PHImageResultIsDegradedKey] {
isThumbnail = (degraded as AnyObject).boolValue!
}
subscriber.putNext((image, isThumbnail))
if !isThumbnail {
subscriber.putCompletion()
}
subscriber.putNext((image, thumbnail))
subscriber.putCompletion()
}
}
})

View File

@ -8,7 +8,7 @@ class GalleryControllerNode: ASDisplayNode, UIScrollViewDelegate, UIGestureRecog
var navigationBar: NavigationBar?
let footerNode: GalleryFooterNode
var currentThumbnailContainerNode: GalleryThumbnailContainerNode?
var toolbarNode: ASDisplayNode?
var overlayNode: ASDisplayNode?
var transitionDataForCentralItem: (() -> ((ASDisplayNode, () -> UIView?)?, (UIView) -> Void)?)?
var dismiss: (() -> Void)?
@ -255,10 +255,6 @@ class GalleryControllerNode: ASDisplayNode, UIScrollViewDelegate, UIGestureRecog
self.currentThumbnailContainerNode?.alpha = 1.0
})
if let toolbarNode = self.toolbarNode {
toolbarNode.layer.animatePosition(from: CGPoint(x: 0.0, y: self.bounds.size.height), to: CGPoint(), duration: 0.4, timingFunction: kCAMediaTimingFunctionSpring, additive: true)
}
if animateContent {
self.scrollView.layer.animateBounds(from: self.scrollView.layer.bounds.offsetBy(dx: 0.0, dy: -self.scrollView.layer.bounds.size.height), to: self.scrollView.layer.bounds, duration: 0.4, timingFunction: kCAMediaTimingFunctionSpring)
}
@ -292,10 +288,6 @@ class GalleryControllerNode: ASDisplayNode, UIScrollViewDelegate, UIGestureRecog
intermediateCompletion()
})
if let toolbarNode = self.toolbarNode {
toolbarNode.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: self.bounds.size.height), duration: 0.25, timingFunction: kCAMediaTimingFunctionLinear, removeOnCompletion: false, additive: true)
}
if animateContent {
contentAnimationCompleted = false
self.scrollView.layer.animateBounds(from: self.scrollView.layer.bounds, to: self.scrollView.layer.bounds.offsetBy(dx: 0.0, dy: -self.scrollView.layer.bounds.size.height), duration: 0.25, timingFunction: kCAMediaTimingFunctionLinear, removeOnCompletion: false, completion: { _ in
@ -327,8 +319,8 @@ class GalleryControllerNode: ASDisplayNode, UIScrollViewDelegate, UIGestureRecog
self.updateDismissTransition(transition)
if let toolbarNode = toolbarNode {
toolbarNode.alpha = transition
if let overlayNode = self.overlayNode {
overlayNode.alpha = transition
}
}

View File

@ -60,6 +60,7 @@ final class HorizontalStickerGridItemNode: GridItemNode {
super.init()
self.imageNode.transform = CATransform3DMakeRotation(CGFloat.pi / 2.0, 0.0, 0.0, 1.0)
self.addSubnode(self.imageNode)
}

View File

@ -8,6 +8,38 @@ import SwiftSignalKit
final class HorizontalStickersChatContextPanelInteraction {
var previewedStickerItem: StickerPackItem?
}
private func backgroundCenterImage(_ theme: PresentationTheme) -> UIImage? {
return generateImage(CGSize(width: 30.0, height: 82.0), rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setStrokeColor(theme.list.itemPlainSeparatorColor.cgColor)
context.setFillColor(theme.list.plainBackgroundColor.cgColor)
let lineWidth = UIScreenPixel
context.setLineWidth(lineWidth)
context.translateBy(x: 460.5, y: 364)
let _ = try? drawSvgPath(context, path: "M-490.476836,-365 L-394.167708,-365 L-394.167708,-291.918214 C-394.167708,-291.918214 -383.538396,-291.918214 -397.691655,-291.918214 C-402.778486,-291.918214 -424.555168,-291.918214 -434.037301,-291.918214 C-440.297129,-291.918214 -440.780682,-283.5 -445.999879,-283.5 C-450.393041,-283.5 -452.491241,-291.918214 -456.502636,-291.918214 C-465.083339,-291.918214 -476.209155,-291.918214 -483.779021,-291.918214 C-503.033963,-291.918214 -490.476836,-291.918214 -490.476836,-291.918214 L-490.476836,-365 ")
context.fillPath()
context.translateBy(x: 0.0, y: lineWidth / 2.0)
let _ = try? drawSvgPath(context, path: "M-490.476836,-365 L-394.167708,-365 L-394.167708,-291.918214 C-394.167708,-291.918214 -383.538396,-291.918214 -397.691655,-291.918214 C-402.778486,-291.918214 -424.555168,-291.918214 -434.037301,-291.918214 C-440.297129,-291.918214 -440.780682,-283.5 -445.999879,-283.5 C-450.393041,-283.5 -452.491241,-291.918214 -456.502636,-291.918214 C-465.083339,-291.918214 -476.209155,-291.918214 -483.779021,-291.918214 C-503.033963,-291.918214 -490.476836,-291.918214 -490.476836,-291.918214 L-490.476836,-365 ")
context.strokePath()
context.translateBy(x: -460.5, y: -lineWidth / 2.0 - 364.0)
context.move(to: CGPoint(x: 0.0, y: lineWidth / 2.0))
context.addLine(to: CGPoint(x: size.width, y: lineWidth / 2.0))
context.strokePath()
})
}
private func backgroundLeftImage(_ theme: PresentationTheme) -> UIImage? {
return generateImage(CGSize(width: 8.0, height: 16.0), rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setStrokeColor(theme.list.itemPlainSeparatorColor.cgColor)
context.setFillColor(theme.list.plainBackgroundColor.cgColor)
let lineWidth = UIScreenPixel
context.setLineWidth(lineWidth)
context.fillEllipse(in: CGRect(origin: CGPoint(), size: CGSize(width: size.height, height: size.height)))
context.strokeEllipse(in: CGRect(origin: CGPoint(x: lineWidth / 2.0, y: lineWidth / 2.0), size: CGSize(width: size.height - lineWidth, height: size.height - lineWidth)))
})?.stretchableImage(withLeftCapWidth: 8, topCapHeight: 8)
}
private struct StickerEntry: Identifiable, Comparable {
let index: Int
@ -55,12 +87,15 @@ private func preparedGridEntryTransition(account: Account, from fromEntries: [St
final class HorizontalStickersChatContextPanelNode: ChatInputContextPanelNode {
private var strings: PresentationStrings
private let backgroundLeftNode: ASImageNode
private let backgroundNode: ASImageNode
private let backgroundRightNode: ASImageNode
private let clippingNode: ASDisplayNode
private let gridNode: GridNode
private let backgroundNode: ASDisplayNode
private var validLayout: (CGSize, CGFloat, CGFloat, ChatPresentationInterfaceState)?
private var currentEntries: [StickerEntry]?
private var queuedTransitions: [(StickerEntryTransition, Bool)] = []
private var currentEntries: [StickerEntry] = []
private var queuedTransitions: [StickerEntryTransition] = []
public var controllerInteraction: ChatControllerInteraction?
private let stickersInteraction: HorizontalStickersChatContextPanelInteraction
@ -70,22 +105,41 @@ final class HorizontalStickersChatContextPanelNode: ChatInputContextPanelNode {
override init(account: Account, theme: PresentationTheme, strings: PresentationStrings) {
self.strings = strings
self.gridNode = GridNode()
self.gridNode.view.disablesInteractiveTransitionGestureRecognizer = true
self.gridNode.scrollView.alwaysBounceVertical = true
self.backgroundNode = ASImageNode()
self.backgroundNode.displayWithoutProcessing = true
self.backgroundNode.displaysAsynchronously = false
self.backgroundNode.image = backgroundCenterImage(theme)
self.backgroundNode = ASDisplayNode()
self.backgroundNode.backgroundColor = theme.list.plainBackgroundColor
self.backgroundLeftNode = ASImageNode()
self.backgroundLeftNode.displayWithoutProcessing = true
self.backgroundLeftNode.displaysAsynchronously = false
self.backgroundLeftNode.image = backgroundLeftImage(theme)
self.backgroundRightNode = ASImageNode()
self.backgroundRightNode.displayWithoutProcessing = true
self.backgroundRightNode.displaysAsynchronously = false
self.backgroundRightNode.image = backgroundLeftImage(theme)
self.backgroundRightNode.transform = CATransform3DMakeScale(-1.0, 1.0, 1.0)
self.clippingNode = ASDisplayNode()
self.clippingNode.clipsToBounds = true
self.gridNode = GridNode()
self.gridNode.transform = CATransform3DMakeRotation(-CGFloat.pi / 2.0, 0.0, 0.0, 1.0)
self.gridNode.view.disablesInteractiveTransitionGestureRecognizer = true
self.stickersInteraction = HorizontalStickersChatContextPanelInteraction()
super.init(account: account, theme: theme, strings: strings)
self.placement = .overTextInput
self.isOpaque = false
self.clipsToBounds = true
self.addSubnode(self.gridNode)
self.gridNode.addSubnode(self.backgroundNode)
self.addSubnode(self.backgroundNode)
self.addSubnode(self.backgroundLeftNode)
self.addSubnode(self.backgroundRightNode)
self.addSubnode(self.clippingNode)
self.clippingNode.addSubnode(self.gridNode)
}
override func didLoad() {
@ -99,82 +153,81 @@ final class HorizontalStickersChatContextPanelNode: ChatInputContextPanelNode {
}
if let itemNode = strongSelf.gridNode.itemNodeAtPoint(strongSelf.view.convert(point, to: strongSelf.gridNode.view)) as? HorizontalStickerGridItemNode, let item = itemNode.stickerItem {
return strongSelf.account.postbox.transaction { transaction -> Bool in
return getIsStickerSaved(transaction: transaction, fileId: item.file.fileId)
}
|> deliverOnMainQueue
|> map { isStarred -> (ASDisplayNode, PeekControllerContent)? in
if let strongSelf = self, let controllerInteraction = strongSelf.controllerInteraction {
var menuItems: [PeekControllerMenuItem] = []
menuItems = [
PeekControllerMenuItem(title: strongSelf.strings.StickerPack_Send, color: .accent, font: .bold, action: {
controllerInteraction.sendSticker(.standalone(media: item.file), true)
}),
PeekControllerMenuItem(title: isStarred ? strongSelf.strings.Stickers_RemoveFromFavorites : strongSelf.strings.Stickers_AddToFavorites, color: isStarred ? .destructive : .accent, action: {
if let strongSelf = self {
if isStarred {
let _ = removeSavedSticker(postbox: strongSelf.account.postbox, mediaId: item.file.fileId).start()
} else {
let _ = addSavedSticker(postbox: strongSelf.account.postbox, network: strongSelf.account.network, file: item.file).start()
}
return strongSelf.account.postbox.transaction { transaction -> Bool in
return getIsStickerSaved(transaction: transaction, fileId: item.file.fileId)
}
|> deliverOnMainQueue
|> map { isStarred -> (ASDisplayNode, PeekControllerContent)? in
if let strongSelf = self, let controllerInteraction = strongSelf.controllerInteraction {
var menuItems: [PeekControllerMenuItem] = []
menuItems = [
PeekControllerMenuItem(title: strongSelf.strings.StickerPack_Send, color: .accent, font: .bold, action: {
controllerInteraction.sendSticker(.standalone(media: item.file), true)
}),
PeekControllerMenuItem(title: isStarred ? strongSelf.strings.Stickers_RemoveFromFavorites : strongSelf.strings.Stickers_AddToFavorites, color: isStarred ? .destructive : .accent, action: {
if let strongSelf = self {
if isStarred {
let _ = removeSavedSticker(postbox: strongSelf.account.postbox, mediaId: item.file.fileId).start()
} else {
let _ = addSavedSticker(postbox: strongSelf.account.postbox, network: strongSelf.account.network, file: item.file).start()
}
}),
PeekControllerMenuItem(title: strongSelf.strings.StickerPack_ViewPack, color: .accent, action: {
if let strongSelf = self, let controllerInteraction = strongSelf.controllerInteraction {
loop: for attribute in item.file.attributes {
switch attribute {
case let .Sticker(_, packReference, _):
if let packReference = packReference {
let controller = StickerPackPreviewController(account: strongSelf.account, stickerPack: packReference, parentNavigationController: controllerInteraction.navigationController())
controller.sendSticker = { file in
if let strongSelf = self, let controllerInteraction = strongSelf.controllerInteraction {
controllerInteraction.sendSticker(file, true)
}
}
}),
PeekControllerMenuItem(title: strongSelf.strings.StickerPack_ViewPack, color: .accent, action: {
if let strongSelf = self, let controllerInteraction = strongSelf.controllerInteraction {
loop: for attribute in item.file.attributes {
switch attribute {
case let .Sticker(_, packReference, _):
if let packReference = packReference {
let controller = StickerPackPreviewController(account: strongSelf.account, stickerPack: packReference, parentNavigationController: controllerInteraction.navigationController())
controller.sendSticker = { file in
if let strongSelf = self, let controllerInteraction = strongSelf.controllerInteraction {
controllerInteraction.sendSticker(file, true)
}
controllerInteraction.navigationController()?.view.window?.endEditing(true)
controllerInteraction.presentController(controller, nil)
}
break loop
default:
break
controllerInteraction.navigationController()?.view.window?.endEditing(true)
controllerInteraction.presentController(controller, nil)
}
break loop
default:
break
}
}
}),
PeekControllerMenuItem(title: strongSelf.strings.Common_Cancel, color: .accent, action: {})
]
return (itemNode, StickerPreviewPeekContent(account: strongSelf.account, item: .pack(item), menu: menuItems))
} else {
return nil
}
}
}),
PeekControllerMenuItem(title: strongSelf.strings.Common_Cancel, color: .accent, action: {})
]
return (itemNode, StickerPreviewPeekContent(account: strongSelf.account, item: .pack(item), menu: menuItems))
} else {
return nil
}
}
}
}
return nil
}, present: { [weak self] content, sourceNode in
if let strongSelf = self {
let controller = PeekController(theme: PeekControllerTheme(presentationTheme: strongSelf.theme), content: content, sourceNode: {
return sourceNode
})
strongSelf.interfaceInteraction?.presentGlobalOverlayController(controller, nil)
return controller
}
return nil
}, updateContent: { [weak self] content in
if let strongSelf = self {
var item: StickerPackItem?
if let content = content as? StickerPreviewPeekContent, case let .pack(contentItem) = content.item {
item = contentItem
}, present: { [weak self] content, sourceNode in
if let strongSelf = self {
let controller = PeekController(theme: PeekControllerTheme(presentationTheme: strongSelf.theme), content: content, sourceNode: {
return sourceNode
})
strongSelf.interfaceInteraction?.presentGlobalOverlayController(controller, nil)
return controller
}
return nil
}, updateContent: { [weak self] content in
if let strongSelf = self {
var item: StickerPackItem?
if let content = content as? StickerPreviewPeekContent, case let .pack(contentItem) = content.item {
item = contentItem
}
strongSelf.updatePreviewingItem(item: item, animated: true)
}
strongSelf.updatePreviewingItem(item: item, animated: true)
}
}))
}
func updateResults(_ results: [TelegramMediaFile]) {
let firstTime = self.currentEntries == nil
let previousEntries = self.currentEntries ?? []
let previousEntries = self.currentEntries
var entries: [StickerEntry] = []
for i in 0 ..< results.count {
entries.append(StickerEntry(index: i, file: results[i]))
@ -186,11 +239,11 @@ final class HorizontalStickersChatContextPanelNode: ChatInputContextPanelNode {
}
let transition = preparedGridEntryTransition(account: self.account, from: previousEntries, to: entries, stickersInteraction: self.stickersInteraction, interfaceInteraction: self.interfaceInteraction!)
self.enqueueTransition(transition, firstTime: firstTime)
self.enqueueTransition(transition)
}
private func enqueueTransition(_ transition: StickerEntryTransition, firstTime: Bool) {
self.queuedTransitions.append((transition, firstTime))
private func enqueueTransition(_ transition: StickerEntryTransition) {
self.queuedTransitions.append(transition)
if self.validLayout != nil {
self.dequeueTransitions()
}
@ -198,71 +251,71 @@ final class HorizontalStickersChatContextPanelNode: ChatInputContextPanelNode {
private func dequeueTransitions() {
while !self.queuedTransitions.isEmpty {
let (transition, firstTime) = self.queuedTransitions.removeFirst()
self.gridNode.transaction(GridNodeTransaction(deleteItems: transition.deletions, insertItems: transition.insertions, updateItems: transition.updates, scrollToItem: transition.scrollToItem, updateLayout: nil, itemTransition: .immediate, stationaryItems: transition.stationaryItems, updateFirstIndexInSectionOffset: transition.updateFirstIndexInSectionOffset), completion: { [weak self] _ in
if let strongSelf = self {
strongSelf.backgroundNode.frame = CGRect(x: 0.0, y: 0.0, width: strongSelf.bounds.width, height: strongSelf.gridNode.scrollView.contentSize.height + 500.0)
if firstTime {
let position = strongSelf.gridNode.layer.position
let offset = strongSelf.gridNode.frame.height + strongSelf.gridNode.scrollView.contentOffset.y
strongSelf.gridNode.layer.animatePosition(from: CGPoint(x: position.x, y: position.y + offset), to: position, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, completion: { _ in })
}
}
})
let transition = self.queuedTransitions.removeFirst()
self.gridNode.transaction(GridNodeTransaction(deleteItems: transition.deletions, insertItems: transition.insertions, updateItems: transition.updates, scrollToItem: transition.scrollToItem, updateLayout: nil, itemTransition: .immediate, stationaryItems: transition.stationaryItems, updateFirstIndexInSectionOffset: transition.updateFirstIndexInSectionOffset), completion: { _ in })
}
}
private func topInsetForLayout(size: CGSize) -> CGFloat {
let minimumItemHeights: CGFloat = floor(66.0 * 1.5)
return max(size.height - minimumItemHeights, 0.0)
}
override func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) {
let hadValidLayout = self.validLayout != nil
let sideInsets: CGFloat = 10.0 + leftInset
let contentWidth = min(size.width - sideInsets - sideInsets, max(24.0, CGFloat(self.currentEntries.count) * 66.0 + 6.0))
var contentLeftInset: CGFloat = 40.0
var leftOffset: CGFloat = 0.0
if sideInsets + floor(contentWidth / 2.0) < sideInsets + contentLeftInset + 15.0 {
let updatedLeftInset = sideInsets + floor(contentWidth / 2.0) - 15.0 - sideInsets
leftOffset = contentLeftInset - updatedLeftInset
contentLeftInset = updatedLeftInset
}
let backgroundFrame = CGRect(origin: CGPoint(x: sideInsets + leftOffset, y: size.height - 82.0 + 4.0), size: CGSize(width: contentWidth, height: 82.0))
let backgroundLeftFrame = CGRect(origin: backgroundFrame.origin, size: CGSize(width: contentLeftInset, height: backgroundFrame.size.height - 10.0 + UIScreenPixel))
let backgroundCenterFrame = CGRect(origin: CGPoint(x: backgroundLeftFrame.maxX, y: backgroundFrame.minY), size: CGSize(width: 30.0, height: 82.0))
let backgroundRightFrame = CGRect(origin: CGPoint(x: backgroundCenterFrame.maxX, y: backgroundFrame.minY), size: CGSize(width: max(0.0, backgroundFrame.minX + backgroundFrame.size.width - backgroundCenterFrame.maxX), height: backgroundFrame.size.height - 10.0 + UIScreenPixel))
transition.updateFrame(node: self.backgroundLeftNode, frame: backgroundLeftFrame)
transition.updateFrame(node: self.backgroundNode, frame: backgroundCenterFrame)
transition.updateFrame(node: self.backgroundRightNode, frame: backgroundRightFrame)
let gridFrame = CGRect(origin: CGPoint(x: backgroundFrame.minX, y: backgroundFrame.minY + 4.0), size: CGSize(width: backgroundFrame.size.width, height: 66.0))
transition.updateFrame(node: self.clippingNode, frame: gridFrame)
self.gridNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: gridFrame.size.height, height: gridFrame.size.width))
let gridBounds = self.gridNode.bounds
self.gridNode.bounds = CGRect(x: gridBounds.minX, y: gridBounds.minY, width: gridFrame.size.height, height: gridFrame.size.width)
self.gridNode.position = CGPoint(x: gridFrame.size.width / 2.0, y: gridFrame.size.height / 2.0)
self.gridNode.transaction(GridNodeTransaction(deleteItems: [], insertItems: [], updateItems: [], scrollToItem: nil, updateLayout: GridNodeUpdateLayout(layout: GridNodeLayout(size: CGSize(width: gridFrame.size.height, height: gridFrame.size.width), insets: UIEdgeInsets(top: 3.0, left: 0.0, bottom: 3.0, right: 0.0), preloadSize: 100.0, type: .fixed(itemSize: CGSize(width: 66.0, height: 66.0), fillWidth: nil, lineSpacing: 0.0, itemSpacing: nil)), transition: .immediate), itemTransition: .immediate, stationaryItems: .all, updateFirstIndexInSectionOffset: nil), completion: { _ in })
let dequeue = self.validLayout == nil
self.validLayout = (size, leftInset, rightInset, interfaceState)
var insets = UIEdgeInsets()
insets.top = self.topInsetForLayout(size: size)
insets.left = leftInset
insets.right = rightInset
transition.updateFrame(node: self.gridNode, frame: CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height))
let updateSizeAndInsets = GridNodeUpdateLayout(layout: GridNodeLayout(size: size, insets: insets, preloadSize: 100.0, type: .fixed(itemSize: CGSize(width: 66.0, height: 66.0), fillWidth: nil, lineSpacing: 0.0, itemSpacing: nil)), transition: transition)
self.gridNode.transaction(GridNodeTransaction(deleteItems: [], insertItems: [], updateItems: [], scrollToItem: nil, updateLayout: updateSizeAndInsets, itemTransition: .immediate, stationaryItems: .all, updateFirstIndexInSectionOffset: nil), completion: { [weak self] _ in
if let strongSelf = self {
strongSelf.backgroundNode.frame = CGRect(x: 0.0, y: 0.0, width: size.width, height: strongSelf.gridNode.scrollView.contentSize.height + 500.0)
}
})
if !hadValidLayout {
if dequeue {
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
self.dequeueTransitions()
}
if self.theme !== interfaceState.theme {
self.theme = interfaceState.theme
self.backgroundNode.image = backgroundCenterImage(theme)
self.backgroundLeftNode.image = backgroundLeftImage(theme)
self.backgroundRightNode.image = backgroundLeftImage(theme)
// if let currentEntries = self.currentEntries {
// self.updateToEntries(entries: currentEntries, forceUpdate: true)
// }
}
}
override func animateOut(completion: @escaping () -> Void) {
let position = self.gridNode.layer.position
let offset = self.gridNode.frame.height + self.gridNode.scrollView.contentOffset.y
self.gridNode.layer.animatePosition(from: position, to: CGPoint(x: position.x, y: position.y + offset), duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, completion: { _ in
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { _ in
completion()
})
}
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
let convertedPoint = self.convert(point, to: self.gridNode)
if convertedPoint.y > 0.0 {
return super.hitTest(point, with: event)
} else {
if !self.clippingNode.frame.contains(point) {
return nil
}
return super.hitTest(point, with: event)
}
private func updatePreviewingItem(item: StickerPackItem?, animated: Bool) {

View File

@ -2196,7 +2196,7 @@ func instantPageImageFile(account: Account, fileReference: FileMediaReference, f
}
}
private func avatarGalleryPhotoDatas(account: Account, fileReference: FileMediaReference? = nil, representations: [ImageRepresentationWithReference], autoFetchFullSize: Bool = false) -> Signal<(Data?, Data?, Bool), NoError> {
private func avatarGalleryPhotoDatas(account: Account, fileReference: FileMediaReference? = nil, representations: [ImageRepresentationWithReference], alwaysShowThumbnailFirst: Bool = false, autoFetchFullSize: Bool = false) -> Signal<(Data?, Data?, Bool), NoError> {
if let smallestRepresentation = smallestImageRepresentation(representations.map({ $0.representation })), let largestRepresentation = largestImageRepresentation(representations.map({ $0.representation })), let smallestIndex = representations.index(where: { $0.representation == smallestRepresentation }), let largestIndex = representations.index(where: { $0.representation == largestRepresentation }) {
let maybeFullSize = account.postbox.mediaBox.resourceData(largestRepresentation.resource)
let decodedThumbnailData = fileReference?.media.immediateThumbnailData.flatMap(decodeTinyThumbnail)
@ -2206,7 +2206,12 @@ private func avatarGalleryPhotoDatas(account: Account, fileReference: FileMediaR
|> mapToSignal { maybeData -> Signal<(Data?, Data?, Bool), NoError> in
if maybeData.complete {
let loadedData: Data? = try? Data(contentsOf: URL(fileURLWithPath: maybeData.path), options: [])
return .single((nil, loadedData, true))
if alwaysShowThumbnailFirst, let decodedThumbnailData = decodedThumbnailData {
return .single((decodedThumbnailData, nil, false))
|> then(.single((nil, loadedData, true)))
} else {
return .single((nil, loadedData, true))
}
} else {
let fetchedThumbnail: Signal<FetchResourceSourceType, FetchResourceError>
if let _ = decodedThumbnailData {
@ -2269,8 +2274,8 @@ private func avatarGalleryPhotoDatas(account: Account, fileReference: FileMediaR
}
}
func chatAvatarGalleryPhoto(account: Account, fileReference: FileMediaReference? = nil, representations: [ImageRepresentationWithReference], autoFetchFullSize: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
let signal = avatarGalleryPhotoDatas(account: account, fileReference: fileReference, representations: representations, autoFetchFullSize: autoFetchFullSize)
func chatAvatarGalleryPhoto(account: Account, fileReference: FileMediaReference? = nil, representations: [ImageRepresentationWithReference], alwaysShowThumbnailFirst: Bool = false, autoFetchFullSize: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
let signal = avatarGalleryPhotoDatas(account: account, fileReference: fileReference, representations: representations, alwaysShowThumbnailFirst: alwaysShowThumbnailFirst, autoFetchFullSize: autoFetchFullSize)
return signal
|> map { (thumbnailData, fullSizeData, fullSizeComplete) in
@ -2794,7 +2799,10 @@ func playerAlbumArt(postbox: Postbox, fileReference: FileMediaReference?, albumA
}
func photoWallpaper(postbox: Postbox, photoLibraryResource: PhotoLibraryMediaResource) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
return fetchPhotoLibraryImage(localIdentifier: photoLibraryResource.localIdentifier)
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
@ -2802,7 +2810,7 @@ func photoWallpaper(postbox: Postbox, photoLibraryResource: PhotoLibraryMediaRes
return { arguments in
let context = DrawingContext(size: arguments.drawingSize, scale: 1.0, clear: true)
var dimensions = sourceImage?.size
let dimensions = sourceImage?.size
if let thumbnailImage = sourceImage?.cgImage, isThumbnail {
var fittedSize = arguments.imageSize

File diff suppressed because it is too large Load Diff

View File

@ -373,14 +373,25 @@ func proxyServerSettingsController(theme: PresentationTheme, strings: Presentati
let _ = controller?.dismiss()
}
shareImpl = {
shareImpl = { [weak controller] in
let state = stateValue.with { $0 }
guard let server = proxyServerSettings(with: state) else {
guard let server = proxyServerSettings(with: state), let strongController = controller else {
return
}
let controller = ShareProxyServerActionSheetController(theme: theme, strings: strings, updatedPresentationData: updatedPresentationData, link: shareLink(for: server))
presentImpl?(controller, nil)
let link = shareLink(for: server)
if #available(iOSApplicationExtension 9.0, *) {
let controller = ShareProxyServerActionSheetController(theme: theme, strings: strings, updatedPresentationData: updatedPresentationData, link: link)
presentImpl?(controller, nil)
} else {
let activityController = UIActivityViewController(activityItems: [link], applicationActivities: nil)
if let window = strongController.view.window, let rootViewController = window.rootViewController {
activityController.popoverPresentationController?.sourceView = window
activityController.popoverPresentationController?.sourceRect = CGRect(origin: CGPoint(x: window.bounds.width / 2.0, y: window.bounds.size.height - 1.0), size: CGSize(width: 1.0, height: 1.0))
rootViewController.present(activityController, animated: true, completion: nil)
}
}
}
return controller

View File

@ -76,7 +76,7 @@ func qrCode(string: String, color: UIColor, backgroundColor: UIColor? = nil, sca
c.setFillColor(color.cgColor)
let _ = try? drawSvgPath(c, path: "M0.0,40 C0,20.3664202 20.1230605,0.0 32.5,0.0 C44.8769395,0.0 65,20.3664202 65,40 C65,47.217934 65,55.5505326 65,64.9977957 L32.5,79 L0.0,64.9977957 C0.0,55.0825772 0.0,46.7499786 0.0,40 Z")
if false, let backgroundColor = backgroundColor {
if let backgroundColor = backgroundColor {
c.setFillColor(backgroundColor.cgColor)
} else {
c.setBlendMode(.clear)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 KiB

After

Width:  |  Height:  |  Size: 498 KiB

View File

@ -112,8 +112,7 @@ class SearchBarPlaceholderNode: ASDisplayNode {
var iconSize = CGSize()
var totalWidth = labelLayoutResult.size.width
let spacing: CGFloat = 7.0
let spacing: CGFloat = 8.0
if let iconImage = strongSelf.iconNode.image {
iconSize = iconImage.size

View File

@ -97,7 +97,7 @@ final class SettingsThemeWallpaperNode: ASDisplayNode {
var convertedRepresentations: [ImageRepresentationWithReference] = []
for representation in file.file.previewRepresentations {
convertedRepresentations.append(ImageRepresentationWithReference(representation: representation, reference: .standalone(resource: representation.resource)))
convertedRepresentations.append(ImageRepresentationWithReference(representation: representation, reference: .wallpaper(resource: representation.resource)))
}
let dimensions = file.file.dimensions ?? CGSize(width: 100.0, height: 100.0)
self.imageNode.setSignal(chatAvatarGalleryPhoto(account: account, fileReference: .standalone(media: file.file), representations: convertedRepresentations, autoFetchFullSize: true))

View File

@ -33,7 +33,7 @@ public final class ShareProxyServerActionSheetController: ActionSheetController
items.append(ProxyServerQRCodeItem(strings: strings, link: link, ready: { [weak self] in
self?._ready.set(.single(true))
}))
items.append(ActionSheetButtonItem(title: "Share QR Code", action: { [weak self] in
items.append(ActionSheetButtonItem(title: strings.SocksProxySetup_ShareQRCode, action: { [weak self] in
self?.dismissAnimated()
let _ = (qrCode(string: link, color: .black, backgroundColor: .white, scale: 1.0)
|> map { generator -> UIImage? in
@ -47,7 +47,7 @@ public final class ShareProxyServerActionSheetController: ActionSheetController
}
})
}))
items.append(ActionSheetButtonItem(title: "Share Link", action: { [weak self] in
items.append(ActionSheetButtonItem(title: strings.SocksProxySetup_ShareLink, action: { [weak self] in
self?.dismissAnimated()
presentActivityController(link)
}))
@ -105,6 +105,9 @@ private final class ProxyServerQRCodeItemNode: ActionSheetItemNode {
private let ready: () -> Void
private var cachedHasLabel = true
private var cachedHasImage = true
init(theme: ActionSheetControllerTheme, strings: PresentationStrings, link: String, ready: @escaping () -> Void = {}) {
self.theme = theme
self.strings = strings
@ -117,10 +120,10 @@ private final class ProxyServerQRCodeItemNode: ActionSheetItemNode {
self.label.displaysAsynchronously = false
self.label.truncationMode = .byTruncatingTail
self.label.isUserInteractionEnabled = false
self.label.attributedText = NSAttributedString(string: "Your friends can add this proxy by scanning this code with phone or in-app camera.", font: ActionSheetTextNode.defaultFont, textColor: self.theme.secondaryTextColor, paragraphAlignment: .center)
self.label.attributedText = NSAttributedString(string: strings.SocksProxySetup_ShareQRCodeInfo, font: ActionSheetTextNode.defaultFont, textColor: self.theme.secondaryTextColor, paragraphAlignment: .center)
self.imageNode = TransformImageNode()
self.imageNode.setSignal(qrCode(string: link, color: self.theme.primaryTextColor), attemptSynchronously: true)
self.imageNode.setSignal(qrCode(string: link, color: .black, backgroundColor: .white), attemptSynchronously: true)
super.init(theme: theme)
@ -131,16 +134,26 @@ private final class ProxyServerQRCodeItemNode: ActionSheetItemNode {
override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
let imageInset: CGFloat = 44.0
let side = constrainedSize.width - imageInset * 2.0
let imageSize = CGSize(width: side, height: side)
var imageSize = CGSize(width: side, height: side)
let makeLayout = self.imageNode.asyncLayout()
let apply = makeLayout(TransformImageArguments(corners: ImageCorners(), imageSize: imageSize, boundingSize: imageSize, intrinsicInsets: UIEdgeInsets(), emptyColor: nil))
apply()
var labelSize = self.label.measure(CGSize(width: max(1.0, constrainedSize.width - 64.0), height: constrainedSize.height))
self.cachedHasImage = constrainedSize.width < constrainedSize.height
if !self.cachedHasImage {
imageSize = CGSize()
}
self.ready()
let labelSize = self.label.measure(CGSize(width: max(1.0, constrainedSize.width - 64.0), height: constrainedSize.height))
return CGSize(width: constrainedSize.width, height: 14.0 + labelSize.height + 14.0 + constrainedSize.width - 88.0 + 14.0)
self.cachedHasLabel = constrainedSize.height > 480 || !self.cachedHasImage
if !self.cachedHasLabel {
labelSize = CGSize()
}
return CGSize(width: constrainedSize.width, height: 14.0 + (labelSize.height > 0.0 ? labelSize.height + 14.0 : 0.0) + (imageSize.height > 0.0 ? imageSize.height + 14.0 : 8.0))
}
override func layout() {
@ -151,10 +164,21 @@ private final class ProxyServerQRCodeItemNode: ActionSheetItemNode {
let imageInset: CGFloat = 44.0
let spacing: CGFloat = 18.0
let labelSize = self.label.measure(CGSize(width: max(1.0, size.width - inset * 2.0), height: size.height))
self.label.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - labelSize.width) / 2.0), y: spacing), size: labelSize)
let labelSize: CGSize
if self.cachedHasLabel {
labelSize = self.label.measure(CGSize(width: max(1.0, size.width - inset * 2.0), height: size.height))
self.label.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - labelSize.width) / 2.0), y: spacing), size: labelSize)
} else {
labelSize = CGSize()
}
let imageFrame = CGRect(x: imageInset, y: self.label.frame.maxY + spacing - 4.0, width: size.width - imageInset * 2.0, height: size.width - imageInset * 2.0)
self.imageNode.frame = imageFrame
let imageOrigin = CGPoint(x: imageInset, y: self.label.frame.maxY + spacing - 4.0)
var imageSize: CGSize
if !self.cachedHasImage {
imageSize = CGSize()
} else {
imageSize = CGSize(width: size.width - imageInset * 2.0, height: size.width - imageInset * 2.0)
}
self.imageNode.frame = CGRect(origin: imageOrigin, size: imageSize)
}
}

View File

@ -80,7 +80,7 @@ final class StickerPaneSearchBarPlaceholderNode: GridItemNode {
if self.currentState?.0 !== theme || self.currentState?.1 !== strings {
self.backgroundNode.image = generateStretchableFilledCircleImage(diameter: 36.0, color: theme.chat.inputMediaPanel.stickersSearchBackgroundColor)
self.iconNode.image = generateLoupeIcon(color: theme.chat.inputMediaPanel.stickersSearchControlColor)
self.labelNode.attributedText = NSAttributedString(string: strings.Stickers_Search, font: Font.regular(14.0), textColor: theme.chat.inputMediaPanel.stickersSearchPlaceholderColor)
self.labelNode.attributedText = NSAttributedString(string: strings.Stickers_Search, font: Font.regular(17.0), textColor: theme.chat.inputMediaPanel.stickersSearchPlaceholderColor)
}
}
@ -97,7 +97,7 @@ final class StickerPaneSearchBarPlaceholderNode: GridItemNode {
self.labelNode.frame = textFrame
if let iconImage = self.iconNode.image {
self.iconNode.frame = CGRect(origin: CGPoint(x: textFrame.minX - iconImage.size.width - 5.0, y: floorToScreenPixels(textFrame.midY - iconImage.size.height / 2.0)), size: iconImage.size)
self.iconNode.frame = CGRect(origin: CGPoint(x: textFrame.minX - iconImage.size.width - 6.0, y: floorToScreenPixels(textFrame.midY - iconImage.size.height / 2.0)), size: iconImage.size)
}
}

View File

@ -0,0 +1,239 @@
import Foundation
import AsyncDisplayKit
import Postbox
import TelegramCore
import Display
private struct StickersChatInputContextPanelEntryStableId: Hashable {
let text: String
var hashValue: Int {
return self.text.hashValue
}
static func ==(lhs: StickersChatInputContextPanelEntryStableId, rhs: StickersChatInputContextPanelEntryStableId) -> Bool {
return lhs.text == rhs.text
}
}
private struct StickersChatInputContextPanelEntry: Comparable, Identifiable {
let index: Int
let theme: PresentationTheme
let text: String
var stableId: StickersChatInputContextPanelEntryStableId {
return StickersChatInputContextPanelEntryStableId(text: self.text)
}
func withUpdatedTheme(_ theme: PresentationTheme) -> StickersChatInputContextPanelEntry {
return StickersChatInputContextPanelEntry(index: self.index, theme: theme, text: self.text)
}
static func ==(lhs: StickersChatInputContextPanelEntry, rhs: StickersChatInputContextPanelEntry) -> Bool {
return lhs.index == rhs.index && lhs.text == rhs.text && lhs.theme === rhs.theme
}
static func <(lhs: StickersChatInputContextPanelEntry, rhs: StickersChatInputContextPanelEntry) -> Bool {
return lhs.index < rhs.index
}
func item(account: Account, hashtagSelected: @escaping (String) -> Void) -> ListViewItem {
return StickersChatInputPanelItem(theme: self.theme, text: self.text, hashtagSelected: hashtagSelected)
}
}
private struct StickersChatInputContextPanelTransition {
let deletions: [ListViewDeleteItem]
let insertions: [ListViewInsertItem]
let updates: [ListViewUpdateItem]
}
private func preparedTransition(from fromEntries: [StickersChatInputContextPanelEntry], to toEntries: [StickersChatInputContextPanelEntry], account: Account, hashtagSelected: @escaping (String) -> Void) -> StickersChatInputContextPanelTransition {
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, hashtagSelected: hashtagSelected), directionHint: nil) }
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, hashtagSelected: hashtagSelected), directionHint: nil) }
return StickersChatInputContextPanelTransition(deletions: deletions, insertions: insertions, updates: updates)
}
final class StickersChatInputContextPanelNode: ChatInputContextPanelNode {
private let listView: ListView
private var currentEntries: [StickersChatInputContextPanelEntry]?
private var enqueuedTransitions: [(StickersChatInputContextPanelTransition, Bool)] = []
private var validLayout: (CGSize, CGFloat, CGFloat)?
override init(account: Account, theme: PresentationTheme, strings: PresentationStrings) {
self.listView = ListView()
self.listView.isOpaque = false
self.listView.stackFromBottom = true
self.listView.keepBottomItemOverscrollBackground = theme.list.plainBackgroundColor
self.listView.limitHitTestToNodes = true
self.listView.view.disablesInteractiveTransitionGestureRecognizer = true
super.init(account: account, theme: theme, strings: strings)
self.isOpaque = false
self.clipsToBounds = true
self.addSubnode(self.listView)
}
func updateResults(_ results: [String]) {
var entries: [StickersChatInputContextPanelEntry] = []
var index = 0
var stableIds = Set<StickersChatInputContextPanelEntryStableId>()
for text in results {
let entry = StickersChatInputContextPanelEntry(index: index, theme: self.theme, text: text)
if stableIds.contains(entry.stableId) {
continue
}
stableIds.insert(entry.stableId)
entries.append(entry)
index += 1
}
self.prepareTransition(from: self.currentEntries ?? [], to: entries)
}
private func prepareTransition(from: [StickersChatInputContextPanelEntry]? , to: [StickersChatInputContextPanelEntry]) {
let firstTime = from == nil
let transition = preparedTransition(from: from ?? [], to: to, account: self.account, hashtagSelected: { [weak self] text in
})
self.currentEntries = to
self.enqueueTransition(transition, firstTime: firstTime)
}
private func enqueueTransition(_ transition: StickersChatInputContextPanelTransition, firstTime: Bool) {
self.enqueuedTransitions.append((transition, firstTime))
if self.validLayout != nil {
while !self.enqueuedTransitions.isEmpty {
self.dequeueTransition()
}
}
}
private func dequeueTransition() {
if let validLayout = self.validLayout, let (transition, firstTime) = self.enqueuedTransitions.first {
self.enqueuedTransitions.remove(at: 0)
var options = ListViewDeleteAndInsertOptions()
if firstTime {
//options.insert(.Synchronous)
//options.insert(.LowLatency)
} else {
options.insert(.AnimateTopItemPosition)
options.insert(.AnimateCrossfade)
}
var insets = UIEdgeInsets()
insets.top = topInsetForLayout(size: validLayout.0)
insets.left = validLayout.1
insets.right = validLayout.2
let updateSizeAndInsets = ListViewUpdateSizeAndInsets(size: validLayout.0, insets: insets, duration: 0.0, curve: .Default(duration: nil))
self.listView.transaction(deleteIndices: transition.deletions, insertIndicesAndItems: transition.insertions, updateIndicesAndItems: transition.updates, options: options, updateSizeAndInsets: updateSizeAndInsets, updateOpaqueState: nil, completion: { [weak self] _ in
if let strongSelf = self, firstTime {
var topItemOffset: CGFloat?
strongSelf.listView.forEachItemNode { itemNode in
if topItemOffset == nil {
topItemOffset = itemNode.frame.minY
}
}
if let topItemOffset = topItemOffset {
let position = strongSelf.listView.layer.position
strongSelf.listView.layer.animatePosition(from: CGPoint(x: position.x, y: position.y + (strongSelf.listView.bounds.size.height - topItemOffset)), to: position, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring)
}
}
})
}
}
private func topInsetForLayout(size: CGSize) -> CGFloat {
let minimumItemHeights: CGFloat = floor(MentionChatInputPanelItemNode.itemHeight * 3.5)
return max(size.height - minimumItemHeights, 0.0)
}
override func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) {
let hadValidLayout = self.validLayout != nil
self.validLayout = (size, leftInset, rightInset)
var insets = UIEdgeInsets()
insets.top = self.topInsetForLayout(size: size)
insets.left = leftInset
insets.right = rightInset
transition.updateFrame(node: self.listView, frame: CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height))
var duration: Double = 0.0
var curve: UInt = 0
switch transition {
case .immediate:
break
case let .animated(animationDuration, animationCurve):
duration = animationDuration
switch animationCurve {
case .easeInOut:
break
case .spring:
curve = 7
}
}
let listViewCurve: ListViewAnimationCurve
if curve == 7 {
listViewCurve = .Spring(duration: duration)
} else {
listViewCurve = .Default(duration: duration)
}
let updateSizeAndInsets = ListViewUpdateSizeAndInsets(size: size, insets: insets, duration: duration, curve: listViewCurve)
self.listView.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: nil, updateSizeAndInsets: updateSizeAndInsets, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
if !hadValidLayout {
while !self.enqueuedTransitions.isEmpty {
self.dequeueTransition()
}
}
if self.theme !== interfaceState.theme {
self.theme = interfaceState.theme
self.listView.keepBottomItemOverscrollBackground = self.theme.list.plainBackgroundColor
let new = self.currentEntries?.map({$0.withUpdatedTheme(interfaceState.theme)}) ?? []
self.prepareTransition(from: self.currentEntries, to: new)
}
}
override func animateOut(completion: @escaping () -> Void) {
var topItemOffset: CGFloat?
self.listView.forEachItemNode { itemNode in
if topItemOffset == nil {
topItemOffset = itemNode.frame.minY
}
}
if let topItemOffset = topItemOffset {
let position = self.listView.layer.position
self.listView.layer.animatePosition(from: position, to: CGPoint(x: position.x, y: position.y + (self.listView.bounds.size.height - topItemOffset)), duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, completion: { _ in
completion()
})
} else {
completion()
}
}
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
let listViewFrame = self.listView.frame
return self.listView.hitTest(CGPoint(x: point.x - listViewFrame.minX, y: point.y - listViewFrame.minY), with: event)
}
}

View File

@ -0,0 +1,134 @@
import Foundation
import AsyncDisplayKit
import Display
import TelegramCore
import SwiftSignalKit
import Postbox
final class StickersChatInputPanelItem: ListViewItem {
fileprivate let theme: PresentationTheme
fileprivate let text: String
private let hashtagSelected: (String) -> Void
let selectable: Bool = true
public init(theme: PresentationTheme, text: String, hashtagSelected: @escaping (String) -> Void) {
self.theme = theme
self.text = text
self.hashtagSelected = hashtagSelected
}
public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
let configure = { () -> Void in
let node = StickersChatInputPanelItemNode()
let nodeLayout = node.asyncLayout()
let (top, bottom) = (previousItem != nil, nextItem != nil)
let (layout, apply) = nodeLayout(self, params, top, bottom)
node.contentSize = layout.contentSize
node.insets = layout.insets
Queue.mainQueue().async {
completion(node, {
return (nil, { _ in apply(.None) })
})
}
}
if Thread.isMainThread {
async {
configure()
}
} else {
configure()
}
}
public func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) {
Queue.mainQueue().async {
if let nodeValue = node() as? StickersChatInputPanelItemNode {
let nodeLayout = nodeValue.asyncLayout()
async {
let (top, bottom) = (previousItem != nil, nextItem != nil)
let (layout, apply) = nodeLayout(self, params, top, bottom)
Queue.mainQueue().async {
completion(layout, { _ in
apply(animation)
})
}
}
} else {
assertionFailure()
}
}
}
}
private let textFont = Font.medium(14.0)
final class StickersChatInputPanelItemNode: ListViewItemNode {
static let itemHeight: CGFloat = 42.0
private let textNode: TextNode
private let topSeparatorNode: ASDisplayNode
private let highlightedBackgroundNode: ASDisplayNode
init() {
self.textNode = TextNode()
self.topSeparatorNode = ASDisplayNode()
self.topSeparatorNode.isLayerBacked = true
self.highlightedBackgroundNode = ASDisplayNode()
self.highlightedBackgroundNode.isLayerBacked = true
super.init(layerBacked: false, dynamicBounce: false)
self.addSubnode(self.topSeparatorNode)
self.addSubnode(self.textNode)
}
override public func layoutForParams(_ params: ListViewItemLayoutParams, item: ListViewItem, previousItem: ListViewItem?, nextItem: ListViewItem?) {
if let item = item as? StickersChatInputPanelItem {
let doLayout = self.asyncLayout()
let merged = (top: previousItem != nil, bottom: nextItem != nil)
let (layout, apply) = doLayout(item, params, merged.top, merged.bottom)
self.contentSize = layout.contentSize
self.insets = layout.insets
apply(.None)
}
}
func asyncLayout() -> (_ item: StickersChatInputPanelItem, _ params: ListViewItemLayoutParams, _ mergedTop: Bool, _ mergedBottom: Bool) -> (ListViewItemNodeLayout, (ListViewItemUpdateAnimation) -> Void) {
let makeTextLayout = TextNode.asyncLayout(self.textNode)
return { [weak self] item, params, mergedTop, mergedBottom in
let baseWidth = params.width - params.leftInset - params.rightInset
let leftInset: CGFloat = 15.0 + params.leftInset
let rightInset: CGFloat = 10.0 + params.rightInset
let (textLayout, textApply) = makeTextLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "#\(item.text)", font: textFont, textColor: item.theme.list.itemPrimaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - rightInset, height: 100.0), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
let nodeLayout = ListViewItemNodeLayout(contentSize: CGSize(width: params.width, height: HashtagChatInputPanelItemNode.itemHeight), insets: UIEdgeInsets())
return (nodeLayout, { _ in
if let strongSelf = self {
strongSelf.topSeparatorNode.backgroundColor = item.theme.list.itemPlainSeparatorColor
strongSelf.backgroundColor = item.theme.list.plainBackgroundColor
strongSelf.highlightedBackgroundNode.backgroundColor = item.theme.list.itemHighlightedBackgroundColor
let _ = textApply()
strongSelf.textNode.frame = CGRect(origin: CGPoint(x: leftInset, y: floor((nodeLayout.contentSize.height - textLayout.size.height) / 2.0)), size: textLayout.size)
strongSelf.topSeparatorNode.isHidden = mergedTop
strongSelf.topSeparatorNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: params.width, height: UIScreenPixel))
strongSelf.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: params.width, height: nodeLayout.size.height + UIScreenPixel))
}
})
}
}
}

View File

@ -82,7 +82,7 @@ public final class TelegramRootController: NavigationController {
//
// DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.15) {
// //(controller.navigationController as? NavigationController)?.pushViewController(ThemeGridController(account: self.account))
//
//
// let wrapperNode = ASDisplayNode()
// let bounds = controller.displayNode.bounds
// wrapperNode.frame = bounds

View File

@ -45,7 +45,8 @@ private func availableColors() -> [Int32] {
}
private func randomColor() -> Int32 {
return availableColors().randomElement() ?? 0x000000
let colors = availableColors()
return colors[1 ..< colors.count - 1].randomElement() ?? 0x000000
}
final class ThemeColorsGridController: ViewController {
@ -116,9 +117,18 @@ final class ThemeColorsGridController: ViewController {
override func loadDisplayNode() {
self.displayNode = ThemeColorsGridControllerNode(account: self.account, presentationData: self.presentationData, colors: availableColors(), present: { [weak self] controller, arguments in
self?.present(controller, in: .window(.root), with: arguments, blockInteraction: true)
}, pop: { [weak self] in
if let strongSelf = self, let navigationController = strongSelf.navigationController as? NavigationController {
let _ = navigationController.popViewController(animated: true)
}
}, presentColorPicker: { [weak self] in
if let strongSelf = self {
let controller = WallpaperListPreviewController(account: strongSelf.account, source: .customColor(randomColor()))
controller.apply = { _, _, _ in
if let strongSelf = self, let navigationController = strongSelf.navigationController as? NavigationController {
let _ = navigationController.popViewController(animated: true)
}
}
self?.present(controller, in: .window(.root), blockInteraction: true)
}
})

View File

@ -79,7 +79,7 @@ final class ThemeColorsGridControllerNode: ASDisplayNode {
private var disposable: Disposable?
init(account: Account, presentationData: PresentationData, colors: [Int32], present: @escaping (ViewController, Any?) -> Void, presentColorPicker: @escaping () -> Void) {
init(account: Account, presentationData: PresentationData, colors: [Int32], present: @escaping (ViewController, Any?) -> Void, pop: @escaping () -> Void, presentColorPicker: @escaping () -> Void) {
self.account = account
self.presentationData = presentationData
self.present = present
@ -119,7 +119,11 @@ final class ThemeColorsGridControllerNode: ASDisplayNode {
let entries = previousEntries.with { $0 }
if let entries = entries, !entries.isEmpty {
let wallpapers = entries.map { $0.wallpaper }
let controller = WallpaperListPreviewController(account: account, source: .list(wallpapers: wallpapers, central: wallpaper, type: .colors))
let controller = WallpaperGalleryController(account: account, source: .list(wallpapers: wallpapers, central: wallpaper, type: .colors))
controller.apply = { _, _, _ in
pop()
}
//let controller = WallpaperListPreviewController(account: account, source: .list(wallpapers: wallpapers, central: wallpaper, type: .colors))
strongSelf.present(controller, nil)
}
}

View File

@ -206,7 +206,7 @@ class ThemeGalleryController: ViewController {
let toolbarNode = ThemeGalleryToolbarNode(theme: presentationData.theme, strings: presentationData.strings)
self.toolbarNode = toolbarNode
self.galleryNode.addSubnode(toolbarNode)
self.galleryNode.toolbarNode = toolbarNode
//self.galleryNode.toolbarNode = toolbarNode
toolbarNode.cancel = { [weak self] in
self?.dismiss(forceAway: true)
}

View File

@ -49,6 +49,11 @@ final class ThemeGalleryToolbarNode: ASDisplayNode {
self.doneButton.addTarget(self, action: #selector(self.donePressed), forControlEvents: .touchUpInside)
}
func setDoneEnabled(_ enabled: Bool) {
self.doneButton.alpha = enabled ? 1.0 : 0.3
self.doneButton.isUserInteractionEnabled = enabled
}
func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings) {
self.backgroundColor = theme.rootController.tabBar.backgroundColor
self.separatorNode.backgroundColor = theme.rootController.tabBar.separatorColor

View File

@ -64,10 +64,10 @@ final class ThemeGridController: ViewController {
}
})
self.searchContentNode = NavigationBarSearchContentNode(theme: self.presentationData.theme, placeholder: self.presentationData.strings.Wallpaper_Search, activate: { [weak self] in
self?.activateSearch()
})
self.navigationBar?.setContentNode(self.searchContentNode, animated: false)
// self.searchContentNode = NavigationBarSearchContentNode(theme: self.presentationData.theme, placeholder: self.presentationData.strings.Wallpaper_Search, activate: { [weak self] in
// self?.activateSearch()
// })
// self.navigationBar?.setContentNode(self.searchContentNode, animated: false)
}
required public init(coder aDecoder: NSCoder) {
@ -84,11 +84,11 @@ final class ThemeGridController: ViewController {
if let isEmpty = self.isEmpty, isEmpty {
} else {
if self.editingMode {
self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Done, style: .done, target: self, action: #selector(self.donePressed))
} else {
self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Edit, style: .plain, target: self, action: #selector(self.editPressed))
}
// if self.editingMode {
// self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Done, style: .done, target: self, action: #selector(self.donePressed))
// } else {
// self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Edit, style: .plain, target: self, action: #selector(self.editPressed))
// }
}
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBar.style.style
@ -103,19 +103,19 @@ final class ThemeGridController: ViewController {
override func loadDisplayNode() {
self.displayNode = ThemeGridControllerNode(account: self.account, presentationData: self.presentationData, presentPreviewController: { [weak self] source in
if let strongSelf = self {
//let controller = WallpaperGalleryController(account: strongSelf.account, source: source)
//self?.present(controller, in: .window(.root), with: nil, blockInteraction: true)
let controller = WallpaperListPreviewController(account: strongSelf.account, source: source)
controller.apply = { [weak self, weak controller] wallpaper, mode, cropRect in
if let strongSelf = self {
strongSelf.uploadCustomWallpaper(wallpaper, mode: mode, cropRect: cropRect)
if case .wallpaper = wallpaper {
} else if let controller = controller {
controller.dismiss()
}
}
}
let controller = WallpaperGalleryController(account: strongSelf.account, source: source)
self?.present(controller, in: .window(.root), with: nil, blockInteraction: true)
// let controller = WallpaperListPreviewController(account: strongSelf.account, source: source)
// controller.apply = { [weak self, weak controller] wallpaper, mode, cropRect in
// if let strongSelf = self {
// strongSelf.uploadCustomWallpaper(wallpaper, mode: mode, cropRect: cropRect)
// if case .wallpaper = wallpaper {
// } else if let controller = controller {
// controller.dismiss()
// }
// }
// }
// self?.present(controller, in: .window(.root), with: nil, blockInteraction: true)
}
}, presentGallery: { [weak self] in
if let strongSelf = self {
@ -132,11 +132,12 @@ final class ThemeGridController: ViewController {
let controller = WallpaperListPreviewController(account: strongSelf.account, source: .asset(asset.backingAsset, thumbnailImage))
controller.apply = { [weak self, weak legacyController, weak controller] wallpaper, mode, cropRect in
if let strongSelf = self, let legacyController = legacyController, let controller = controller {
strongSelf.uploadCustomWallpaper(wallpaper, mode: mode, cropRect: cropRect)
let _ = (strongSelf.navigationController as? NavigationController)?.popViewController(animated: true)
legacyController.dismiss()
controller.dismiss()
strongSelf.uploadCustomWallpaper(wallpaper, mode: mode, cropRect: cropRect, completion: { [weak legacyController, weak controller] in
if let legacyController = legacyController, let controller = controller {
legacyController.dismiss()
controller.dismiss()
}
})
}
}
strongSelf.present(controller, in: .window(.root), with: nil, blockInteraction: true)
@ -164,11 +165,11 @@ final class ThemeGridController: ViewController {
if empty {
strongSelf.navigationItem.setRightBarButton(nil, animated: true)
} else {
if strongSelf.editingMode {
strongSelf.navigationItem.rightBarButtonItem = UIBarButtonItem(title: strongSelf.presentationData.strings.Common_Done, style: .done, target: strongSelf, action: #selector(strongSelf.donePressed))
} else {
strongSelf.navigationItem.rightBarButtonItem = UIBarButtonItem(title: strongSelf.presentationData.strings.Common_Edit, style: .plain, target: strongSelf, action: #selector(strongSelf.editPressed))
}
// if strongSelf.editingMode {
// strongSelf.navigationItem.rightBarButtonItem = UIBarButtonItem(title: strongSelf.presentationData.strings.Common_Done, style: .done, target: strongSelf, action: #selector(strongSelf.donePressed))
// } else {
// strongSelf.navigationItem.rightBarButtonItem = UIBarButtonItem(title: strongSelf.presentationData.strings.Common_Edit, style: .plain, target: strongSelf, action: #selector(strongSelf.editPressed))
// }
}
}
}
@ -238,13 +239,13 @@ final class ThemeGridController: ViewController {
self.displayNodeDidLoad()
}
private func uploadCustomWallpaper(_ wallpaper: WallpaperEntry, mode: WallpaperPresentationOptions, cropRect: CGRect?) {
private func uploadCustomWallpaper(_ wallpaper: WallpaperEntry, mode: WallpaperPresentationOptions, cropRect: CGRect?, completion: @escaping () -> Void) {
let imageSignal: Signal<UIImage, NoError>
switch wallpaper {
case .wallpaper:
imageSignal = .complete()
case let .asset(asset, _):
imageSignal = fetchPhotoLibraryImage(localIdentifier: asset.localIdentifier)
imageSignal = fetchPhotoLibraryImage(localIdentifier: asset.localIdentifier, thumbnail: false)
|> filter { value in
return !(value?.1 ?? true)
}
@ -311,29 +312,31 @@ final class ThemeGridController: ViewController {
})).start()
}
let completion: () -> Void = {
let wallpaper: TelegramWallpaper = .image([TelegramMediaImageRepresentation(dimensions: image.size, resource: resource)])
let apply: () -> Void = {
let wallpaper: TelegramWallpaper = .image([TelegramMediaImageRepresentation(dimensions: croppedImage.size, resource: resource)])
updateWallpaper(wallpaper)
let _ = uploadWallpaper(account: account, resource: resource).start(next: { status in
if case let .complete(wallpaper) = status {
if mode.contains(.blur), case let .file(_, _, _, _, _, file) = wallpaper {
let _ = account.postbox.mediaBox.cachedResourceRepresentation(file.resource, representation: CachedBlurredWallpaperRepresentation(), complete: true, fetch: true).start(completed: {
updateWallpaper(wallpaper)
})
} else {
updateWallpaper(wallpaper)
}
}
})
DispatchQueue.main.async {
completion()
}
// let _ = uploadWallpaper(account: account, resource: resource).start(next: { status in
// if case let .complete(wallpaper) = status {
// if mode.contains(.blur), case let .file(_, _, _, _, _, file) = wallpaper {
// let _ = account.postbox.mediaBox.cachedResourceRepresentation(file.resource, representation: CachedBlurredWallpaperRepresentation(), complete: true, fetch: true).start(completed: {
// updateWallpaper(wallpaper)
// })
// } else {
// updateWallpaper(wallpaper)
// }
// }
// }).start()
}
if mode.contains(.blur) {
let _ = account.postbox.mediaBox.cachedResourceRepresentation(resource, representation: CachedBlurredWallpaperRepresentation(), complete: true, fetch: true).start(completed: {
completion()
apply()
})
} else {
completion()
apply()
}
}

View File

@ -233,7 +233,7 @@ final class ThemeGridControllerNode: ASDisplayNode {
self.gridNode.addSubnode(self.separatorNode)
self.gridNode.addSubnode(self.colorItemNode)
self.gridNode.addSubnode(self.galleryItemNode)
self.gridNode.addSubnode(self.descriptionItemNode)
//self.gridNode.addSubnode(self.descriptionItemNode)
self.addSubnode(self.gridNode)
let wallpapersPromise: Promise<[TelegramWallpaper]> = Promise()
@ -471,7 +471,7 @@ final class ThemeGridControllerNode: ASDisplayNode {
let buttonTopInset: CGFloat = 32.0
let buttonHeight: CGFloat = 44.0
let buttonBottomInset: CGFloat = descriptionLayout.contentSize.height + 17.0
let buttonBottomInset: CGFloat = 35.0 //descriptionLayout.contentSize.height + 17.0
let buttonInset: CGFloat = buttonTopInset + buttonHeight * 2.0 + buttonBottomInset
let buttonOffset = buttonInset + 10.0

View File

@ -244,6 +244,9 @@ final class WallpaperColorPickerNode: ASDisplayNode {
let colorPanRecognizer = UIPanGestureRecognizer(target: self, action: #selector(WallpaperColorPickerNode.colorPan))
self.colorNode.view.addGestureRecognizer(colorPanRecognizer)
let colorTapRecognizer = UITapGestureRecognizer(target: self, action: #selector(WallpaperColorPickerNode.colorTap))
self.colorNode.view.addGestureRecognizer(colorTapRecognizer)
let brightnessPanRecognizer = UIPanGestureRecognizer(target: self, action: #selector(WallpaperColorPickerNode.brightnessPan))
self.brightnessNode.view.addGestureRecognizer(brightnessPanRecognizer)
}
@ -286,6 +289,23 @@ final class WallpaperColorPickerNode: ASDisplayNode {
self.updateKnobLayout(size: size, panningColor: false, transition: transition)
}
@objc private func colorTap(_ recognizer: UITapGestureRecognizer) {
guard let size = self.validLayout, recognizer.state == .recognized else {
return
}
let location = recognizer.location(in: recognizer.view)
let newHue = max(0.0, min(1.0, location.x / size.width))
let newSaturation = max(0.0, min(1.0, (1.0 - location.y / (size.height - 66.0))))
self.colorHSV.0 = newHue
self.colorHSV.1 = newSaturation
self.updateKnobLayout(size: size, panningColor: false, transition: .immediate)
self.update()
self.colorChanged?(self.color)
}
@objc private func colorPan(_ recognizer: UIPanGestureRecognizer) {
guard let size = self.validLayout else {
return
@ -307,7 +327,7 @@ final class WallpaperColorPickerNode: ASDisplayNode {
switch recognizer.state {
case .began:
self.updateKnobLayout(size: size, panningColor: true, transition: .animated(duration: 0.3, curve: .easeInOut))
self.updateKnobLayout(size: size, panningColor: true, transition: .immediate)
case .changed:
self.updateKnobLayout(size: size, panningColor: true, transition: .immediate)
recognizer.setTranslation(CGPoint(), in: recognizer.view)

View File

@ -50,6 +50,17 @@ enum WallpaperGalleryEntry: Equatable {
}
}
class WallpaperGalleryOverlayNode: ASDisplayNode {
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
let result = super.hitTest(point, with: event)
if result != self.view {
return result
} else {
return nil
}
}
}
class WallpaperGalleryController: ViewController {
private var galleryNode: GalleryControllerNode {
return self.displayNode as! GalleryControllerNode
@ -57,7 +68,7 @@ class WallpaperGalleryController: ViewController {
private let account: Account
private let source: WallpaperListSource
var apply: ((WallpaperEntry, WallpaperPresentationOptions, CGRect?) -> Void)?
var apply: ((WallpaperGalleryEntry, WallpaperPresentationOptions, CGRect?) -> Void)?
private let _ready = Promise<Bool>()
override var ready: Promise<Bool> {
@ -79,6 +90,8 @@ class WallpaperGalleryController: ViewController {
private var validLayout: (ContainerViewLayout, CGFloat)?
private var overlayNode: WallpaperGalleryOverlayNode?
private var messageNodes: [ListViewItemNode]?
private var toolbarNode: ThemeGalleryToolbarNode?
init(account: Account, source: WallpaperListSource) {
@ -119,24 +132,6 @@ class WallpaperGalleryController: ViewController {
self.centralEntryIndex = 0
}
// let initialEntries: [ThemeGalleryEntry] = wallpapers.map { ThemeGalleryEntry.wallpaper($0) }
// let entriesSignal: Signal<[ThemeGalleryEntry], NoError> = .single(initialEntries)
//
// self.disposable.set((entriesSignal |> deliverOnMainQueue).start(next: { [weak self] entries in
// if let strongSelf = self {
// strongSelf.entries = entries
// strongSelf.centralEntryIndex = wallpapers.index(of: centralWallpaper)!
// if strongSelf.isViewLoaded {
// strongSelf.galleryNode.pager.replaceItems(strongSelf.entries.map({ ThemeGalleryItem(account: account, entry: $0) }), centralItemIndex: strongSelf.centralEntryIndex, keepFirst: true)
//
// let ready = strongSelf.galleryNode.pager.ready() |> timeout(2.0, queue: Queue.mainQueue(), alternate: .single(Void())) |> afterNext { [weak strongSelf] _ in
// strongSelf?.didSetReady = true
// }
// strongSelf._ready.set(ready |> map { true })
// }
// }
// }))
self.presentationDataDisposable = (account.telegramApplicationContext.presentationData
|> deliverOnMainQueue).start(next: { [weak self] presentationData in
if let strongSelf = self {
@ -150,15 +145,18 @@ class WallpaperGalleryController: ViewController {
}
})
//self.centralItemAttributesDisposable.add(self.centralItemTitleView.get().start(next: { [weak self] titleView in
// self?.navigationItem.titleView = titleView
//}))
// self.centralItemAttributesDisposable.add(self.centralItemFooterContentNode.get().start(next: { [weak self] footerContentNode in
// self?.galleryNode.updatePresentationState({
// $0.withUpdatedFooterContentNode(footerContentNode)
// }, transition: .immediate)
// }))
self.centralItemAttributesDisposable.add(self.centralItemStatus.get().start(next: { [weak self] status in
if let strongSelf = self {
let enabled: Bool
switch status {
case .Local:
enabled = true
default:
enabled = false
}
strongSelf.toolbarNode?.setDoneEnabled(enabled)
}
}))
}
required init(coder aDecoder: NSCoder) {
@ -177,16 +175,12 @@ class WallpaperGalleryController: ViewController {
self.toolbarNode?.updateThemeAndStrings(theme: self.presentationData.theme, strings: self.presentationData.strings)
}
@objc func donePressed() {
self.dismiss(forceAway: false)
}
private func dismiss(forceAway: Bool) {
let completion = { [weak self] in
let completion: () -> Void = { [weak self] in
self?.presentingViewController?.dismiss(animated: false, completion: nil)
}
//self.galleryNode.modalAnimateOut(completion: completion)
self.galleryNode.modalAnimateOut(completion: completion)
}
override func loadDisplayNode() {
@ -203,27 +197,14 @@ class WallpaperGalleryController: ViewController {
self.galleryNode.statusBar = self.statusBar
self.galleryNode.navigationBar = self.navigationBar
self.galleryNode.transitionDataForCentralItem = { [weak self] in
// if let strongSelf = self {
// if let centralItemNode = strongSelf.galleryNode.pager.centralItemNode(), let presentationArguments = strongSelf.presentationArguments as? ThemePreviewControllerPresentationArguments {
// if let transitionArguments = presentationArguments.transitionArguments(strongSelf.entries[centralItemNode.index]) {
// return (transitionArguments.transitionNode, transitionArguments.addToTransitionSurface)
// }
// }
// }
return nil
}
self.galleryNode.dismiss = { [weak self] in
self?.presentingViewController?.dismiss(animated: false, completion: nil)
}
self.galleryNode.pager.centralItemIndexUpdated = { [weak self] index in
if let strongSelf = self {
if let index = index {
if let node = strongSelf.galleryNode.pager.centralItemNode() {
//strongSelf.centralItemTitle.set(node.title())
}
if let node = strongSelf.galleryNode.pager.centralItemNode() as? WallpaperGalleryItemNode {
strongSelf.centralItemStatus.set(node.status.get())
}
}
}
@ -234,29 +215,36 @@ class WallpaperGalleryController: ViewController {
let presentationData = self.account.telegramApplicationContext.currentPresentationData.with { $0 }
let toolbarNode = ThemeGalleryToolbarNode(theme: presentationData.theme, strings: presentationData.strings)
let overlayNode = WallpaperGalleryOverlayNode()
self.overlayNode = overlayNode
self.galleryNode.overlayNode = overlayNode
self.galleryNode.addSubnode(overlayNode)
self.toolbarNode = toolbarNode
self.galleryNode.addSubnode(toolbarNode)
self.galleryNode.toolbarNode = toolbarNode
overlayNode.addSubnode(toolbarNode)
toolbarNode.cancel = { [weak self] in
//self?.dismiss(forceAway: true)
self?.dismiss(forceAway: true)
}
toolbarNode.done = { [weak self] in
// if let strongSelf = self {
// if let centralItemNode = strongSelf.galleryNode.pager.centralItemNode() {
// if !strongSelf.entries.isEmpty {
// let wallpaper: TelegramWallpaper
// switch strongSelf.entries[centralItemNode.index] {
// case let .wallpaper(value):
// wallpaper = value
// }
// let _ = (updatePresentationThemeSettingsInteractively(postbox: strongSelf.account.postbox, { current in
// return PresentationThemeSettings(chatWallpaper: wallpaper, chatWallpaperOptions: [], theme: current.theme, themeAccentColor: current.themeAccentColor, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, disableAnimations: current.disableAnimations)
// }) |> deliverOnMainQueue).start(completed: {
// self?.dismiss(forceAway: true)
// })
// }
// }
// }
if let strongSelf = self {
if let centralItemNode = strongSelf.galleryNode.pager.centralItemNode() {
if !strongSelf.entries.isEmpty {
let entry = strongSelf.entries[centralItemNode.index]
switch entry {
case let .wallpaper(wallpaper):
let _ = (updatePresentationThemeSettingsInteractively(postbox: strongSelf.account.postbox, { current in
return PresentationThemeSettings(chatWallpaper: wallpaper, chatWallpaperOptions: [], theme: current.theme, themeAccentColor: current.themeAccentColor, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, disableAnimations: current.disableAnimations)
}) |> deliverOnMainQueue).start(completed: {
self?.dismiss(forceAway: true)
})
default:
break
}
strongSelf.apply?(entry, [], nil)
}
}
}
}
let ready = self.galleryNode.pager.ready() |> timeout(2.0, queue: Queue.mainQueue(), alternate: .single(Void())) |> afterNext { [weak self] _ in
@ -276,10 +264,129 @@ class WallpaperGalleryController: ViewController {
self.galleryNode.frame = CGRect(origin: CGPoint(), size: layout.size)
self.galleryNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationHeight, transition: transition)
self.overlayNode?.frame = self.galleryNode.bounds
var items: [ChatMessageItem] = []
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: 1)
let otherPeerId = self.account.peerId
var peers = SimpleDictionary<PeerId, Peer>()
let messages = SimpleDictionary<MessageId, Message>()
peers[peerId] = TelegramUser(id: peerId, accessHash: nil, firstName: self.presentationData.strings.Appearance_PreviewReplyAuthor, lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])
peers[otherPeerId] = TelegramUser(id: otherPeerId, accessHash: nil, firstName: self.presentationData.strings.Appearance_PreviewReplyAuthor, lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])
let controllerInteraction = ChatControllerInteraction(openMessage: { _, _ in
return false }, openPeer: { _, _, _ in }, openPeerMention: { _ in }, openMessageContextMenu: { _, _, _, _ in }, navigateToMessage: { _, _ in }, clickThroughMessage: { }, toggleMessagesSelection: { _, _ in }, sendMessage: { _ in }, sendSticker: { _, _ in }, sendGif: { _ in }, requestMessageActionCallback: { _, _, _ in }, activateSwitchInline: { _, _ in }, openUrl: { _, _, _ in }, shareCurrentLocation: {}, shareAccountContact: {}, sendBotCommand: { _, _ in }, openInstantPage: { _ in }, openWallpaper: { _ in }, openHashtag: { _, _ in }, updateInputState: { _ in }, updateInputMode: { _ in }, openMessageShareMenu: { _ in
}, presentController: { _, _ in }, navigationController: {
return nil
}, presentGlobalOverlayController: { _, _ in }, callPeer: { _ in }, longTap: { _ in }, openCheckoutOrReceipt: { _ in }, openSearch: { }, setupReply: { _ in
}, canSetupReply: { _ in
return false
}, navigateToFirstDateMessage: { _ in
}, requestRedeliveryOfFailedMessages: { _ in
}, addContact: { _ in
}, rateCall: { _, _ in
}, requestSelectMessagePollOption: { _, _ in
}, openAppStorePage: {
}, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: AutomaticMediaDownloadSettings.defaultSettings,
pollActionState: ChatInterfacePollActionState())
let chatPresentationData = ChatPresentationData(theme: ChatPresentationThemeData(theme: self.presentationData.theme, wallpaper: self.presentationData.chatWallpaper), fontSize: self.presentationData.fontSize, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder, disableAnimations: false)
let topMessageText: String
let bottomMessageText: String
switch self.source {
case .wallpaper, .slug:
topMessageText = presentationData.strings.WallpaperPreview_PreviewTopText
bottomMessageText = presentationData.strings.WallpaperPreview_PreviewBottomText
case let .list(_, _, type):
switch type {
case .wallpapers:
topMessageText = presentationData.strings.WallpaperPreview_SwipeTopText
bottomMessageText = presentationData.strings.WallpaperPreview_SwipeBottomText
case .colors:
topMessageText = presentationData.strings.WallpaperPreview_SwipeColorsTopText
bottomMessageText = presentationData.strings.WallpaperPreview_SwipeColorsBottomText
}
case .asset, .contextResult:
topMessageText = presentationData.strings.WallpaperPreview_CropTopText
bottomMessageText = presentationData.strings.WallpaperPreview_CropBottomText
case .customColor:
topMessageText = presentationData.strings.WallpaperPreview_CustomColorTopText
bottomMessageText = presentationData.strings.WallpaperPreview_CustomColorBottomText
}
items.append(ChatMessageItem(presentationData: chatPresentationData, account: self.account, chatLocation: .peer(peerId), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .contact, automaticDownloadNetworkType: .cellular, isRecentActions: false), controllerInteraction: controllerInteraction, content: .message(message: Message(stableId: 2, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 2), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66001, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: bottomMessageText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), read: true, selection: .none, isAdmin: false), disableDate: true))
items.append(ChatMessageItem(presentationData: chatPresentationData, account: self.account, chatLocation: .peer(peerId), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .contact, automaticDownloadNetworkType: .cellular, isRecentActions: false), controllerInteraction: controllerInteraction, content: .message(message: Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: topMessageText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), read: true, selection: .none, isAdmin: false), disableDate: true))
let params = ListViewItemLayoutParams(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right)
if let messageNodes = self.messageNodes {
for i in 0 ..< items.count {
let itemNode = messageNodes[i]
items[i].updateNode(async: { $0() }, node: {
return itemNode
}, params: params, previousItem: i == 0 ? nil : items[i - 1], nextItem: i == (items.count - 1) ? nil : items[i + 1], animation: .None, completion: { (layout, apply) in
let nodeFrame = CGRect(origin: itemNode.frame.origin, size: CGSize(width: layout.size.width, height: layout.size.height))
itemNode.contentSize = layout.contentSize
itemNode.insets = layout.insets
itemNode.frame = nodeFrame
itemNode.isUserInteractionEnabled = false
apply(ListViewItemApply(isOnScreen: true))
})
}
} else {
var messageNodes: [ListViewItemNode] = []
for i in 0 ..< items.count {
var itemNode: ListViewItemNode?
items[i].nodeConfiguredForParams(async: { $0() }, params: params, synchronousLoads: false, previousItem: i == 0 ? nil : items[i - 1], nextItem: i == (items.count - 1) ? nil : items[i + 1], completion: { node, apply in
itemNode = node
apply().1(ListViewItemApply(isOnScreen: true))
})
itemNode!.subnodeTransform = CATransform3DMakeRotation(CGFloat.pi, 0.0, 0.0, 1.0)
itemNode!.isUserInteractionEnabled = false
messageNodes.append(itemNode!)
self.overlayNode?.addSubnode(itemNode!)
}
self.messageNodes = messageNodes
}
var bottomInset = layout.intrinsicInsets.bottom + 49.0
var optionsAvailable = true
if let centralItemNode = self.galleryNode.pager.centralItemNode() {
if !self.entries.isEmpty {
let entry = self.entries[centralItemNode.index]
switch entry {
case let .wallpaper(wallpaper):
switch wallpaper {
case .color:
optionsAvailable = false
default:
break
}
default:
break
}
}
}
transition.updateFrame(node: self.toolbarNode!, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - 49.0 - layout.intrinsicInsets.bottom), size: CGSize(width: layout.size.width, height: 49.0 + layout.intrinsicInsets.bottom)))
self.toolbarNode!.updateLayout(size: CGSize(width: layout.size.width, height: 49.0), layout: layout, transition: transition)
if let messageNodes = self.messageNodes {
var bottomOffset: CGFloat = layout.size.height - bottomInset - 9.0
// if optionsAvailable {
// bottomOffset -= segmentedControlSize.height + 37.0
// }
for itemNode in messageNodes {
transition.updateFrame(node: itemNode, frame: CGRect(origin: CGPoint(x: 0.0, y: bottomOffset - itemNode.frame.height), size: itemNode.frame.size))
bottomOffset -= itemNode.frame.height
}
}
let replace = self.validLayout == nil
self.validLayout = (layout, 0.0)

View File

@ -116,7 +116,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
case let .wallpaper(wallpaper):
switch wallpaper {
case .builtin:
displaySize = CGSize(width: 640.0, height: 1136.0)
displaySize = CGSize(width: 1308.0, height: 2688.0).fitted(CGSize(width: 1280.0, height: 1280.0)).dividedByScreenScale().integralFloor
contentSize = displaySize
signal = settingsBuiltinWallpaperImage(account: account)
fetchSignal = .complete()
@ -135,10 +135,10 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
var convertedRepresentations: [ImageRepresentationWithReference] = []
for representation in file.file.previewRepresentations {
convertedRepresentations.append(ImageRepresentationWithReference(representation: representation, reference: .standalone(resource: representation.resource)))
convertedRepresentations.append(ImageRepresentationWithReference(representation: representation, reference: .wallpaper(resource: representation.resource)))
}
convertedRepresentations.append(ImageRepresentationWithReference(representation: .init(dimensions: dimensions, resource: file.file.resource), reference: .standalone(resource: file.file.resource)))
signal = chatMessageImageFile(account: account, fileReference: .standalone(media: file.file), thumbnail: false)
convertedRepresentations.append(ImageRepresentationWithReference(representation: .init(dimensions: dimensions, resource: file.file.resource), reference: .wallpaper(resource: file.file.resource)))
signal = chatAvatarGalleryPhoto(account: account, fileReference: .standalone(media: file.file), representations: convertedRepresentations, alwaysShowThumbnailFirst: true, autoFetchFullSize: false)
fetchSignal = fetchedMediaResource(postbox: account.postbox, reference: convertedRepresentations[convertedRepresentations.count - 1].reference)
statusSignal = account.postbox.mediaBox.resourceStatus(file.file.resource)
case let .image(representations):
@ -276,7 +276,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
controlsColorSignal = backgroundContrastColor(for: imagePromise.get())
}
self.controlsColor.set(.single(.white) |> then(controlsColorSignal))
self.status.set(statusSignal)
self.status.set(statusSignal |> deliverOnMainQueue)
}
}

View File

@ -55,7 +55,7 @@ final class WallpaperListPreviewController: ViewController {
})
self.title = self.presentationData.strings.WallpaperPreview_Title
self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionAction"), color: self.presentationData.theme.rootController.navigationBar.accentTextColor), style: .plain, target: self, action: #selector(self.sharePressed))
//self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionAction"), color: self.presentationData.theme.rootController.navigationBar.accentTextColor), style: .plain, target: self, action: #selector(self.sharePressed))
}
required init(coder aDecoder: NSCoder) {
@ -166,7 +166,7 @@ final class WallpaperListPreviewController: ViewController {
} else {
strongSelf.wallpaper = nil
}
strongSelf.navigationItem.rightBarButtonItem = barButtonItem
//strongSelf.navigationItem.rightBarButtonItem = barButtonItem
})
}

View File

@ -719,23 +719,23 @@ final class WallpaperListPreviewControllerNode: ViewControllerTracingNode {
self.colorPanelNode.updateLayout(size: colorPanelFrame.size, keyboardHeight: layout.inputHeight ?? 0.0, transition: transition)
bottomInset += height
}
var optionsAvailable = true
if let centralWallpaper = self.centralWallpaper {
switch centralWallpaper {
case let .wallpaper(wallpaper):
switch wallpaper {
case .color:
optionsAvailable = false
default:
break
}
default:
break
}
}
let optionsAvailable = false //true
// if let centralWallpaper = self.centralWallpaper {
// switch centralWallpaper {
// case let .wallpaper(wallpaper):
// switch wallpaper {
// case .color:
// optionsAvailable = false
// default:
// break
// }
// default:
// break
// }
// }
var segmentedControlSize = self.segmentedControl.sizeThatFits(layout.size)
segmentedControlSize.width = max(270.0, segmentedControlSize.width)
@ -875,6 +875,7 @@ final class WallpaperListPreviewControllerNode: ViewControllerTracingNode {
break
}
self.apply(wallpaper, options, self.centralNode()?.cropRect)
self.isUserInteractionEnabled = false
}
}
}