Various Fixes

This commit is contained in:
Ilya Laktyushin 2021-06-25 15:40:14 +04:00
parent f8890b9734
commit 80426cdf8f
14 changed files with 376 additions and 342 deletions

View File

@ -361,7 +361,7 @@ public final class DeviceAccess {
switch status {
case .restricted, .denied, .notDetermined:
value = false
case .authorized:
case .authorized, .limited:
value = true
@unknown default:
fatalError()
@ -416,8 +416,6 @@ public final class DeviceAccess {
locationManager?.requestAlwaysAuthorization(completion: { status in
completion(status == .authorizedAlways)
})
default:
break
}
@unknown default:
fatalError()

View File

@ -2,6 +2,12 @@ import Foundation
import UIKit
import Postbox
enum StickerVerificationStatus {
case loading
case verified
case declined
}
public class ImportStickerPack {
public class Sticker: Equatable {
public enum Content {
@ -32,6 +38,14 @@ public class ImportStickerPack {
return data
}
}
var isAnimated: Bool {
if case .animation = self.content {
return true
} else {
return false
}
}
}
public let software: String

View File

@ -29,8 +29,8 @@ public final class ImportStickerPackController: ViewController, StandalonePresen
private let stickerPack: ImportStickerPack
private var presentationDataDisposable: Disposable?
private var verificationDisposable: Disposable?
public init(context: AccountContext, stickerPack: ImportStickerPack, parentNavigationController: NavigationController?) {
self.context = context
self.parentNavigationController = parentNavigationController
@ -57,6 +57,7 @@ public final class ImportStickerPackController: ViewController, StandalonePresen
deinit {
self.presentationDataDisposable?.dispose()
self.verificationDisposable?.dispose()
}
override public func loadDisplayNode() {
@ -77,8 +78,65 @@ public final class ImportStickerPackController: ViewController, StandalonePresen
self.controllerNode.navigationController = self.parentNavigationController
Queue.mainQueue().after(0.1) {
self.controllerNode.updateStickerPack(self.stickerPack)
self.controllerNode.updateStickerPack(self.stickerPack, verifiedStickers: Set(), declinedStickers: Set(), uploadedStickerResources: [:])
if self.stickerPack.isAnimated {
let _ = (self.context.account.postbox.loadedPeerWithId(self.context.account.peerId)
|> deliverOnMainQueue).start(next: { [weak self] peer in
guard let strongSelf = self else {
return
}
var signals: [Signal<(UUID, StickerVerificationStatus, MediaResource?), NoError>] = []
for sticker in strongSelf.stickerPack.stickers {
if let resource = strongSelf.controllerNode.stickerResources[sticker.uuid] {
signals.append(strongSelf.context.engine.stickers.uploadSticker(peer: peer, resource: resource, alt: sticker.emojis.first ?? "", dimensions: PixelDimensions(width: 512, height: 512), isAnimated: true)
|> map { result -> (UUID, StickerVerificationStatus, MediaResource?) in
switch result {
case .progress:
return (sticker.uuid, .loading, nil)
case let .complete(resource, mimeType):
if mimeType == "application/x-tgsticker" {
return (sticker.uuid, .verified, resource)
} else {
return (sticker.uuid, .declined, nil)
}
}
}
|> `catch` { _ -> Signal<(UUID, StickerVerificationStatus, MediaResource?), NoError> in
return .single((sticker.uuid, .declined, nil))
})
}
}
strongSelf.verificationDisposable = (combineLatest(signals)
|> deliverOnMainQueue).start(next: { [weak self] results in
guard let strongSelf = self else {
return
}
var verifiedStickers = Set<UUID>()
var declinedStickers = Set<UUID>()
var uploadedStickerResources: [UUID: MediaResource] = [:]
for (uuid, result, resource) in results {
switch result {
case .verified:
if let resource = resource {
verifiedStickers.insert(uuid)
uploadedStickerResources[uuid] = resource
} else {
declinedStickers.insert(uuid)
}
case .declined:
declinedStickers.insert(uuid)
case .loading:
break
}
}
strongSelf.controllerNode.updateStickerPack(strongSelf.stickerPack, verifiedStickers: verifiedStickers, declinedStickers: declinedStickers, uploadedStickerResources: uploadedStickerResources)
})
})
}
}
self.ready.set(self.controllerNode.ready.get())
}

View File

@ -17,13 +17,13 @@ import RadialStatusNode
import UndoUI
import StickerPackPreviewUI
private struct StickerPackPreviewGridEntry: Comparable, Identifiable {
private struct StickerPackPreviewGridEntry: Comparable, Equatable, Identifiable {
let index: Int
let stickerItem: ImportStickerPack.Sticker
let isVerified: Bool
var stableId: Int {
return self.index
// return self.stickerItem.file.fileId
}
static func <(lhs: StickerPackPreviewGridEntry, rhs: StickerPackPreviewGridEntry) -> Bool {
@ -31,8 +31,10 @@ private struct StickerPackPreviewGridEntry: Comparable, Identifiable {
}
func item(account: Account, interaction: StickerPackPreviewInteraction, theme: PresentationTheme) -> StickerPackPreviewGridItem {
return StickerPackPreviewGridItem(account: account, stickerItem: self.stickerItem, interaction: interaction, theme: theme, isEmpty: false)
return StickerPackPreviewGridItem(account: account, stickerItem: self.stickerItem, interaction: interaction, theme: theme, isVerified: self.isVerified)
}
}
private struct StickerPackPreviewGridTransaction {
@ -53,6 +55,9 @@ final class ImportStickerPackControllerNode: ViewControllerTracingNode, UIScroll
private let context: AccountContext
private var presentationData: PresentationData
private var stickerPack: ImportStickerPack?
var stickerResources: [UUID: MediaResource] = [:]
private var uploadedStickerResources: [UUID: MediaResource] = [:]
private var stickerPackReady = true
private var containerLayout: (ContainerViewLayout, CGFloat)?
@ -130,6 +135,7 @@ final class ImportStickerPackControllerNode: ViewControllerTracingNode, UIScroll
self.contentTitleNode = ImmediateTextNode()
self.contentTitleNode.displaysAsynchronously = false
self.contentTitleNode.maximumNumberOfLines = 1
self.contentTitleNode.alpha = 0.0
self.contentSeparatorNode = ASDisplayNode()
self.contentSeparatorNode.isLayerBacked = true
@ -205,6 +211,8 @@ final class ImportStickerPackControllerNode: ViewControllerTracingNode, UIScroll
self.wrappingScrollNode.addSubnode(self.progressText)
self.wrappingScrollNode.addSubnode(self.infoText)
self.installActionButtonNode.setTitle(self.presentationData.strings.ImportStickerPack_CreateStickerSet, with: Font.regular(20.0), with: self.presentationData.theme.actionSheet.controlAccentColor, for: .normal)
self.contentGridNode.presentationLayoutUpdated = { [weak self] presentationLayout, transition in
self?.gridPresentationLayoutUpdated(presentationLayout, transition: transition)
}
@ -345,16 +353,14 @@ final class ImportStickerPackControllerNode: ViewControllerTracingNode, UIScroll
let contentFrame = contentContainerFrame.insetBy(dx: 12.0, dy: 0.0)
var transaction: StickerPackPreviewGridTransaction?
var animateIn = false
var forceTitleUpdate = false
if self.progress != nil && !self.hadProgress {
self.hadProgress = true
forceTitleUpdate = true
}
if let _ = self.stickerPack, self.currentItems.isEmpty || self.currentItems.count != self.pendingItems.count || forceTitleUpdate {
if let _ = self.stickerPack, self.currentItems.isEmpty || self.currentItems.count != self.pendingItems.count || self.pendingItems != self.currentItems || forceTitleUpdate {
let previousItems = self.currentItems
self.currentItems = self.pendingItems
@ -366,7 +372,6 @@ final class ImportStickerPackControllerNode: ViewControllerTracingNode, UIScroll
title = self.presentationData.strings.ImportStickerPack_StickerCount(Int32(self.currentItems.count))
}
self.contentTitleNode.attributedText = stringWithAppliedEntities(title, entities: [], baseColor: self.presentationData.theme.actionSheet.primaryTextColor, linkColor: self.presentationData.theme.actionSheet.controlAccentColor, baseFont: titleFont, linkFont: titleFont, boldFont: titleFont, italicFont: titleFont, boldItalicFont: titleFont, fixedFont: titleFont, blockQuoteFont: titleFont)
animateIn = true
if !forceTitleUpdate {
transaction = StickerPackPreviewGridTransaction(previousList: previousItems, list: self.currentItems, account: self.context.account, interaction: self.interaction, theme: self.presentationData.theme)
@ -405,13 +410,7 @@ final class ImportStickerPackControllerNode: ViewControllerTracingNode, UIScroll
self.contentGridNode.transaction(GridNodeTransaction(deleteItems: transaction?.deletions ?? [], insertItems: transaction?.insertions ?? [], updateItems: transaction?.updates ?? [], scrollToItem: nil, updateLayout: GridNodeUpdateLayout(layout: GridNodeLayout(size: gridSize, insets: UIEdgeInsets(top: topInset, left: 0.0, bottom: bottomGridInset, right: 0.0), preloadSize: 80.0, type: .fixed(itemSize: CGSize(width: itemWidth, height: itemWidth), fillWidth: nil, lineSpacing: 0.0, itemSpacing: nil)), transition: transition), itemTransition: .immediate, stationaryItems: .none, updateFirstIndexInSectionOffset: nil), completion: { _ in })
transition.updateFrame(node: self.contentGridNode, frame: CGRect(origin: CGPoint(x: floor((contentContainerFrame.size.width - contentFrame.size.width) / 2.0), y: titleAreaHeight), size: gridSize))
if animateIn {
self.contentGridNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
self.installActionButtonNode.titleNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
self.installActionSeparatorNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
}
transition.updateAlpha(node: self.contentGridNode, alpha: self.progress == nil ? 1.0 : 0.0)
var effectiveProgress: CGFloat = 0.0
@ -563,7 +562,12 @@ final class ImportStickerPackControllerNode: ViewControllerTracingNode, UIScroll
if case let .image(data) = item.stickerItem.content, let image = UIImage(data: data) {
dimensions = PixelDimensions(image.size)
}
if let resource = item.stickerItem.resource {
if let resource = self.uploadedStickerResources[item.stickerItem.uuid] {
if let localResource = item.stickerItem.resource {
self.context.account.postbox.mediaBox.copyResourceData(from: localResource.id, to: resource.id)
}
stickers.append(ImportSticker(resource: resource, emojis: item.stickerItem.emojis, dimensions: dimensions))
} else if let resource = item.stickerItem.resource {
stickers.append(ImportSticker(resource: resource, emojis: item.stickerItem.emojis, dimensions: dimensions))
}
}
@ -592,6 +596,7 @@ final class ImportStickerPackControllerNode: ViewControllerTracingNode, UIScroll
if case let .complete(info, items) = status {
if let (_, _, count) = strongSelf.progress {
strongSelf.progress = (1.0, count, count)
strongSelf.radialStatus.transitionToState(.progress(color: strongSelf.presentationData.theme.list.itemAccentColor, lineWidth: 6.0, value: 1.0, cancelEnabled: false, animateRotation: false), animated: !stickerPack.isAnimated, synchronous: true, completion: {})
if let (layout, navigationBarHeight) = strongSelf.containerLayout {
strongSelf.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate)
}
@ -631,9 +636,11 @@ final class ImportStickerPackControllerNode: ViewControllerTracingNode, UIScroll
if let firstStickerItem = firstStickerItem, let resource = firstStickerItem.resource as? TelegramMediaResource {
firstItem = StickerPackItem(index: ItemCollectionItemIndex(index: 0, id: 0), file: TelegramMediaFile(fileId: MediaId(namespace: 0, id: 0), partialReference: nil, resource: resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: stickerPack.isAnimated ? "application/x-tgsticker": "image/png", size: nil, attributes: [.FileName(fileName: stickerPack.isAnimated ? "sticker.tgs" : "sticker.png"), .ImageSize(size: firstStickerItem.dimensions)]), indexKeys: [])
}
strongSelf.presentInGlobalOverlay?(UndoOverlayController(presentationData: strongSelf.presentationData, content: .stickersModified(title: strongSelf.presentationData.strings.StickerPackActionInfo_AddedTitle, text: strongSelf.presentationData.strings.StickerPackActionInfo_AddedText(info.title).0, undo: false, info: info, topItem: firstItem ?? items.first, context: strongSelf.context), elevatedLayout: false, action: { _ in
// (navigationController?.viewControllers.last as? ViewController)?.present(StickerPackScreen(context: context, mode: .settings, mainStickerPack: .id(id: info.id.id, accessHash: info.accessHash), stickerPacks: [], parentNavigationController: navigationController, actionPerformed: { _, _, _ in
// }), in: .window(.root))
strongSelf.presentInGlobalOverlay?(UndoOverlayController(presentationData: strongSelf.presentationData, content: .stickersModified(title: strongSelf.presentationData.strings.StickerPackActionInfo_AddedTitle, text: strongSelf.presentationData.strings.StickerPackActionInfo_AddedText(info.title).0, undo: false, info: info, topItem: firstItem ?? items.first, context: strongSelf.context), elevatedLayout: false, action: { action in
if case .info = action {
(navigationController?.viewControllers.last as? ViewController)?.present(StickerPackScreen(context: context, mode: .settings, mainStickerPack: .id(id: info.id.id, accessHash: info.accessHash), stickerPacks: [], parentNavigationController: navigationController, actionPerformed: { _, _, _ in
}), in: .window(.root))
}
return true
}), nil)
strongSelf.cancel?()
@ -716,23 +723,35 @@ final class ImportStickerPackControllerNode: ViewControllerTracingNode, UIScroll
})
}
func updateStickerPack(_ stickerPack: ImportStickerPack) {
func updateStickerPack(_ stickerPack: ImportStickerPack, verifiedStickers: Set<UUID>, declinedStickers: Set<UUID>, uploadedStickerResources: [UUID: MediaResource]) {
self.stickerPack = stickerPack
self.uploadedStickerResources = uploadedStickerResources
var updatedItems: [StickerPackPreviewGridEntry] = []
for item in stickerPack.stickers {
let resource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max))
self.context.account.postbox.mediaBox.storeResourceData(resource.id, data: item.data)
item.resource = resource
updatedItems.append(StickerPackPreviewGridEntry(index: updatedItems.count, stickerItem: item))
if declinedStickers.contains(item.uuid) {
continue
}
if let resource = self.stickerResources[item.uuid] {
item.resource = resource
} else {
let resource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max))
self.context.account.postbox.mediaBox.storeResourceData(resource.id, data: item.data)
item.resource = resource
self.stickerResources[item.uuid] = resource
}
updatedItems.append(StickerPackPreviewGridEntry(index: updatedItems.count, stickerItem: item, isVerified: !item.isAnimated || verifiedStickers.contains(item.uuid)))
}
self.pendingItems = updatedItems
self.interaction.playAnimatedStickers = true
if stickerPack.isAnimated {
self.stickerPackReady = stickerPack.stickers.count == (verifiedStickers.count + declinedStickers.count) && updatedItems.count > 0
}
self.interaction.playAnimatedStickers = true
if let _ = self.containerLayout {
self.dequeueUpdateStickerPack()
}
self.installActionButtonNode.setTitle(self.presentationData.strings.ImportStickerPack_CreateStickerSet, with: Font.regular(20.0), with: self.presentationData.theme.actionSheet.controlAccentColor, for: .normal)
}
func dequeueUpdateStickerPack() {
@ -742,11 +761,17 @@ final class ImportStickerPackControllerNode: ViewControllerTracingNode, UIScroll
transition = .animated(duration: 0.4, curve: .spring)
} else {
transition = .immediate
self.contentTitleNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
self.contentGridNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
self.installActionButtonNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
}
self.contentTitleNode.alpha = 1.0
self.contentTitleNode.layer.animateAlpha(from: self.contentTitleNode.alpha, to: 1.0, duration: 0.2)
self.contentGridNode.alpha = 1.0
self.contentGridNode.layer.animateAlpha(from: self.contentGridNode.alpha, to: 1.0, duration: 0.2)
let buttonTransition: ContainedViewLayoutTransition = .animated(duration: 0.3, curve: .easeInOut)
buttonTransition.updateAlpha(node: self.installActionButtonNode, alpha: self.stickerPackReady ? 1.0 : 0.3)
self.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: transition)
if !self.didSetReady {

View File

@ -27,21 +27,21 @@ final class StickerPackPreviewGridItem: GridItem {
let stickerItem: ImportStickerPack.Sticker
let interaction: StickerPackPreviewInteraction
let theme: PresentationTheme
let isEmpty: Bool
let isVerified: Bool
let section: GridSection? = nil
init(account: Account, stickerItem: ImportStickerPack.Sticker, interaction: StickerPackPreviewInteraction, theme: PresentationTheme, isEmpty: Bool) {
init(account: Account, stickerItem: ImportStickerPack.Sticker, interaction: StickerPackPreviewInteraction, theme: PresentationTheme, isVerified: Bool) {
self.account = account
self.stickerItem = stickerItem
self.interaction = interaction
self.theme = theme
self.isEmpty = isEmpty
self.isVerified = isVerified
}
func node(layout: GridNodeLayout, synchronousLoad: Bool) -> GridItemNode {
let node = StickerPackPreviewGridItemNode()
node.setup(account: self.account, stickerItem: self.stickerItem, interaction: self.interaction, theme: self.theme, isEmpty: self.isEmpty)
node.setup(account: self.account, stickerItem: self.stickerItem, interaction: self.interaction, theme: self.theme, isVerified: self.isVerified)
return node
}
@ -50,7 +50,7 @@ final class StickerPackPreviewGridItem: GridItem {
assertionFailure()
return
}
node.setup(account: self.account, stickerItem: self.stickerItem, interaction: self.interaction, theme: self.theme, isEmpty: self.isEmpty)
node.setup(account: self.account, stickerItem: self.stickerItem, interaction: self.interaction, theme: self.theme, isVerified: self.isVerified)
}
}
@ -58,9 +58,10 @@ private let textFont = Font.regular(20.0)
final class StickerPackPreviewGridItemNode: GridItemNode {
private var currentState: (Account, ImportStickerPack.Sticker?, CGSize)?
private var isEmpty: Bool?
private var isVerified: Bool?
private let imageNode: ASImageNode
private var animationNode: AnimatedStickerNode?
private var placeholderNode: ShimmerEffectNode?
private var theme: PresentationTheme?
@ -84,7 +85,7 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
override init() {
self.imageNode = ASImageNode()
super.init()
self.addSubnode(self.imageNode)
@ -100,11 +101,11 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.imageNodeTap(_:))))
}
func setup(account: Account, stickerItem: ImportStickerPack.Sticker?, interaction: StickerPackPreviewInteraction, theme: PresentationTheme, isEmpty: Bool) {
func setup(account: Account, stickerItem: ImportStickerPack.Sticker?, interaction: StickerPackPreviewInteraction, theme: PresentationTheme, isVerified: Bool) {
self.interaction = interaction
self.theme = theme
if self.currentState == nil || self.currentState!.0 !== account || self.currentState!.1 !== stickerItem || self.isEmpty != isEmpty {
if self.currentState == nil || self.currentState!.0 !== account || self.currentState!.1 !== stickerItem || self.isVerified != isVerified {
var dimensions = CGSize(width: 512.0, height: 512.0)
if let stickerItem = stickerItem {
switch stickerItem.content {
@ -121,15 +122,35 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
}
case .animation:
self.imageNode.isHidden = true
let animationNode = AnimatedStickerNode()
self.animationNode = animationNode
self.addSubnode(animationNode)
let fittedDimensions = dimensions.aspectFitted(CGSize(width: 160.0, height: 160.0))
if let resource = stickerItem.resource {
animationNode.setup(source: AnimatedStickerResourceSource(account: account, resource: resource), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), mode: .direct(cachePathPrefix: nil))
if isVerified {
let animationNode = AnimatedStickerNode()
self.animationNode = animationNode
if let placeholderNode = self.placeholderNode {
self.placeholderNode = nil
placeholderNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak placeholderNode] _ in
placeholderNode?.removeFromSupernode()
})
self.insertSubnode(animationNode, belowSubnode: placeholderNode)
} else {
self.addSubnode(animationNode)
}
let fittedDimensions = dimensions.aspectFitted(CGSize(width: 160.0, height: 160.0))
if let resource = stickerItem.resource {
animationNode.setup(source: AnimatedStickerResourceSource(account: account, resource: resource), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), mode: .direct(cachePathPrefix: nil))
}
animationNode.visibility = self.isVisibleInGrid && self.interaction?.playAnimatedStickers ?? true
} else {
let placeholderNode = ShimmerEffectNode()
self.placeholderNode = placeholderNode
self.addSubnode(placeholderNode)
if let (absoluteRect, containerSize) = self.absoluteLocation {
placeholderNode.updateAbsoluteRect(absoluteRect, within: containerSize)
}
}
animationNode.visibility = self.isVisibleInGrid && self.interaction?.playAnimatedStickers ?? true
}
} else {
dimensions = CGSize()
@ -137,7 +158,7 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
self.currentState = (account, stickerItem, dimensions)
self.setNeedsLayout()
}
self.isEmpty = isEmpty
self.isVerified = isVerified
}
override func layout() {
@ -154,6 +175,11 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
animationNode.frame = CGRect(origin: CGPoint(x: floor((bounds.size.width - imageSize.width) / 2.0), y: (bounds.size.height - imageSize.height) / 2.0), size: imageSize)
animationNode.updateLayout(size: imageSize)
}
if let placeholderNode = self.placeholderNode, let theme = self.theme {
placeholderNode.update(backgroundColor: theme.list.itemBlocksBackgroundColor, foregroundColor: theme.list.mediaPlaceholderColor, shimmeringColor: theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.4), shapes: [.roundedRect(rect: CGRect(origin: CGPoint(), size: imageSize), cornerRadius: 11.0)], horizontal: true, size: imageSize)
placeholderNode.frame = self.imageNode.frame
}
}
}
@ -185,5 +211,13 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
}
}
}
var absoluteLocation: (CGRect, CGSize)?
override func updateAbsoluteRect(_ absoluteRect: CGRect, within containerSize: CGSize) {
self.absoluteLocation = (absoluteRect, containerSize)
if let placeholderNode = self.placeholderNode {
placeholderNode.updateAbsoluteRect(absoluteRect, within: containerSize)
}
}
}

