UI improvements

This commit is contained in:
Ali 2023-03-02 16:24:52 +04:00
parent f173aaa5e5
commit 04d97739cd
14 changed files with 138 additions and 77 deletions

View File

@ -3371,9 +3371,9 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
strongSelf.updateLayout(size: CGSize(width: layout.contentSize.width, height: itemHeight), leftInset: params.leftInset, rightInset: params.rightInset)
if item.editing {
strongSelf.setRevealOptions((left: [], right: []))
strongSelf.setRevealOptions((left: [], right: []), enableAnimations: item.context.sharedContext.energyUsageSettings.fullTranslucency)
} else {
strongSelf.setRevealOptions((left: peerLeftRevealOptions, right: peerRevealOptions))
strongSelf.setRevealOptions((left: peerLeftRevealOptions, right: peerRevealOptions), enableAnimations: item.context.sharedContext.energyUsageSettings.fullTranslucency)
}
if !strongSelf.customAnimationInProgress {
strongSelf.setRevealOptionsOpened(item.hasActiveRevealControls, animated: true)

View File

@ -86,9 +86,9 @@ public final class TrendingPanePackEntry: Identifiable, Comparable {
return lhs.index < rhs.index
}
public func item(account: Account, interaction: TrendingPaneInteraction, grid: Bool) -> GridItem {
public func item(context: AccountContext, interaction: TrendingPaneInteraction, grid: Bool) -> GridItem {
let info = self.info
return StickerPaneSearchGlobalItem(account: account, theme: self.theme, strings: self.strings, listAppearance: false, info: self.info, topItems: self.topItems, topSeparator: self.topSeparator, regularInsets: false, installed: self.installed, unread: self.unread, open: {
return StickerPaneSearchGlobalItem(context: context, theme: self.theme, strings: self.strings, listAppearance: false, info: self.info, topItems: self.topItems, topSeparator: self.topSeparator, regularInsets: false, installed: self.installed, unread: self.unread, open: {
interaction.openPack(info)
}, install: {
interaction.installPack(info)
@ -147,14 +147,14 @@ private enum TrendingPaneEntry: Identifiable, Comparable {
}
}
func item(account: Account, interaction: TrendingPaneInteraction, grid: Bool) -> GridItem {
func item(context: AccountContext, interaction: TrendingPaneInteraction, grid: Bool) -> GridItem {
switch self {
case let .search(theme, strings):
return PaneSearchBarPlaceholderItem(theme: theme, strings: strings, type: .stickers, activate: {
interaction.openSearch()
})
case let .pack(pack):
return pack.item(account: account, interaction: interaction, grid: grid)
return pack.item(context: context, interaction: interaction, grid: grid)
}
}
}
@ -166,12 +166,12 @@ private struct TrendingPaneTransition {
let initial: Bool
}
private func preparedTransition(from fromEntries: [TrendingPaneEntry], to toEntries: [TrendingPaneEntry], account: Account, interaction: TrendingPaneInteraction, initial: Bool) -> TrendingPaneTransition {
private func preparedTransition(from fromEntries: [TrendingPaneEntry], to toEntries: [TrendingPaneEntry], context: AccountContext, interaction: TrendingPaneInteraction, initial: Bool) -> TrendingPaneTransition {
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
let deletions = deleteIndices
let insertions = indicesAndItems.map { GridNodeInsertItem(index: $0.0, item: $0.1.item(account: account, interaction: interaction, grid: false), previousIndex: $0.2) }
let updates = updateIndices.map { GridNodeUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, interaction: interaction, grid: false)) }
let insertions = indicesAndItems.map { GridNodeInsertItem(index: $0.0, item: $0.1.item(context: context, interaction: interaction, grid: false), previousIndex: $0.2) }
let updates = updateIndices.map { GridNodeUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, interaction: interaction, grid: false)) }
return TrendingPaneTransition(deletions: deletions, insertions: insertions, updates: updates, initial: initial)
}
@ -356,7 +356,7 @@ public final class ChatMediaInputTrendingPane: ChatMediaInputPane {
let entries = trendingPaneEntries(trendingEntries: trendingEntries, installedPacks: installedPacks, theme: presentationData.theme, strings: presentationData.strings, isPane: isPane)
let previous = previousEntries.swap(entries)
return preparedTransition(from: previous ?? [], to: entries, account: context.account, interaction: interaction, initial: previous == nil)
return preparedTransition(from: previous ?? [], to: entries, context: context, interaction: interaction, initial: previous == nil)
}
|> deliverOnMainQueue).start(next: { [weak self] transition in
guard let strongSelf = self else {

View File

@ -96,9 +96,9 @@ private final class FeaturedPackEntry: Identifiable, Comparable {
return lhs.index < rhs.index
}
func item(account: Account, interaction: FeaturedInteraction, isOther: Bool) -> GridItem {
func item(context: AccountContext, interaction: FeaturedInteraction, isOther: Bool) -> GridItem {
let info = self.info
return StickerPaneSearchGlobalItem(account: account, theme: self.theme, strings: self.strings, listAppearance: true, fillsRow: false, info: self.info, topItems: self.topItems, topSeparator: self.topSeparator, regularInsets: self.regularInsets, installed: self.installed, unread: self.unread, open: {
return StickerPaneSearchGlobalItem(context: context, theme: self.theme, strings: self.strings, listAppearance: true, fillsRow: false, info: self.info, topItems: self.topItems, topSeparator: self.topSeparator, regularInsets: self.regularInsets, installed: self.installed, unread: self.unread, open: {
interaction.openPack(info)
}, install: {
interaction.installPack(info, !self.installed)
@ -143,10 +143,10 @@ private enum FeaturedEntry: Identifiable, Comparable {
}
}
func item(account: Account, interaction: FeaturedInteraction) -> GridItem {
func item(context: AccountContext, interaction: FeaturedInteraction) -> GridItem {
switch self {
case let .pack(pack, isOther):
return pack.item(account: account, interaction: interaction, isOther: isOther)
return pack.item(context: context, interaction: interaction, isOther: isOther)
}
}
}
@ -159,12 +159,12 @@ private struct FeaturedTransition {
let scrollToItem: GridNodeScrollToItem?
}
private func preparedTransition(from fromEntries: [FeaturedEntry], to toEntries: [FeaturedEntry], account: Account, interaction: FeaturedInteraction, initial: Bool, scrollToItem: GridNodeScrollToItem?) -> FeaturedTransition {
private func preparedTransition(from fromEntries: [FeaturedEntry], to toEntries: [FeaturedEntry], context: AccountContext, interaction: FeaturedInteraction, initial: Bool, scrollToItem: GridNodeScrollToItem?) -> FeaturedTransition {
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
let deletions = deleteIndices
let insertions = indicesAndItems.map { GridNodeInsertItem(index: $0.0, item: $0.1.item(account: account, interaction: interaction), previousIndex: $0.2) }
let updates = updateIndices.map { GridNodeUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, interaction: interaction)) }
let insertions = indicesAndItems.map { GridNodeInsertItem(index: $0.0, item: $0.1.item(context: context, interaction: interaction), previousIndex: $0.2) }
let updates = updateIndices.map { GridNodeUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, interaction: interaction)) }
return FeaturedTransition(deletions: deletions, insertions: insertions, updates: updates, initial: initial, scrollToItem: scrollToItem)
}
@ -401,7 +401,7 @@ private final class FeaturedStickersScreenNode: ViewControllerTracingNode {
}
}
return preparedTransition(from: previous ?? [], to: entries, account: context.account, interaction: interaction, initial: initial, scrollToItem: scrollToItem)
return preparedTransition(from: previous ?? [], to: entries, context: context, interaction: interaction, initial: initial, scrollToItem: scrollToItem)
}
|> deliverOnMainQueue).start(next: { [weak self] transition in
guard let strongSelf = self else {
@ -1034,14 +1034,14 @@ private enum FeaturedSearchEntry: Identifiable, Comparable {
}
}
func item(account: Account, theme: PresentationTheme, strings: PresentationStrings, interaction: StickerPaneSearchInteraction, inputNodeInteraction: ChatMediaInputNodeInteraction, itemContext: StickerPaneSearchGlobalItemContext) -> GridItem {
func item(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, interaction: StickerPaneSearchInteraction, inputNodeInteraction: ChatMediaInputNodeInteraction, itemContext: StickerPaneSearchGlobalItemContext) -> GridItem {
switch self {
case let .sticker(_, code, stickerItem, theme):
return StickerPaneSearchStickerItem(account: account, code: code, stickerItem: stickerItem, inputNodeInteraction: inputNodeInteraction, theme: theme, selected: { node, rect in
return StickerPaneSearchStickerItem(context: context, code: code, stickerItem: stickerItem, inputNodeInteraction: inputNodeInteraction, theme: theme, selected: { node, rect in
interaction.sendSticker(.standalone(media: stickerItem.file), node.view, rect)
})
case let .global(_, info, topItems, installed, topSeparator):
return StickerPaneSearchGlobalItem(account: account, theme: theme, strings: strings, listAppearance: true, fillsRow: true, info: info, topItems: topItems, topSeparator: topSeparator, regularInsets: false, installed: installed, unread: false, open: {
return StickerPaneSearchGlobalItem(context: context, theme: theme, strings: strings, listAppearance: true, fillsRow: true, info: info, topItems: topItems, topSeparator: topSeparator, regularInsets: false, installed: installed, unread: false, open: {
interaction.open(info)
}, install: {
interaction.install(info, topItems, !installed)
@ -1062,7 +1062,7 @@ private struct FeaturedSearchGridTransition {
let animated: Bool
}
private func preparedFeaturedSearchEntryTransition(account: Account, theme: PresentationTheme, strings: PresentationStrings, from fromEntries: [FeaturedSearchEntry], to toEntries: [FeaturedSearchEntry], interaction: StickerPaneSearchInteraction, inputNodeInteraction: ChatMediaInputNodeInteraction, itemContext: StickerPaneSearchGlobalItemContext) -> FeaturedSearchGridTransition {
private func preparedFeaturedSearchEntryTransition(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, from fromEntries: [FeaturedSearchEntry], to toEntries: [FeaturedSearchEntry], interaction: StickerPaneSearchInteraction, inputNodeInteraction: ChatMediaInputNodeInteraction, itemContext: StickerPaneSearchGlobalItemContext) -> FeaturedSearchGridTransition {
let stationaryItems: GridNodeStationaryItems = .none
let scrollToItem: GridNodeScrollToItem? = nil
var animated = false
@ -1071,8 +1071,8 @@ private func preparedFeaturedSearchEntryTransition(account: Account, theme: Pres
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
let deletions = deleteIndices
let insertions = indicesAndItems.map { GridNodeInsertItem(index: $0.0, item: $0.1.item(account: account, theme: theme, strings: strings, interaction: interaction, inputNodeInteraction: inputNodeInteraction, itemContext: itemContext), previousIndex: $0.2) }
let updates = updateIndices.map { GridNodeUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, theme: theme, strings: strings, interaction: interaction, inputNodeInteraction: inputNodeInteraction, itemContext: itemContext)) }
let insertions = indicesAndItems.map { GridNodeInsertItem(index: $0.0, item: $0.1.item(context: context, theme: theme, strings: strings, interaction: interaction, inputNodeInteraction: inputNodeInteraction, itemContext: itemContext), previousIndex: $0.2) }
let updates = updateIndices.map { GridNodeUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, theme: theme, strings: strings, interaction: interaction, inputNodeInteraction: inputNodeInteraction, itemContext: itemContext)) }
let firstIndexInSectionOffset = 0
@ -1375,7 +1375,7 @@ private final class FeaturedPaneSearchContentNode: ASDisplayNode {
}
let previousEntries = strongSelf.currentEntries.swap(entries)
let transition = preparedFeaturedSearchEntryTransition(account: strongSelf.context.account, theme: strongSelf.theme, strings: strongSelf.strings, from: previousEntries ?? [], to: entries, interaction: interaction, inputNodeInteraction: strongSelf.inputNodeInteraction, itemContext: strongSelf.itemContext)
let transition = preparedFeaturedSearchEntryTransition(context: strongSelf.context, theme: strongSelf.theme, strings: strongSelf.strings, from: previousEntries ?? [], to: entries, interaction: interaction, inputNodeInteraction: strongSelf.inputNodeInteraction, itemContext: strongSelf.itemContext)
strongSelf.enqueueTransition(transition)
if displayResults {

View File

@ -8,6 +8,7 @@ import Postbox
import TelegramPresentationData
import StickerPackPreviewUI
import ListSectionHeaderNode
import AccountContext
final class StickerPaneSearchGlobalSection: GridSection {
let title: String?
@ -78,7 +79,7 @@ public final class StickerPaneSearchGlobalItemContext {
}
public final class StickerPaneSearchGlobalItem: GridItem {
public let account: Account
public let context: AccountContext
public let theme: PresentationTheme
public let strings: PresentationStrings
public let listAppearance: Bool
@ -110,8 +111,8 @@ public final class StickerPaneSearchGlobalItem: GridItem {
return (128.0 + additionalHeight, self.fillsRow)
}
public init(account: Account, theme: PresentationTheme, strings: PresentationStrings, listAppearance: Bool, fillsRow: Bool = true, info: StickerPackCollectionInfo, topItems: [StickerPackItem], topSeparator: Bool, regularInsets: Bool, installed: Bool, installing: Bool = false, unread: Bool, open: @escaping () -> Void, install: @escaping () -> Void, getItemIsPreviewed: @escaping (StickerPackItem) -> Bool, itemContext: StickerPaneSearchGlobalItemContext, sectionTitle: String? = nil) {
self.account = account
public init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, listAppearance: Bool, fillsRow: Bool = true, info: StickerPackCollectionInfo, topItems: [StickerPackItem], topSeparator: Bool, regularInsets: Bool, installed: Bool, installing: Bool = false, unread: Bool, open: @escaping () -> Void, install: @escaping () -> Void, getItemIsPreviewed: @escaping (StickerPackItem) -> Bool, itemContext: StickerPaneSearchGlobalItemContext, sectionTitle: String? = nil) {
self.context = context
self.theme = theme
self.strings = strings
self.listAppearance = listAppearance
@ -199,7 +200,7 @@ public class StickerPaneSearchGlobalItemNode: GridItemNode {
if let item = self.item, self.isVisibleInGrid, !self.preloadedThumbnail {
self.preloadedThumbnail = true
self.preloadedStickerPackThumbnailDisposable.set(preloadedStickerPackThumbnail(account: item.account, info: item.info, items: item.topItems).start())
self.preloadedStickerPackThumbnailDisposable.set(preloadedStickerPackThumbnail(account: item.context.account, info: item.info, items: item.topItems).start())
}
}
}
@ -320,7 +321,7 @@ public class StickerPaneSearchGlobalItemNode: GridItemNode {
public func setup(item: StickerPaneSearchGlobalItem) {
if item.topItems.count < Int(item.info.count) && item.topItems.count < 5 && self.item?.info.id != item.info.id {
self.preloadDisposable.set(preloadedFeaturedStickerSet(network: item.account.network, postbox: item.account.postbox, id: item.info.id).start())
self.preloadDisposable.set(preloadedFeaturedStickerSet(network: item.context.account.network, postbox: item.context.account.postbox, id: item.info.id).start())
}
self.item = item
@ -334,7 +335,7 @@ public class StickerPaneSearchGlobalItemNode: GridItemNode {
return
}
self.canPlayMedia = item.itemContext.canPlayMedia
self.canPlayMedia = item.itemContext.canPlayMedia && item.context.sharedContext.energyUsageSettings.loopStickers
}
public func highlight() {
@ -486,7 +487,7 @@ public class StickerPaneSearchGlobalItemNode: GridItemNode {
strongSelf.addSubnode(node)
}
if file.fileId != node.file?.fileId {
node.setup(account: item.account, item: topItems[i], itemSize: itemSize, synchronousLoads: synchronousLoads)
node.setup(account: item.context.account, item: topItems[i], itemSize: itemSize, synchronousLoads: synchronousLoads)
}
if item.theme !== node.theme {
node.update(theme: item.theme, listAppearance: item.listAppearance)
@ -508,7 +509,7 @@ public class StickerPaneSearchGlobalItemNode: GridItemNode {
}
}
self.canPlayMedia = item.itemContext.canPlayMedia
self.canPlayMedia = item.itemContext.canPlayMedia && item.context.sharedContext.energyUsageSettings.loopStickers
}
@objc func installPressed() {

View File

@ -67,7 +67,7 @@ final class StickerPaneSearchStickerSectionNode: ASDisplayNode {
}
public final class StickerPaneSearchStickerItem: GridItem {
public let account: Account
public let context: AccountContext
public let code: String?
public let stickerItem: FoundStickerItem
public let selected: (ASDisplayNode, CGRect) -> Void
@ -75,8 +75,8 @@ public final class StickerPaneSearchStickerItem: GridItem {
public let section: GridSection?
public init(account: Account, code: String?, stickerItem: FoundStickerItem, inputNodeInteraction: ChatMediaInputNodeInteraction, theme: PresentationTheme, selected: @escaping (ASDisplayNode, CGRect) -> Void) {
self.account = account
public init(context: AccountContext, code: String?, stickerItem: FoundStickerItem, inputNodeInteraction: ChatMediaInputNodeInteraction, theme: PresentationTheme, selected: @escaping (ASDisplayNode, CGRect) -> Void) {
self.context = context
self.stickerItem = stickerItem
self.inputNodeInteraction = inputNodeInteraction
self.selected = selected
@ -87,7 +87,7 @@ public final class StickerPaneSearchStickerItem: GridItem {
public func node(layout: GridNodeLayout, synchronousLoad: Bool) -> GridItemNode {
let node = StickerPaneSearchStickerItemNode()
node.inputNodeInteraction = self.inputNodeInteraction
node.setup(account: self.account, stickerItem: self.stickerItem, code: self.code)
node.setup(context: self.context, stickerItem: self.stickerItem, code: self.code)
node.selected = self.selected
return node
}
@ -98,7 +98,7 @@ public final class StickerPaneSearchStickerItem: GridItem {
return
}
node.inputNodeInteraction = self.inputNodeInteraction
node.setup(account: self.account, stickerItem: self.stickerItem, code: self.code)
node.setup(context: self.context, stickerItem: self.stickerItem, code: self.code)
node.selected = self.selected
}
}
@ -106,7 +106,7 @@ public final class StickerPaneSearchStickerItem: GridItem {
private let textFont = Font.regular(20.0)
public final class StickerPaneSearchStickerItemNode: GridItemNode {
private var currentState: (Account, FoundStickerItem, CGSize)?
private var currentState: (AccountContext, FoundStickerItem, CGSize)?
public let imageNode: TransformImageNode
public private(set) var animationNode: AnimatedStickerNode?
private let textNode: ASTextNode
@ -152,8 +152,8 @@ public final class StickerPaneSearchStickerItemNode: GridItemNode {
self.imageNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.imageNodeTap(_:))))
}
func setup(account: Account, stickerItem: FoundStickerItem, code: String?) {
if self.currentState == nil || self.currentState!.0 !== account || self.currentState!.1 != stickerItem {
func setup(context: AccountContext, stickerItem: FoundStickerItem, code: String?) {
if self.currentState == nil || self.currentState!.0 !== context || self.currentState!.1 != stickerItem {
self.textNode.attributedText = NSAttributedString(string: code ?? "", font: textFont, textColor: .black)
if let dimensions = stickerItem.file.dimensions {
@ -166,20 +166,20 @@ public final class StickerPaneSearchStickerItemNode: GridItemNode {
}
let dimensions = stickerItem.file.dimensions ?? PixelDimensions(width: 512, height: 512)
let fittedDimensions = dimensions.cgSize.aspectFitted(CGSize(width: 160.0, height: 160.0))
self.animationNode?.setup(source: AnimatedStickerResourceSource(account: account, resource: stickerItem.file.resource, isVideo: stickerItem.file.isVideoSticker), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), playbackMode: .loop, mode: .cached)
self.animationNode?.visibility = self.isVisibleInGrid
self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: account, userLocation: .other, fileReference: stickerPackFileReference(stickerItem.file), resource: stickerItem.file.resource).start())
self.animationNode?.setup(source: AnimatedStickerResourceSource(account: context.account, resource: stickerItem.file.resource, isVideo: stickerItem.file.isVideoSticker), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), playbackMode: .loop, mode: .cached)
self.animationNode?.visibility = self.isVisibleInGrid && context.sharedContext.energyUsageSettings.loopStickers
self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: context.account, userLocation: .other, fileReference: stickerPackFileReference(stickerItem.file), resource: stickerItem.file.resource).start())
} else {
if let animationNode = self.animationNode {
animationNode.visibility = false
self.animationNode = nil
animationNode.removeFromSupernode()
}
self.imageNode.setSignal(chatMessageSticker(account: account, userLocation: .other, file: stickerItem.file, small: true))
self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: account, userLocation: .other, fileReference: stickerPackFileReference(stickerItem.file), resource: chatMessageStickerResource(file: stickerItem.file, small: true)).start())
self.imageNode.setSignal(chatMessageSticker(account: context.account, userLocation: .other, file: stickerItem.file, small: true))
self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: context.account, userLocation: .other, fileReference: stickerPackFileReference(stickerItem.file), resource: chatMessageStickerResource(file: stickerItem.file, small: true)).start())
}
self.currentState = (account, stickerItem, dimensions.cgSize)
self.currentState = (context, stickerItem, dimensions.cgSize)
self.setNeedsLayout()
}
}
@ -217,7 +217,11 @@ public final class StickerPaneSearchStickerItemNode: GridItemNode {
}
public func updateVisibility() {
let isPlaying = self.isVisibleInGrid
guard let context = self.currentState?.0 else {
return
}
let isPlaying = self.isVisibleInGrid && context.sharedContext.energyUsageSettings.loopStickers
if self.isPlaying != isPlaying {
self.isPlaying = isPlaying
self.animationNode?.visibility = isPlaying

View File

@ -83,19 +83,23 @@ private final class ItemListRevealOptionNode: ASDisplayNode {
private let iconNode: ASImageNode?
private let animationNode: SimpleAnimationNode?
private let enableAnimations: Bool
private var animationScale: CGFloat = 1.0
private var animationNodeOffset: CGFloat = 0.0
private var animationNodeFlip = false
var alignment: ItemListRevealOptionAlignment?
var isExpanded: Bool = false
init(title: String, icon: ItemListRevealOptionIcon, color: UIColor, textColor: UIColor) {
init(title: String, icon: ItemListRevealOptionIcon, color: UIColor, textColor: UIColor, enableAnimations: Bool) {
self.backgroundNode = ASDisplayNode()
self.highlightNode = ASDisplayNode()
self.titleNode = ASTextNode()
self.titleNode.attributedText = NSAttributedString(string: title, font: icon == .none ? titleFontWithoutIcon : titleFontWithIcon, textColor: textColor)
self.enableAnimations = enableAnimations
switch icon {
case let .image(image):
let iconNode = ASImageNode()
@ -113,6 +117,9 @@ private final class ItemListRevealOptionNode: ASDisplayNode {
}
}
self.animationNode = SimpleAnimationNode(animationName: animation, replaceColors: colors, size: CGSize(width: 79.0, height: 79.0), playOnce: true)
if !enableAnimations {
self.animationNode!.seekToEnd()
}
if flip {
self.animationNode!.transform = CATransform3DMakeScale(1.0, -1.0, 1.0)
}
@ -217,10 +224,12 @@ private final class ItemListRevealOptionNode: ASDisplayNode {
transition.updateFrame(node: self.titleNode, frame: titleFrame)
}
if (abs(revealFactor) >= 0.4) {
animationNode.play()
} else if abs(revealFactor) < CGFloat.ulpOfOne && !transition.isAnimated {
animationNode.reset()
if self.enableAnimations {
if (abs(revealFactor) >= 0.4) {
animationNode.play()
} else if abs(revealFactor) < CGFloat.ulpOfOne && !transition.isAnimated {
animationNode.reset()
}
}
} else if let iconNode = self.iconNode, let imageSize = iconNode.image?.size {
let iconOffset: CGFloat = -9.0
@ -303,7 +312,7 @@ public final class ItemListRevealOptionsNode: ASDisplayNode {
self.view.addGestureRecognizer(gestureRecognizer)
}
public func setOptions(_ options: [ItemListRevealOption], isLeft: Bool) {
public func setOptions(_ options: [ItemListRevealOption], isLeft: Bool, enableAnimations: Bool) {
if self.options != options || self.isLeft != isLeft {
self.options = options
self.isLeft = isLeft
@ -311,7 +320,7 @@ public final class ItemListRevealOptionsNode: ASDisplayNode {
node.removeFromSupernode()
}
self.optionNodes = options.map { option in
return ItemListRevealOptionNode(title: option.title, icon: option.icon, color: option.color, textColor: option.textColor)
return ItemListRevealOptionNode(title: option.title, icon: option.icon, color: option.color, textColor: option.textColor, enableAnimations: enableAnimations)
}
if isLeft {
for node in self.optionNodes.reversed() {

View File

@ -64,6 +64,7 @@ open class ItemListRevealOptionsItemNode: ListViewItemNode, UIGestureRecognizerD
private var leftRevealNode: ItemListRevealOptionsNode?
private var rightRevealNode: ItemListRevealOptionsNode?
private var revealOptions: (left: [ItemListRevealOption], right: [ItemListRevealOption]) = ([], [])
private var enableAnimations: Bool = true
private var initialRevealOffset: CGFloat = 0.0
public private(set) var revealOffset: CGFloat = 0.0
@ -117,13 +118,14 @@ open class ItemListRevealOptionsItemNode: ListViewItemNode, UIGestureRecognizerD
}
}
open func setRevealOptions(_ options: (left: [ItemListRevealOption], right: [ItemListRevealOption])) {
open func setRevealOptions(_ options: (left: [ItemListRevealOption], right: [ItemListRevealOption]), enableAnimations: Bool = true) {
if self.revealOptions == options {
return
}
let previousOptions = self.revealOptions
let wasEmpty = self.revealOptions.left.isEmpty && self.revealOptions.right.isEmpty
self.revealOptions = options
self.enableAnimations = enableAnimations
let isEmpty = options.left.isEmpty && options.right.isEmpty
if options.left.isEmpty {
if let _ = self.leftRevealNode {
@ -329,7 +331,7 @@ open class ItemListRevealOptionsItemNode: ListViewItemNode, UIGestureRecognizerD
}, tapticAction: { [weak self] in
self?.hapticImpact()
})
revealNode.setOptions(self.revealOptions.left, isLeft: true)
revealNode.setOptions(self.revealOptions.left, isLeft: true, enableAnimations: self.enableAnimations)
self.leftRevealNode = revealNode
if let (size, leftInset, _) = self.validLayout {
@ -351,7 +353,7 @@ open class ItemListRevealOptionsItemNode: ListViewItemNode, UIGestureRecognizerD
}, tapticAction: { [weak self] in
self?.hapticImpact()
})
revealNode.setOptions(self.revealOptions.right, isLeft: false)
revealNode.setOptions(self.revealOptions.right, isLeft: false, enableAnimations: self.enableAnimations)
self.rightRevealNode = revealNode
if let (size, _, rightInset) = self.validLayout {

View File

@ -330,6 +330,7 @@ open class ManagedAnimationNode: ASDisplayNode {
public final class SimpleAnimationNode: ManagedAnimationNode {
private let stillItem: ManagedAnimationItem
private let stillEndItem: ManagedAnimationItem
private let animationItem: ManagedAnimationItem
public let size: CGSize
@ -340,6 +341,7 @@ public final class SimpleAnimationNode: ManagedAnimationNode {
self.size = size
self.playOnce = playOnce
self.stillItem = ManagedAnimationItem(source: .local(animationName), replaceColors: replaceColors, frames: .range(startFrame: 0, endFrame: 0), duration: 0.01)
self.stillEndItem = ManagedAnimationItem(source: .local(animationName), replaceColors: replaceColors, frames: .still(.end), duration: 0.01)
self.animationItem = ManagedAnimationItem(source: .local(animationName), replaceColors: replaceColors)
super.init(size: size)
@ -358,4 +360,9 @@ public final class SimpleAnimationNode: ManagedAnimationNode {
self.didPlay = false
self.trackTo(item: self.stillItem)
}
public func seekToEnd() {
self.didPlay = false
self.trackTo(item: self.stillEndItem)
}
}

View File

@ -39,6 +39,7 @@ public final class PasscodeEntryController: ViewController {
private let applicationBindings: TelegramApplicationBindings
private let accountManager: AccountManager<TelegramAccountManagerTypes>
private var energyUsageSettings: EnergyUsageSettings?
private let appLockContext: AppLockContext
private let presentationDataSignal: Signal<PresentationData, NoError>

View File

@ -12,6 +12,7 @@ import AppBundle
import PasscodeInputFieldNode
import MonotonicTime
import GradientBackground
import TelegramUIPreferences
private extension CGRect {
var center: CGPoint {
@ -60,6 +61,9 @@ final class PasscodeEntryControllerNode: ASDisplayNode {
var checkPasscode: ((String) -> Void)?
var requestBiometrics: (() -> Void)?
var energyUsageSettings: EnergyUsageSettings = .default
var energyUsageSettingsDisposable: Disposable?
init(accountManager: AccountManager<TelegramAccountManagerTypes>, presentationData: PresentationData, theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper, passcodeType: PasscodeEntryFieldType, biometricsType: LocalAuthBiometricAuthentication?, arguments: PasscodeEntryControllerPresentationArguments, modalPresentation: Bool) {
self.accountManager = accountManager
self.presentationData = presentationData
@ -105,7 +109,9 @@ final class PasscodeEntryControllerNode: ASDisplayNode {
if let strongSelf = self {
strongSelf.inputFieldNode.append(character)
if let gradientNode = strongSelf.backgroundCustomNode as? GradientBackgroundNode {
gradientNode.animateEvent(transition: .animated(duration: 0.55, curve: .spring), extendAnimation: false, backwards: false, completion: {})
if strongSelf.energyUsageSettings.fullTranslucency {
gradientNode.animateEvent(transition: .animated(duration: 0.55, curve: .spring), extendAnimation: false, backwards: false, completion: {})
}
}
}
}
@ -113,7 +119,9 @@ final class PasscodeEntryControllerNode: ASDisplayNode {
if let strongSelf = self {
let _ = strongSelf.inputFieldNode.delete()
if let gradientNode = strongSelf.backgroundCustomNode as? GradientBackgroundNode {
gradientNode.animateEvent(transition: .animated(duration: 0.55, curve: .spring), extendAnimation: false, backwards: true, completion: {})
if strongSelf.energyUsageSettings.fullTranslucency {
gradientNode.animateEvent(transition: .animated(duration: 0.55, curve: .spring), extendAnimation: false, backwards: true, completion: {})
}
}
}
}
@ -158,6 +166,24 @@ final class PasscodeEntryControllerNode: ASDisplayNode {
if self.arguments.cancel != nil {
self.addSubnode(self.cancelButtonNode)
}
self.energyUsageSettingsDisposable = (accountManager.sharedData(keys: Set([ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings]))
|> deliverOnMainQueue).start(next: { [weak self] sharedData in
guard let self else {
return
}
if let mediaAutoDownloadSettings = sharedData.entries[ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings]?.get(MediaAutoDownloadSettings.self) {
if automaticEnergyUsageShouldBeOnNow(settings: mediaAutoDownloadSettings) {
self.energyUsageSettings = EnergyUsageSettings.powerSavingDefault
} else {
self.energyUsageSettings = mediaAutoDownloadSettings.energyUsageSettings
}
}
})
}
deinit {
self.energyUsageSettingsDisposable?.dispose()
}
override func didLoad() {
@ -183,7 +209,9 @@ final class PasscodeEntryControllerNode: ASDisplayNode {
self.hapticFeedback.tap()
let result = self.inputFieldNode.delete()
if result, let gradientNode = self.backgroundCustomNode as? GradientBackgroundNode {
gradientNode.animateEvent(transition: .animated(duration: 0.55, curve: .spring), extendAnimation: false, backwards: true, completion: {})
if self.energyUsageSettings.fullTranslucency {
gradientNode.animateEvent(transition: .animated(duration: 0.55, curve: .spring), extendAnimation: false, backwards: true, completion: {})
}
}
}
@ -359,7 +387,10 @@ final class PasscodeEntryControllerNode: ASDisplayNode {
if let gradientNode = self.backgroundCustomNode as? GradientBackgroundNode {
gradientNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
self.backgroundDimNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
gradientNode.animateEvent(transition: .animated(duration: 1.0, curve: .spring), extendAnimation: true, backwards: false, completion: {})
if self.energyUsageSettings.fullTranslucency {
gradientNode.animateEvent(transition: .animated(duration: 1.0, curve: .spring), extendAnimation: true, backwards: false, completion: {})
}
}
}
self.titleNode.setAttributedText(NSAttributedString(string: self.strings.EnterPasscode_EnterPasscode, font: titleFont, textColor: .white), animation: .none)
@ -377,9 +408,11 @@ final class PasscodeEntryControllerNode: ASDisplayNode {
}
})
self.backgroundImageNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
if let gradientNode = self.backgroundCustomNode as? GradientBackgroundNode {
if let gradientNode = self.backgroundCustomNode as? GradientBackgroundNode, self.energyUsageSettings.fullTranslucency {
gradientNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
gradientNode.animateEvent(transition: .animated(duration: 0.35, curve: .spring), extendAnimation: false, backwards: false, completion: {})
if self.energyUsageSettings.fullTranslucency {
gradientNode.animateEvent(transition: .animated(duration: 0.35, curve: .spring), extendAnimation: false, backwards: false, completion: {})
}
self.backgroundDimNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
}
if !iconFrame.isEmpty {
@ -411,7 +444,9 @@ final class PasscodeEntryControllerNode: ASDisplayNode {
self.subtitleNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25)
if let gradientNode = self.backgroundCustomNode as? GradientBackgroundNode {
gradientNode.animateEvent(transition: .animated(duration: 1.0, curve: .spring), extendAnimation: false, backwards: false, completion: {})
if self.energyUsageSettings.fullTranslucency {
gradientNode.animateEvent(transition: .animated(duration: 1.0, curve: .spring), extendAnimation: false, backwards: false, completion: {})
}
}
self.inputFieldNode.animateIn()
self.keyboardNode.animateIn()
@ -454,7 +489,9 @@ final class PasscodeEntryControllerNode: ASDisplayNode {
self.hapticFeedback.error()
if let gradientNode = self.backgroundCustomNode as? GradientBackgroundNode {
gradientNode.animateEvent(transition: .animated(duration: 1.5, curve: .spring), extendAnimation: true, backwards: true, completion: {})
if self.energyUsageSettings.fullTranslucency {
gradientNode.animateEvent(transition: .animated(duration: 1.5, curve: .spring), extendAnimation: true, backwards: true, completion: {})
}
}
}

View File

@ -259,7 +259,7 @@ class FormEditableBlockItemNode<Item: FormControllerItem>: ASDisplayNode, FormCo
}, tapticAction: { [weak self] in
self?.hapticImpact()
})
revealNode.setOptions(self.revealOptions.left, isLeft: true)
revealNode.setOptions(self.revealOptions.left, isLeft: true, enableAnimations: true)
self.leftRevealNode = revealNode
if let (size, leftInset, _) = self.validLayout {
@ -281,7 +281,7 @@ class FormEditableBlockItemNode<Item: FormControllerItem>: ASDisplayNode, FormCo
}, tapticAction: { [weak self] in
self?.hapticImpact()
})
revealNode.setOptions(self.revealOptions.right, isLeft: false)
revealNode.setOptions(self.revealOptions.right, isLeft: false, enableAnimations: true)
self.rightRevealNode = revealNode
if let (size, _, rightInset) = self.validLayout {

View File

@ -87,16 +87,16 @@ private enum StickerSearchEntry: Identifiable, Comparable {
}
}
func item(account: Account, theme: PresentationTheme, strings: PresentationStrings, interaction: StickerPaneSearchInteraction, inputNodeInteraction: ChatMediaInputNodeInteraction) -> GridItem {
func item(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, interaction: StickerPaneSearchInteraction, inputNodeInteraction: ChatMediaInputNodeInteraction) -> GridItem {
switch self {
case let .sticker(_, code, stickerItem, theme):
return StickerPaneSearchStickerItem(account: account, code: code, stickerItem: stickerItem, inputNodeInteraction: inputNodeInteraction, theme: theme, selected: { node, rect in
return StickerPaneSearchStickerItem(context: context, code: code, stickerItem: stickerItem, inputNodeInteraction: inputNodeInteraction, theme: theme, selected: { node, rect in
interaction.sendSticker(.standalone(media: stickerItem.file), node.view, rect)
})
case let .global(_, info, topItems, installed, topSeparator):
let itemContext = StickerPaneSearchGlobalItemContext()
itemContext.canPlayMedia = true
return StickerPaneSearchGlobalItem(account: account, theme: theme, strings: strings, listAppearance: false, info: info, topItems: topItems, topSeparator: topSeparator, regularInsets: false, installed: installed, unread: false, open: {
return StickerPaneSearchGlobalItem(context: context, theme: theme, strings: strings, listAppearance: false, info: info, topItems: topItems, topSeparator: topSeparator, regularInsets: false, installed: installed, unread: false, open: {
interaction.open(info)
}, install: {
interaction.install(info, topItems, !installed)
@ -117,7 +117,7 @@ private struct StickerPaneSearchGridTransition {
let animated: Bool
}
private func preparedChatMediaInputGridEntryTransition(account: Account, theme: PresentationTheme, strings: PresentationStrings, from fromEntries: [StickerSearchEntry], to toEntries: [StickerSearchEntry], interaction: StickerPaneSearchInteraction, inputNodeInteraction: ChatMediaInputNodeInteraction) -> StickerPaneSearchGridTransition {
private func preparedChatMediaInputGridEntryTransition(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, from fromEntries: [StickerSearchEntry], to toEntries: [StickerSearchEntry], interaction: StickerPaneSearchInteraction, inputNodeInteraction: ChatMediaInputNodeInteraction) -> StickerPaneSearchGridTransition {
let stationaryItems: GridNodeStationaryItems = .none
let scrollToItem: GridNodeScrollToItem? = nil
var animated = false
@ -126,8 +126,8 @@ private func preparedChatMediaInputGridEntryTransition(account: Account, theme:
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
let deletions = deleteIndices
let insertions = indicesAndItems.map { GridNodeInsertItem(index: $0.0, item: $0.1.item(account: account, theme: theme, strings: strings, interaction: interaction, inputNodeInteraction: inputNodeInteraction), previousIndex: $0.2) }
let updates = updateIndices.map { GridNodeUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, theme: theme, strings: strings, interaction: interaction, inputNodeInteraction: inputNodeInteraction)) }
let insertions = indicesAndItems.map { GridNodeInsertItem(index: $0.0, item: $0.1.item(context: context, theme: theme, strings: strings, interaction: interaction, inputNodeInteraction: inputNodeInteraction), previousIndex: $0.2) }
let updates = updateIndices.map { GridNodeUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, theme: theme, strings: strings, interaction: interaction, inputNodeInteraction: inputNodeInteraction)) }
let firstIndexInSectionOffset = 0
@ -508,7 +508,7 @@ final class StickerPaneSearchContentNode: ASDisplayNode, PaneSearchContentNode {
}
let previousEntries = strongSelf.currentEntries.swap(entries)
let transition = preparedChatMediaInputGridEntryTransition(account: strongSelf.context.account, theme: strongSelf.theme, strings: strongSelf.strings, from: previousEntries ?? [], to: entries, interaction: interaction, inputNodeInteraction: strongSelf.inputNodeInteraction)
let transition = preparedChatMediaInputGridEntryTransition(context: strongSelf.context, theme: strongSelf.theme, strings: strongSelf.strings, from: previousEntries ?? [], to: entries, interaction: interaction, inputNodeInteraction: strongSelf.inputNodeInteraction)
strongSelf.enqueueTransition(transition)
}
}))

View File

@ -366,7 +366,7 @@ final class HashtagChatInputPanelItemNode: ListViewItemNode {
}, tapticAction: { [weak self] in
self?.hapticImpact()
})
revealNode.setOptions(self.revealOptions, isLeft: false)
revealNode.setOptions(self.revealOptions, isLeft: false, enableAnimations: true)
self.revealNode = revealNode
if let (size, _, rightInset) = self.validLayout {

View File

@ -414,7 +414,7 @@ final class MentionChatInputPanelItemNode: ListViewItemNode {
}, tapticAction: { [weak self] in
self?.hapticImpact()
})
revealNode.setOptions(self.revealOptions, isLeft: false)
revealNode.setOptions(self.revealOptions, isLeft: false, enableAnimations: true)
self.revealNode = revealNode
if let (size, _, rightInset) = self.validLayout {