View File

@ -26,14 +26,10 @@ typedef enum {
@protocol LegacyComponentsAccessChecker <NSObject>
- (bool)checkAddressBookAuthorizationStatusWithAlertDismissComlpetion:(void (^)(void))alertDismissCompletion;
- (bool)checkPhotoAuthorizationStatusForIntent:(TGPhotoAccessIntent)intent alertDismissCompletion:(void (^)(void))alertDismissCompletion;
- (bool)checkMicrophoneAuthorizationStatusForIntent:(TGMicrophoneAccessIntent)intent alertDismissCompletion:(void (^)(void))alertDismissCompletion;
- (bool)checkCameraAuthorizationStatusForIntent:(TGCameraAccessIntent)intent alertDismissCompletion:(void (^)(void))alertDismissCompletion;
- (bool)checkLocationAuthorizationStatusForIntent:(TGLocationAccessIntent)intent alertDismissComlpetion:(void (^)(void))alertDismissCompletion;
- (bool)checkCameraAuthorizationStatusForIntent:(TGCameraAccessIntent)intent completion:(void (^)(BOOL))completion alertDismissCompletion:(void (^)(void))alertDismissCompletion;
@end

View File

@ -270,101 +270,102 @@
- (void)_displayCameraWithView:(TGAttachmentCameraView *)cameraView menuController:(TGMenuSheetController *)menuController
{
if (![[[LegacyComponentsGlobals provider] accessChecker] checkCameraAuthorizationStatusForIntent:TGCameraAccessIntentDefault alertDismissCompletion:nil])
return;
if ([_context currentlyInSplitView])
return;
TGCameraController *controller = nil;
CGSize screenSize = TGScreenSize();
id<LegacyComponentsOverlayWindowManager> windowManager = [_context makeOverlayWindowManager];
if (cameraView.previewView != nil)
controller = [[TGCameraController alloc] initWithContext:[windowManager context] saveEditedPhotos:_saveEditedPhotos saveCapturedMedia:_saveCapturedMedia camera:cameraView.previewView.camera previewView:cameraView.previewView intent:_signup ? TGCameraControllerSignupAvatarIntent : TGCameraControllerAvatarIntent];
else
controller = [[TGCameraController alloc] initWithContext:[windowManager context] saveEditedPhotos:_saveEditedPhotos saveCapturedMedia:_saveCapturedMedia intent:_signup ? TGCameraControllerSignupAvatarIntent : TGCameraControllerAvatarIntent];
controller.stickersContext = _stickersContext;
controller.shouldStoreCapturedAssets = true;
TGCameraControllerWindow *controllerWindow = [[TGCameraControllerWindow alloc] initWithManager:windowManager parentController:_parentController contentController:controller];
controllerWindow.hidden = false;
controllerWindow.clipsToBounds = true;
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone)
controllerWindow.frame = CGRectMake(0, 0, screenSize.width, screenSize.height);
else
controllerWindow.frame = [_context fullscreenBounds];
bool standalone = true;
CGRect startFrame = CGRectMake(0, screenSize.height, screenSize.width, screenSize.height);
if (cameraView != nil)
{
standalone = false;
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad)
startFrame = CGRectZero;
else
startFrame = [controller.view convertRect:cameraView.previewView.frame fromView:cameraView];
}
[cameraView detachPreviewView];
[controller beginTransitionInFromRect:startFrame];
__weak TGMediaAvatarMenuMixin *weakSelf = self;
__weak TGCameraController *weakCameraController = controller;
__weak TGAttachmentCameraView *weakCameraView = cameraView;
controller.beginTransitionOut = ^CGRect
{
__strong TGCameraController *strongCameraController = weakCameraController;
if (strongCameraController == nil)
return CGRectZero;
__strong TGAttachmentCameraView *strongCameraView = weakCameraView;
if (strongCameraView != nil)
{
[strongCameraView willAttachPreviewView];
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad)
return CGRectZero;
[[[LegacyComponentsGlobals provider] accessChecker] checkCameraAuthorizationStatusForIntent:TGCameraAccessIntentDefault completion:^(BOOL allowed) {
if (!allowed)
return;
if ([_context currentlyInSplitView])
return;
return [strongCameraController.view convertRect:strongCameraView.frame fromView:strongCameraView.superview];
TGCameraController *controller = nil;
CGSize screenSize = TGScreenSize();
id<LegacyComponentsOverlayWindowManager> windowManager = [_context makeOverlayWindowManager];
if (cameraView.previewView != nil)
controller = [[TGCameraController alloc] initWithContext:[windowManager context] saveEditedPhotos:_saveEditedPhotos saveCapturedMedia:_saveCapturedMedia camera:cameraView.previewView.camera previewView:cameraView.previewView intent:_signup ? TGCameraControllerSignupAvatarIntent : TGCameraControllerAvatarIntent];
else
controller = [[TGCameraController alloc] initWithContext:[windowManager context] saveEditedPhotos:_saveEditedPhotos saveCapturedMedia:_saveCapturedMedia intent:_signup ? TGCameraControllerSignupAvatarIntent : TGCameraControllerAvatarIntent];
controller.stickersContext = _stickersContext;
controller.shouldStoreCapturedAssets = true;
TGCameraControllerWindow *controllerWindow = [[TGCameraControllerWindow alloc] initWithManager:windowManager parentController:_parentController contentController:controller];
controllerWindow.hidden = false;
controllerWindow.clipsToBounds = true;
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone)
controllerWindow.frame = CGRectMake(0, 0, screenSize.width, screenSize.height);
else
controllerWindow.frame = [_context fullscreenBounds];
bool standalone = true;
CGRect startFrame = CGRectMake(0, screenSize.height, screenSize.width, screenSize.height);
if (cameraView != nil)
{
standalone = false;
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad)
startFrame = CGRectZero;
else
startFrame = [controller.view convertRect:cameraView.previewView.frame fromView:cameraView];
}
return CGRectZero;
};
controller.finishedTransitionOut = ^
{
__strong TGAttachmentCameraView *strongCameraView = weakCameraView;
if (strongCameraView == nil)
return;
[cameraView detachPreviewView];
[controller beginTransitionInFromRect:startFrame];
[strongCameraView attachPreviewViewAnimated:true];
};
controller.finishedWithPhoto = ^(__unused TGOverlayController *controller, UIImage *resultImage, __unused NSString *caption, __unused NSArray *entities, __unused NSArray *stickers, __unused NSNumber *timer)
{
__strong TGMediaAvatarMenuMixin *strongSelf = weakSelf;
if (strongSelf == nil)
return;
__weak TGMediaAvatarMenuMixin *weakSelf = self;
__weak TGCameraController *weakCameraController = controller;
__weak TGAttachmentCameraView *weakCameraView = cameraView;
if (strongSelf.didFinishWithImage != nil)
strongSelf.didFinishWithImage(resultImage);
controller.beginTransitionOut = ^CGRect
{
__strong TGCameraController *strongCameraController = weakCameraController;
if (strongCameraController == nil)
return CGRectZero;
__strong TGAttachmentCameraView *strongCameraView = weakCameraView;
if (strongCameraView != nil)
{
[strongCameraView willAttachPreviewView];
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad)
return CGRectZero;
return [strongCameraController.view convertRect:strongCameraView.frame fromView:strongCameraView.superview];
}
return CGRectZero;
};
[menuController dismissAnimated:false];
};
controller.finishedWithVideo = ^(__unused TGOverlayController *controller, NSURL *url, UIImage *previewImage, __unused NSTimeInterval duration, __unused CGSize dimensions, TGVideoEditAdjustments *adjustments, __unused NSString *caption, __unused NSArray *entities, __unused NSArray *stickers, __unused NSNumber *timer){
__strong TGMediaAvatarMenuMixin *strongSelf = weakSelf;
if (strongSelf == nil)
return;
controller.finishedTransitionOut = ^
{
__strong TGAttachmentCameraView *strongCameraView = weakCameraView;
if (strongCameraView == nil)
return;
[strongCameraView attachPreviewViewAnimated:true];
};
if (strongSelf.didFinishWithVideo != nil)
strongSelf.didFinishWithVideo(previewImage, [[AVURLAsset alloc] initWithURL:url options:nil], adjustments);
controller.finishedWithPhoto = ^(__unused TGOverlayController *controller, UIImage *resultImage, __unused NSString *caption, __unused NSArray *entities, __unused NSArray *stickers, __unused NSNumber *timer)
{
__strong TGMediaAvatarMenuMixin *strongSelf = weakSelf;
if (strongSelf == nil)
return;
if (strongSelf.didFinishWithImage != nil)
strongSelf.didFinishWithImage(resultImage);
[menuController dismissAnimated:false];
};
[menuController dismissAnimated:false];
};
controller.finishedWithVideo = ^(__unused TGOverlayController *controller, NSURL *url, UIImage *previewImage, __unused NSTimeInterval duration, __unused CGSize dimensions, TGVideoEditAdjustments *adjustments, __unused NSString *caption, __unused NSArray *entities, __unused NSArray *stickers, __unused NSNumber *timer){
__strong TGMediaAvatarMenuMixin *strongSelf = weakSelf;
if (strongSelf == nil)
return;
if (strongSelf.didFinishWithVideo != nil)
strongSelf.didFinishWithVideo(previewImage, [[AVURLAsset alloc] initWithURL:url options:nil], adjustments);
[menuController dismissAnimated:false];
};
} alertDismissCompletion:nil];
}
- (void)_displayMediaPicker

View File

@ -271,7 +271,7 @@
+ (void)_displayCameraWithView:(TGAttachmentCameraView *)cameraView menuController:(TGMenuSheetController *)menuController parentController:(TGViewController *)parentController context:(id<LegacyComponentsContext>)context intent:(TGPassportAttachIntent)intent uploadAction:(void (^)(SSignal *, void (^)(void)))uploadAction
{
if (![[[LegacyComponentsGlobals provider] accessChecker] checkCameraAuthorizationStatusForIntent:TGCameraAccessIntentDefault alertDismissCompletion:nil])
if (![[[LegacyComponentsGlobals provider] accessChecker] checkCameraAuthorizationStatusForIntent:TGCameraAccessIntentDefault completion:^(BOOL allowed) { } alertDismissCompletion:nil])
return;
if ([context currentlyInSplitView])

View File

@ -39,10 +39,6 @@ private final class LegacyComponentsAccessCheckerImpl: NSObject, LegacyComponent
self.context = context
}
public func checkAddressBookAuthorizationStatus(alertDismissComlpetion alertDismissCompletion: (() -> Void)!) -> Bool {
return true
}
public func checkPhotoAuthorizationStatus(for intent: TGPhotoAccessIntent, alertDismissCompletion: (() -> Void)!) -> Bool {
if let context = self.context {
DeviceAccess.authorizeAccess(to: .mediaLibrary(.send), presentationData: context.sharedContext.currentPresentationData.with { $0 }, present: context.sharedContext.presentGlobalController, openSettings: context.sharedContext.applicationBindings.openSettings, { value in
@ -58,24 +54,10 @@ private final class LegacyComponentsAccessCheckerImpl: NSObject, LegacyComponent
return true
}
public func checkCameraAuthorizationStatus(for intent: TGCameraAccessIntent, alertDismissCompletion: (() -> Void)!) -> Bool {
return true
}
public func checkLocationAuthorizationStatus(for intent: TGLocationAccessIntent, alertDismissComlpetion alertDismissCompletion: (() -> Void)!) -> Bool {
let subject: DeviceAccessLocationSubject
if intent == TGLocationAccessIntentSend {
subject = .send
} else if intent == TGLocationAccessIntentLiveLocation {
subject = .live
} else if intent == TGLocationAccessIntentTracking {
subject = .tracking
} else {
assertionFailure()
subject = .send
}
public func checkCameraAuthorizationStatus(for intent: TGCameraAccessIntent, completion: ((Bool) -> Void)!, alertDismissCompletion: (() -> Void)!) -> Bool {
if let context = self.context {
DeviceAccess.authorizeAccess(to: .location(subject), presentationData: context.sharedContext.currentPresentationData.with { $0 }, present: context.sharedContext.presentGlobalController, openSettings: context.sharedContext.applicationBindings.openSettings, { value in
DeviceAccess.authorizeAccess(to: .camera(.video), presentationData: context.sharedContext.currentPresentationData.with { $0 }, present: context.sharedContext.presentGlobalController, openSettings: context.sharedContext.applicationBindings.openSettings, { value in
completion(value)
if !value {
alertDismissCompletion?()
}

View File

@ -2,9 +2,10 @@ import UIKit
import AsyncDisplayKit
import Display
private final class ShimmerEffectForegroundNode: ASDisplayNode {
final class ShimmerEffectForegroundNode: ASDisplayNode {
private var currentBackgroundColor: UIColor?
private var currentForegroundColor: UIColor?
private var currentHorizontal: Bool?
private let imageNodeContainer: ASDisplayNode
private let imageNode: ASImageNode
@ -45,31 +46,56 @@ private final class ShimmerEffectForegroundNode: ASDisplayNode {
self.updateAnimation()
}
func update(backgroundColor: UIColor, foregroundColor: UIColor) {
if let currentBackgroundColor = self.currentBackgroundColor, currentBackgroundColor.isEqual(backgroundColor), let currentForegroundColor = self.currentForegroundColor, currentForegroundColor.isEqual(foregroundColor) {
func update(backgroundColor: UIColor, foregroundColor: UIColor, horizontal: Bool = false) {
if let currentBackgroundColor = self.currentBackgroundColor, currentBackgroundColor.isEqual(backgroundColor), let currentForegroundColor = self.currentForegroundColor, currentForegroundColor.isEqual(foregroundColor), self.currentHorizontal == horizontal {
return
}
self.currentBackgroundColor = backgroundColor
self.currentForegroundColor = foregroundColor
self.currentHorizontal = horizontal
self.imageNode.image = generateImage(CGSize(width: 16.0, height: 320.0), opaque: false, scale: 1.0, rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setFillColor(backgroundColor.cgColor)
context.fill(CGRect(origin: CGPoint(), size: size))
context.clip(to: CGRect(origin: CGPoint(), size: size))
let transparentColor = foregroundColor.withAlphaComponent(0.0).cgColor
let peakColor = foregroundColor.cgColor
var locations: [CGFloat] = [0.0, 0.5, 1.0]
let colors: [CGColor] = [transparentColor, peakColor, transparentColor]
let colorSpace = CGColorSpaceCreateDeviceRGB()
let gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: &locations)!
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: 0.0, y: size.height), options: CGGradientDrawingOptions())
})
let image: UIImage?
if horizontal {
image = generateImage(CGSize(width: 320.0, height: 16.0), opaque: false, scale: 1.0, rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setFillColor(backgroundColor.cgColor)
context.fill(CGRect(origin: CGPoint(), size: size))
context.clip(to: CGRect(origin: CGPoint(), size: size))
let transparentColor = foregroundColor.withAlphaComponent(0.0).cgColor
let peakColor = foregroundColor.cgColor
var locations: [CGFloat] = [0.0, 0.5, 1.0]
let colors: [CGColor] = [transparentColor, peakColor, transparentColor]
let colorSpace = CGColorSpaceCreateDeviceRGB()
let gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: &locations)!
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: size.width, y: 0.0), options: CGGradientDrawingOptions())
})
} else {
image = generateImage(CGSize(width: 16.0, height: 320.0), opaque: false, scale: 1.0, rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setFillColor(backgroundColor.cgColor)
context.fill(CGRect(origin: CGPoint(), size: size))
context.clip(to: CGRect(origin: CGPoint(), size: size))
let transparentColor = foregroundColor.withAlphaComponent(0.0).cgColor
let peakColor = foregroundColor.cgColor
var locations: [CGFloat] = [0.0, 0.5, 1.0]
let colors: [CGColor] = [transparentColor, peakColor, transparentColor]
let colorSpace = CGColorSpaceCreateDeviceRGB()
let gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: &locations)!
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: 0.0, y: size.height), options: CGGradientDrawingOptions())
})
}
self.imageNode.image = image
self.updateAnimation()
}
func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize) {
@ -95,7 +121,7 @@ private final class ShimmerEffectForegroundNode: ASDisplayNode {
}
private func updateAnimation() {
let shouldBeAnimating = self.isCurrentlyInHierarchy && self.absoluteLocation != nil
let shouldBeAnimating = self.isCurrentlyInHierarchy && self.absoluteLocation != nil && self.currentHorizontal != nil
if shouldBeAnimating != self.shouldBeAnimating {
self.shouldBeAnimating = shouldBeAnimating
if shouldBeAnimating {
@ -107,15 +133,25 @@ private final class ShimmerEffectForegroundNode: ASDisplayNode {
}
private func addImageAnimation() {
guard let containerSize = self.absoluteLocation?.1 else {
guard let containerSize = self.absoluteLocation?.1, let horizontal = self.currentHorizontal else {
return
}
let gradientHeight: CGFloat = 250.0
self.imageNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -gradientHeight), size: CGSize(width: containerSize.width, height: gradientHeight))
let animation = self.imageNode.layer.makeAnimation(from: 0.0 as NSNumber, to: (containerSize.height + gradientHeight) as NSNumber, keyPath: "position.y", timingFunction: CAMediaTimingFunctionName.easeOut.rawValue, duration: 1.3 * 1.0, delay: 0.0, mediaTimingFunction: nil, removeOnCompletion: true, additive: true)
animation.repeatCount = Float.infinity
animation.beginTime = 1.0
self.imageNode.layer.add(animation, forKey: "shimmer")
if horizontal {
let gradientHeight: CGFloat = 320.0
self.imageNode.frame = CGRect(origin: CGPoint(x: -gradientHeight, y: 0.0), size: CGSize(width: gradientHeight, height: containerSize.height))
let animation = self.imageNode.layer.makeAnimation(from: 0.0 as NSNumber, to: (containerSize.width + gradientHeight) as NSNumber, keyPath: "position.x", timingFunction: CAMediaTimingFunctionName.easeOut.rawValue, duration: 1.3 * 1.0, delay: 0.0, mediaTimingFunction: nil, removeOnCompletion: true, additive: true)
animation.repeatCount = Float.infinity
animation.beginTime = 1.0
self.imageNode.layer.add(animation, forKey: "shimmer")
} else {
let gradientHeight: CGFloat = 250.0
self.imageNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -gradientHeight), size: CGSize(width: containerSize.width, height: gradientHeight))
let animation = self.imageNode.layer.makeAnimation(from: 0.0 as NSNumber, to: (containerSize.height + gradientHeight) as NSNumber, keyPath: "position.y", timingFunction: CAMediaTimingFunctionName.easeOut.rawValue, duration: 1.3 * 1.0, delay: 0.0, mediaTimingFunction: nil, removeOnCompletion: true, additive: true)
animation.repeatCount = Float.infinity
animation.beginTime = 1.0
self.imageNode.layer.add(animation, forKey: "shimmer")
}
}
}
@ -135,6 +171,7 @@ public final class ShimmerEffectNode: ASDisplayNode {
private var currentBackgroundColor: UIColor?
private var currentForegroundColor: UIColor?
private var currentShimmeringColor: UIColor?
private var currentHorizontal: Bool?
private var currentSize = CGSize()
override public init() {
@ -157,8 +194,8 @@ public final class ShimmerEffectNode: ASDisplayNode {
self.effectNode.updateAbsoluteRect(rect, within: containerSize)
}
public func update(backgroundColor: UIColor, foregroundColor: UIColor, shimmeringColor: UIColor, shapes: [Shape], size: CGSize) {
if self.currentShapes == shapes, let currentBackgroundColor = self.currentBackgroundColor, currentBackgroundColor.isEqual(backgroundColor), let currentForegroundColor = self.currentForegroundColor, currentForegroundColor.isEqual(foregroundColor), let currentShimmeringColor = self.currentShimmeringColor, currentShimmeringColor.isEqual(shimmeringColor), self.currentSize == size {
public func update(backgroundColor: UIColor, foregroundColor: UIColor, shimmeringColor: UIColor, shapes: [Shape], horizontal: Bool = false, size: CGSize) {
if self.currentShapes == shapes, let currentBackgroundColor = self.currentBackgroundColor, currentBackgroundColor.isEqual(backgroundColor), let currentForegroundColor = self.currentForegroundColor, currentForegroundColor.isEqual(foregroundColor), let currentShimmeringColor = self.currentShimmeringColor, currentShimmeringColor.isEqual(shimmeringColor), horizontal == self.currentHorizontal, self.currentSize == size {
return
}
@ -166,11 +203,12 @@ public final class ShimmerEffectNode: ASDisplayNode {
self.currentForegroundColor = foregroundColor
self.currentShimmeringColor = shimmeringColor
self.currentShapes = shapes
self.currentHorizontal = horizontal
self.currentSize = size
self.backgroundNode.backgroundColor = foregroundColor
self.effectNode.update(backgroundColor: foregroundColor, foregroundColor: shimmeringColor)
self.effectNode.update(backgroundColor: foregroundColor, foregroundColor: shimmeringColor, horizontal: horizontal)
self.foregroundNode.image = generateImage(size, rotatedContext: { size, context in
context.setFillColor(backgroundColor.cgColor)

View File

@ -2,124 +2,6 @@ import Foundation
import AsyncDisplayKit
import Display
private final class ShimmerEffectForegroundNode: ASDisplayNode {
private var currentBackgroundColor: UIColor?
private var currentForegroundColor: UIColor?
private let imageNodeContainer: ASDisplayNode
private let imageNode: ASImageNode
private var absoluteLocation: (CGRect, CGSize)?
private var isCurrentlyInHierarchy = false
private var shouldBeAnimating = false
override init() {
self.imageNodeContainer = ASDisplayNode()
self.imageNodeContainer.isLayerBacked = true
self.imageNode = ASImageNode()
self.imageNode.isLayerBacked = true
self.imageNode.displaysAsynchronously = false
self.imageNode.displayWithoutProcessing = true
self.imageNode.contentMode = .scaleToFill
super.init()
self.isLayerBacked = true
self.clipsToBounds = true
self.imageNodeContainer.addSubnode(self.imageNode)
self.addSubnode(self.imageNodeContainer)
}
override func didEnterHierarchy() {
super.didEnterHierarchy()
self.isCurrentlyInHierarchy = true
self.updateAnimation()
}
override func didExitHierarchy() {
super.didExitHierarchy()
self.isCurrentlyInHierarchy = false
self.updateAnimation()
}
func update(backgroundColor: UIColor, foregroundColor: UIColor) {
if let currentBackgroundColor = self.currentBackgroundColor, currentBackgroundColor.isEqual(backgroundColor), let currentForegroundColor = self.currentForegroundColor, currentForegroundColor.isEqual(foregroundColor) {
return
}
self.currentBackgroundColor = backgroundColor
self.currentForegroundColor = foregroundColor
let image = generateImage(CGSize(width: 320.0, height: 16.0), opaque: false, scale: 1.0, rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setFillColor(backgroundColor.cgColor)
context.fill(CGRect(origin: CGPoint(), size: size))
context.clip(to: CGRect(origin: CGPoint(), size: size))
let transparentColor = foregroundColor.withAlphaComponent(0.0).cgColor
let peakColor = foregroundColor.cgColor
var locations: [CGFloat] = [0.0, 0.5, 1.0]
let colors: [CGColor] = [transparentColor, peakColor, transparentColor]
let colorSpace = CGColorSpaceCreateDeviceRGB()
let gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: &locations)!
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: size.width, y: 0.0), options: CGGradientDrawingOptions())
})
self.imageNode.image = image
}
func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize) {
if let absoluteLocation = self.absoluteLocation, absoluteLocation.0 == rect && absoluteLocation.1 == containerSize {
return
}
let sizeUpdated = self.absoluteLocation?.1 != containerSize
let frameUpdated = self.absoluteLocation?.0 != rect
self.absoluteLocation = (rect, containerSize)
if sizeUpdated {
if self.shouldBeAnimating {
self.imageNode.layer.removeAnimation(forKey: "shimmer")
self.addImageAnimation()
} else {
self.updateAnimation()
}
}
if frameUpdated {
self.imageNodeContainer.frame = CGRect(origin: CGPoint(x: -rect.minX, y: -rect.minY), size: containerSize)
}
}
private func updateAnimation() {
let shouldBeAnimating = self.isCurrentlyInHierarchy && self.absoluteLocation != nil
if shouldBeAnimating != self.shouldBeAnimating {
self.shouldBeAnimating = shouldBeAnimating
if shouldBeAnimating {
self.addImageAnimation()
} else {
self.imageNode.layer.removeAnimation(forKey: "shimmer")
}
}
}
private func addImageAnimation() {
guard let containerSize = self.absoluteLocation?.1 else {
return
}
let gradientHeight: CGFloat = 320.0
self.imageNode.frame = CGRect(origin: CGPoint(x: -gradientHeight, y: 0.0), size: CGSize(width: gradientHeight, height: containerSize.height))
let animation = self.imageNode.layer.makeAnimation(from: 0.0 as NSNumber, to: (containerSize.width + gradientHeight) as NSNumber, keyPath: "position.x", timingFunction: CAMediaTimingFunctionName.easeOut.rawValue, duration: 1.3 * 1.0, delay: 0.0, mediaTimingFunction: nil, removeOnCompletion: true, additive: true)
animation.repeatCount = Float.infinity
animation.beginTime = 1.0
self.imageNode.layer.add(animation, forKey: "shimmer")
}
}
private let decodingMap: [String] = ["A", "A", "C", "A", "A", "A", "A", "H", "A", "A", "A", "L", "M", "A", "A", "A", "Q", "A", "S", "T", "A", "V", "A", "A", "A", "Z", "a", "a", "c", "a", "a", "a", "a", "h", "a", "a", "a", "l", "m", "a", "a", "a", "q", "a", "s", "t", "a", "v", "a", ".", "a", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "-", ","]
private func decodeStickerThumbnailData(_ data: Data) -> String {
var string = "M"
@ -199,7 +81,7 @@ public class StickerShimmerEffectNode: ASDisplayNode {
self.backgroundNode.backgroundColor = foregroundColor
self.effectNode.update(backgroundColor: backgroundColor == nil ? .clear : foregroundColor, foregroundColor: shimmeringColor)
self.effectNode.update(backgroundColor: backgroundColor == nil ? .clear : foregroundColor, foregroundColor: shimmeringColor, horizontal: true)
let bounds = CGRect(origin: CGPoint(), size: size)
let image = generateImage(size, rotatedContext: { size, context in

View File

@ -4370,8 +4370,8 @@ public final class VoiceChatController: ViewController {
self.actionButton.update(size: centralButtonSize, buttonSize: CGSize(width: 112.0, height: 112.0), state: actionButtonState, title: actionButtonTitle, subtitle: actionButtonSubtitle, dark: self.isFullscreen, small: smallButtons, animated: true)
var hasCameraButton = self.callState?.isVideoEnabled ?? false
if let joinedVideo = self.joinedVideo, !joinedVideo {
hasCameraButton = false
if let joinedVideo = self.joinedVideo {
hasCameraButton = joinedVideo
}
switch actionButtonState {
case let .active(state):
@ -4790,7 +4790,7 @@ public final class VoiceChatController: ViewController {
displayPanelVideos = self.displayPanelVideos
}
var joinedVideo = true
var joinedVideo = self.joinedVideo ?? true
var myEntry: VoiceChatPeerEntry?
var mainEntry: VoiceChatPeerEntry?
@ -4929,7 +4929,7 @@ public final class VoiceChatController: ViewController {
}
}
if !isTile || (isTablet) {
if !isTile || isTablet || !joinedVideo {
entries.append(.peer(peerEntry, index))
}

View File

@ -5,12 +5,12 @@ import TelegramApi
import SyncCore
private enum UploadStickerStatus {
public enum UploadStickerStatus {
case progress(Float)
case complete(TelegramMediaFile)
case complete(CloudDocumentMediaResource, String)
}
private enum UploadStickerError {
public enum UploadStickerError {
case generic
}
@ -34,7 +34,7 @@ private func uploadedSticker(postbox: Postbox, network: Network, resource: Media
}
}
private func uploadSticker(account: Account, peer: Peer, resource: MediaResource, alt: String, dimensions: PixelDimensions, isAnimated: Bool) -> Signal<UploadStickerStatus, UploadStickerError> {
func _internal_uploadSticker(account: Account, peer: Peer, resource: MediaResource, alt: String, dimensions: PixelDimensions, isAnimated: Bool) -> Signal<UploadStickerStatus, UploadStickerError> {
guard let inputPeer = apiInputPeer(peer) else {
return .fail(.generic)
}
@ -59,8 +59,8 @@ private func uploadSticker(account: Account, peer: Peer, resource: MediaResource
|> mapToSignal { media -> Signal<UploadStickerStatus, UploadStickerError> in
switch media {
case let .messageMediaDocument(_, document, _):
if let document = document, let file = telegramMediaFileFromApiDocument(document) {
return .single(.complete(file))
if let document = document, let file = telegramMediaFileFromApiDocument(document), let resource = file.resource as? CloudDocumentMediaResource {
return .single(.complete(resource, file.mimeType))
}
default:
break
@ -108,35 +108,37 @@ func _internal_createStickerSet(account: Account, title: String, shortName: Stri
stickers.append(thumbnail)
}
for sticker in stickers {
uploadStickers.append(uploadSticker(account: account, peer: peer, resource: sticker.resource, alt: sticker.emojis.first ?? "", dimensions: sticker.dimensions, isAnimated: isAnimated)
|> mapError { _ -> CreateStickerSetError in
return .generic
})
if let resource = sticker.resource as? CloudDocumentMediaResource {
uploadStickers.append(.single(.complete(resource, isAnimated ? "application/x-tgsticker": "image/png")))
} else {
uploadStickers.append(_internal_uploadSticker(account: account, peer: peer, resource: sticker.resource, alt: sticker.emojis.first ?? "", dimensions: sticker.dimensions, isAnimated: isAnimated)
|> mapError { _ -> CreateStickerSetError in
return .generic
})
}
}
return combineLatest(uploadStickers)
|> mapToSignal { uploadedStickers -> Signal<CreateStickerSetStatus, CreateStickerSetError> in
var documents: [TelegramMediaFile] = []
var resources: [CloudDocumentMediaResource] = []
for sticker in uploadedStickers {
if case let .complete(document) = sticker {
documents.append(document)
if case let .complete(resource, _) = sticker {
resources.append(resource)
}
}
if documents.count == stickers.count {
if resources.count == stickers.count {
var flags: Int32 = 0
if isAnimated {
flags |= (1 << 1)
}
var inputStickers: [Api.InputStickerSetItem] = []
let stickerDocuments = thumbnail != nil ? documents.dropLast() : documents
let stickerDocuments = thumbnail != nil ? resources.dropLast() : resources
for i in 0 ..< stickerDocuments.count {
let sticker = stickers[i]
let document = documents[i]
if let resource = document.resource as? CloudDocumentMediaResource {
inputStickers.append(.inputStickerSetItem(flags: 0, document: .inputDocument(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference ?? Data())), emoji: sticker.emojis.first ?? "", maskCoords: nil))
}
let resource = resources[i]
inputStickers.append(.inputStickerSetItem(flags: 0, document: .inputDocument(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference ?? Data())), emoji: sticker.emojis.first ?? "", maskCoords: nil))
}
var thumbnailDocument: Api.InputDocument?
if thumbnail != nil, let document = documents.last, let resource = document.resource as? CloudDocumentMediaResource {
if thumbnail != nil, let resource = resources.last {
flags |= (1 << 2)
thumbnailDocument = .inputDocument(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference ?? Data()))
}

View File

@ -70,6 +70,10 @@ public extension TelegramEngine {
return _internal_stickerPacksAttachedToMedia(account: self.account, media: media)
}
public func uploadSticker(peer: Peer, resource: MediaResource, alt: String, dimensions: PixelDimensions, isAnimated: Bool) -> Signal<UploadStickerStatus, UploadStickerError> {
return _internal_uploadSticker(account: self.account, peer: peer, resource: resource, alt: alt, dimensions: dimensions, isAnimated: isAnimated)
}
public func createStickerSet(title: String, shortName: String, stickers: [ImportSticker], thumbnail: ImportSticker?, isAnimated: Bool, software: String?) -> Signal<CreateStickerSetStatus, CreateStickerSetError> {
return _internal_createStickerSet(account: self.account, title: title, shortName: shortName, stickers: stickers, thumbnail: thumbnail, isAnimated: isAnimated, software: software)
}