Added option to disable animated stickers looped playback across all the app

This commit is contained in:
Ilya Laktyushin 2019-07-15 18:17:50 +02:00
parent 6ff5c91fa3
commit 0197abb082
20 changed files with 361 additions and 255 deletions

View File

@ -5,6 +5,7 @@ import SwiftSignalKit
import Postbox import Postbox
import TelegramCore import TelegramCore
import TelegramPresentationData import TelegramPresentationData
import TelegramUIPreferences
public enum ArchivedStickerPacksControllerMode { public enum ArchivedStickerPacksControllerMode {
case stickers case stickers
@ -65,7 +66,7 @@ private enum ArchivedStickerPacksEntryId: Hashable {
private enum ArchivedStickerPacksEntry: ItemListNodeEntry { private enum ArchivedStickerPacksEntry: ItemListNodeEntry {
case info(PresentationTheme, String) case info(PresentationTheme, String)
case pack(Int32, PresentationTheme, PresentationStrings, StickerPackCollectionInfo, StickerPackItem?, String, Bool, ItemListStickerPackItemEditing) case pack(Int32, PresentationTheme, PresentationStrings, StickerPackCollectionInfo, StickerPackItem?, String, Bool, Bool, ItemListStickerPackItemEditing)
var section: ItemListSectionId { var section: ItemListSectionId {
switch self { switch self {
@ -78,7 +79,7 @@ private enum ArchivedStickerPacksEntry: ItemListNodeEntry {
switch self { switch self {
case .info: case .info:
return .index(0) return .index(0)
case let .pack(_, _, _, info, _, _, _, _): case let .pack(_, _, _, info, _, _, _, _, _):
return .pack(info.id) return .pack(info.id)
} }
} }
@ -91,8 +92,8 @@ private enum ArchivedStickerPacksEntry: ItemListNodeEntry {
} else { } else {
return false return false
} }
case let .pack(lhsIndex, lhsTheme, lhsStrings, lhsInfo, lhsTopItem, lhsCount, lhsEnabled, lhsEditing): case let .pack(lhsIndex, lhsTheme, lhsStrings, lhsInfo, lhsTopItem, lhsCount, lhsPlayAnimatedStickers, lhsEnabled, lhsEditing):
if case let .pack(rhsIndex, rhsTheme, rhsStrings, rhsInfo, rhsTopItem, rhsCount, rhsEnabled, rhsEditing) = rhs { if case let .pack(rhsIndex, rhsTheme, rhsStrings, rhsInfo, rhsTopItem, rhsCount, rhsPlayAnimatedStickers, rhsEnabled, rhsEditing) = rhs {
if lhsIndex != rhsIndex { if lhsIndex != rhsIndex {
return false return false
} }
@ -111,6 +112,9 @@ private enum ArchivedStickerPacksEntry: ItemListNodeEntry {
if lhsCount != rhsCount { if lhsCount != rhsCount {
return false return false
} }
if lhsPlayAnimatedStickers != rhsPlayAnimatedStickers {
return false
}
if lhsEnabled != rhsEnabled { if lhsEnabled != rhsEnabled {
return false return false
} }
@ -133,9 +137,9 @@ private enum ArchivedStickerPacksEntry: ItemListNodeEntry {
default: default:
return true return true
} }
case let .pack(lhsIndex, _, _, _, _, _, _, _): case let .pack(lhsIndex, _, _, _, _, _, _, _, _):
switch rhs { switch rhs {
case let .pack(rhsIndex, _, _, _, _, _, _, _): case let .pack(rhsIndex, _, _, _, _, _, _, _, _):
return lhsIndex < rhsIndex return lhsIndex < rhsIndex
default: default:
return false return false
@ -147,8 +151,8 @@ private enum ArchivedStickerPacksEntry: ItemListNodeEntry {
switch self { switch self {
case let .info(theme, text): case let .info(theme, text):
return ItemListTextItem(theme: theme, text: .plain(text), sectionId: self.section) return ItemListTextItem(theme: theme, text: .plain(text), sectionId: self.section)
case let .pack(_, theme, strings, info, topItem, count, enabled, editing): case let .pack(_, theme, strings, info, topItem, count, animatedStickers, enabled, editing):
return ItemListStickerPackItem(theme: theme, strings: strings, account: arguments.account, packInfo: info, itemCount: count, topItem: topItem, unread: false, control: .installation(installed: false), editing: editing, enabled: enabled, sectionId: self.section, action: { return ItemListStickerPackItem(theme: theme, strings: strings, account: arguments.account, packInfo: info, itemCount: count, topItem: topItem, unread: false, control: .installation(installed: false), editing: editing, enabled: enabled, playAnimatedStickers: animatedStickers, sectionId: self.section, action: {
arguments.openStickerPack(info) arguments.openStickerPack(info)
}, setPackIdWithRevealedOptions: { current, previous in }, setPackIdWithRevealedOptions: { current, previous in
arguments.setPackIdWithRevealedOptions(current, previous) arguments.setPackIdWithRevealedOptions(current, previous)
@ -205,7 +209,7 @@ private struct ArchivedStickerPacksControllerState: Equatable {
} }
} }
private func archivedStickerPacksControllerEntries(presentationData: PresentationData, state: ArchivedStickerPacksControllerState, packs: [ArchivedStickerPackItem]?, installedView: CombinedView) -> [ArchivedStickerPacksEntry] { private func archivedStickerPacksControllerEntries(presentationData: PresentationData, state: ArchivedStickerPacksControllerState, packs: [ArchivedStickerPackItem]?, installedView: CombinedView, stickerSettings: StickerSettings) -> [ArchivedStickerPacksEntry] {
var entries: [ArchivedStickerPacksEntry] = [] var entries: [ArchivedStickerPacksEntry] = []
if let packs = packs { if let packs = packs {
@ -219,7 +223,7 @@ private func archivedStickerPacksControllerEntries(presentationData: Presentatio
var index: Int32 = 0 var index: Int32 = 0
for item in packs { for item in packs {
if !installedIds.contains(item.info.id) { if !installedIds.contains(item.info.id) {
entries.append(.pack(index, presentationData.theme, presentationData.strings, item.info, item.topItems.first, presentationData.strings.StickerPack_StickerCount(item.info.count), !state.removingPackIds.contains(item.info.id), ItemListStickerPackItemEditing(editable: true, editing: state.editing, revealed: state.packIdWithRevealedOptions == item.info.id, reorderable: false))) entries.append(.pack(index, presentationData.theme, presentationData.strings, item.info, item.topItems.first, presentationData.strings.StickerPack_StickerCount(item.info.count), stickerSettings.loopAnimatedStickers, !state.removingPackIds.contains(item.info.id), ItemListStickerPackItemEditing(editable: true, editing: state.editing, revealed: state.packIdWithRevealedOptions == item.info.id, reorderable: false)))
index += 1 index += 1
} }
} }
@ -369,9 +373,14 @@ public func archivedStickerPacksController(context: AccountContext, mode: Archiv
var previousPackCount: Int? var previousPackCount: Int?
let signal = combineLatest(context.sharedContext.presentationData, statePromise.get() |> deliverOnMainQueue, stickerPacks.get() |> deliverOnMainQueue, installedStickerPacks.get() |> deliverOnMainQueue) let signal = combineLatest(context.sharedContext.presentationData, statePromise.get() |> deliverOnMainQueue, stickerPacks.get() |> deliverOnMainQueue, installedStickerPacks.get() |> deliverOnMainQueue, context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.stickerSettings]) |> deliverOnMainQueue)
|> deliverOnMainQueue |> deliverOnMainQueue
|> map { presentationData, state, packs, installedView -> (ItemListControllerState, (ItemListNodeState<ArchivedStickerPacksEntry>, ArchivedStickerPacksEntry.ItemGenerationArguments)) in |> map { presentationData, state, packs, installedView, sharedData -> (ItemListControllerState, (ItemListNodeState<ArchivedStickerPacksEntry>, ArchivedStickerPacksEntry.ItemGenerationArguments)) in
var stickerSettings = StickerSettings.defaultSettings
if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.stickerSettings] as? StickerSettings {
stickerSettings = value
}
var rightNavigationButton: ItemListNavigationButton? var rightNavigationButton: ItemListNavigationButton?
if let packs = packs, packs.count != 0 { if let packs = packs, packs.count != 0 {
if state.editing { if state.editing {
@ -399,7 +408,7 @@ public func archivedStickerPacksController(context: AccountContext, mode: Archiv
let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(presentationData.strings.StickerPacksSettings_ArchivedPacks), leftNavigationButton: nil, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true) let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(presentationData.strings.StickerPacksSettings_ArchivedPacks), leftNavigationButton: nil, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true)
let listState = ItemListNodeState(entries: archivedStickerPacksControllerEntries(presentationData: presentationData, state: state, packs: packs, installedView: installedView), style: .blocks, emptyStateItem: emptyStateItem, animateChanges: previous != nil && packs != nil && (previous! != 0 && previous! >= packs!.count - 10)) let listState = ItemListNodeState(entries: archivedStickerPacksControllerEntries(presentationData: presentationData, state: state, packs: packs, installedView: installedView, stickerSettings: stickerSettings), style: .blocks, emptyStateItem: emptyStateItem, animateChanges: previous != nil && packs != nil && (previous! != 0 && previous! >= packs!.count - 10))
return (controllerState, (listState, arguments)) return (controllerState, (listState, arguments))
} |> afterDisposed { } |> afterDisposed {
actionsDisposable.dispose() actionsDisposable.dispose()

View File

@ -208,6 +208,9 @@ public final class ChatController: TelegramController, GalleryHiddenMediaTarget,
private var automaticMediaDownloadSettings: MediaAutoDownloadSettings private var automaticMediaDownloadSettings: MediaAutoDownloadSettings
private var automaticMediaDownloadSettingsDisposable: Disposable? private var automaticMediaDownloadSettingsDisposable: Disposable?
private var stickerSettings: ChatInterfaceStickerSettings
private var stickerSettingsDisposable: Disposable?
private var applicationInForegroundDisposable: Disposable? private var applicationInForegroundDisposable: Disposable?
private var checkedPeerChatServiceActions = false private var checkedPeerChatServiceActions = false
@ -264,6 +267,8 @@ public final class ChatController: TelegramController, GalleryHiddenMediaTarget,
self.presentationData = context.sharedContext.currentPresentationData.with { $0 } self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.automaticMediaDownloadSettings = context.sharedContext.currentAutomaticMediaDownloadSettings.with { $0 } self.automaticMediaDownloadSettings = context.sharedContext.currentAutomaticMediaDownloadSettings.with { $0 }
self.stickerSettings = ChatInterfaceStickerSettings(loopAnimatedStickers: false)
self.presentationInterfaceState = ChatPresentationInterfaceState(chatWallpaper: self.presentationData.chatWallpaper, theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder, limitsConfiguration: context.currentLimitsConfiguration.with { $0 }, fontSize: self.presentationData.fontSize, accountPeerId: context.account.peerId, mode: mode, chatLocation: chatLocation) self.presentationInterfaceState = ChatPresentationInterfaceState(chatWallpaper: self.presentationData.chatWallpaper, theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder, limitsConfiguration: context.currentLimitsConfiguration.with { $0 }, fontSize: self.presentationData.fontSize, accountPeerId: context.account.peerId, mode: mode, chatLocation: chatLocation)
var mediaAccessoryPanelVisibility = MediaAccessoryPanelVisibility.none var mediaAccessoryPanelVisibility = MediaAccessoryPanelVisibility.none
@ -1378,8 +1383,7 @@ public final class ChatController: TelegramController, GalleryHiddenMediaTarget,
}, cancelInteractiveKeyboardGestures: { [weak self] in }, cancelInteractiveKeyboardGestures: { [weak self] in
(self?.view.window as? WindowHost)?.cancelInteractiveKeyboardGestures() (self?.view.window as? WindowHost)?.cancelInteractiveKeyboardGestures()
self?.chatDisplayNode.cancelInteractiveKeyboardGestures() self?.chatDisplayNode.cancelInteractiveKeyboardGestures()
}, automaticMediaDownloadSettings: self.automaticMediaDownloadSettings, }, automaticMediaDownloadSettings: self.automaticMediaDownloadSettings, pollActionState: ChatInterfacePollActionState(), stickerSettings: self.stickerSettings)
pollActionState: ChatInterfacePollActionState())
self.controllerInteraction = controllerInteraction self.controllerInteraction = controllerInteraction
@ -1884,6 +1888,24 @@ public final class ChatController: TelegramController, GalleryHiddenMediaTarget,
} }
}) })
self.stickerSettingsDisposable = (context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.stickerSettings])
|> deliverOnMainQueue).start(next: { [weak self] sharedData in
var stickerSettings = StickerSettings.defaultSettings
if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.stickerSettings] as? StickerSettings {
stickerSettings = value
}
let chatStickerSettings = ChatInterfaceStickerSettings(stickerSettings: stickerSettings)
if let strongSelf = self, strongSelf.stickerSettings != chatStickerSettings {
strongSelf.stickerSettings = chatStickerSettings
strongSelf.controllerInteraction?.stickerSettings = chatStickerSettings
if strongSelf.isNodeLoaded {
strongSelf.chatDisplayNode.updateStickerSettings(chatStickerSettings)
}
}
})
self.applicationInForegroundDisposable = (context.sharedContext.applicationBindings.applicationInForeground self.applicationInForegroundDisposable = (context.sharedContext.applicationBindings.applicationInForeground
|> distinctUntilChanged |> distinctUntilChanged
|> deliverOn(Queue.mainQueue())).start(next: { [weak self] value in |> deliverOn(Queue.mainQueue())).start(next: { [weak self] value in

View File

@ -31,6 +31,22 @@ struct ChatInterfaceHighlightedState: Equatable {
} }
} }
struct ChatInterfaceStickerSettings: Equatable {
let loopAnimatedStickers: Bool
public init(loopAnimatedStickers: Bool) {
self.loopAnimatedStickers = loopAnimatedStickers
}
public init(stickerSettings: StickerSettings) {
self.loopAnimatedStickers = stickerSettings.loopAnimatedStickers
}
static func ==(lhs: ChatInterfaceStickerSettings, rhs: ChatInterfaceStickerSettings) -> Bool {
return lhs.loopAnimatedStickers == rhs.loopAnimatedStickers
}
}
public enum ChatControllerInteractionLongTapAction { public enum ChatControllerInteractionLongTapAction {
case url(String) case url(String)
case mention(String) case mention(String)
@ -104,9 +120,10 @@ public final class ChatControllerInteraction {
var contextHighlightedState: ChatInterfaceHighlightedState? var contextHighlightedState: ChatInterfaceHighlightedState?
var automaticMediaDownloadSettings: MediaAutoDownloadSettings var automaticMediaDownloadSettings: MediaAutoDownloadSettings
var pollActionState: ChatInterfacePollActionState var pollActionState: ChatInterfacePollActionState
var stickerSettings: ChatInterfaceStickerSettings
var searchTextHighightState: String? var searchTextHighightState: String?
init(openMessage: @escaping (Message, ChatControllerInteractionOpenMessageMode) -> Bool, openPeer: @escaping (PeerId?, ChatControllerInteractionNavigateToPeer, Message?) -> Void, openPeerMention: @escaping (String) -> Void, openMessageContextMenu: @escaping (Message, Bool, ASDisplayNode, CGRect) -> Void, navigateToMessage: @escaping (MessageId, MessageId) -> Void, clickThroughMessage: @escaping () -> Void, toggleMessagesSelection: @escaping ([MessageId], Bool) -> Void, sendMessage: @escaping (String) -> Void, sendSticker: @escaping (FileMediaReference, Bool) -> Void, sendGif: @escaping (FileMediaReference) -> Void, requestMessageActionCallback: @escaping (MessageId, MemoryBuffer?, Bool) -> Void, requestMessageActionUrlAuth: @escaping (String, MessageId, Int32) -> Void, activateSwitchInline: @escaping (PeerId?, String) -> Void, openUrl: @escaping (String, Bool, Bool?) -> Void, shareCurrentLocation: @escaping () -> Void, shareAccountContact: @escaping () -> Void, sendBotCommand: @escaping (MessageId?, String) -> Void, openInstantPage: @escaping (Message, ChatMessageItemAssociatedData?) -> Void, openWallpaper: @escaping (Message) -> Void, openHashtag: @escaping (String?, String) -> Void, updateInputState: @escaping ((ChatTextInputState) -> ChatTextInputState) -> Void, updateInputMode: @escaping ((ChatInputMode) -> ChatInputMode) -> Void, openMessageShareMenu: @escaping (MessageId) -> Void, presentController: @escaping (ViewController, Any?) -> Void, navigationController: @escaping () -> NavigationController?, presentGlobalOverlayController: @escaping (ViewController, Any?) -> Void, callPeer: @escaping (PeerId) -> Void, longTap: @escaping (ChatControllerInteractionLongTapAction, Message?) -> Void, openCheckoutOrReceipt: @escaping (MessageId) -> Void, openSearch: @escaping () -> Void, setupReply: @escaping (MessageId) -> Void, canSetupReply: @escaping (Message) -> Bool, navigateToFirstDateMessage: @escaping(Int32) ->Void, requestRedeliveryOfFailedMessages: @escaping (MessageId) -> Void, addContact: @escaping (String) -> Void, rateCall: @escaping (Message, CallId) -> Void, requestSelectMessagePollOption: @escaping (MessageId, Data) -> Void, openAppStorePage: @escaping () -> Void, displayMessageTooltip: @escaping (MessageId, String, ASDisplayNode?, CGRect?) -> Void, seekToTimecode: @escaping (Message, Double, Bool) -> Void, requestMessageUpdate: @escaping (MessageId) -> Void, cancelInteractiveKeyboardGestures: @escaping () -> Void, automaticMediaDownloadSettings: MediaAutoDownloadSettings, pollActionState: ChatInterfacePollActionState) { init(openMessage: @escaping (Message, ChatControllerInteractionOpenMessageMode) -> Bool, openPeer: @escaping (PeerId?, ChatControllerInteractionNavigateToPeer, Message?) -> Void, openPeerMention: @escaping (String) -> Void, openMessageContextMenu: @escaping (Message, Bool, ASDisplayNode, CGRect) -> Void, navigateToMessage: @escaping (MessageId, MessageId) -> Void, clickThroughMessage: @escaping () -> Void, toggleMessagesSelection: @escaping ([MessageId], Bool) -> Void, sendMessage: @escaping (String) -> Void, sendSticker: @escaping (FileMediaReference, Bool) -> Void, sendGif: @escaping (FileMediaReference) -> Void, requestMessageActionCallback: @escaping (MessageId, MemoryBuffer?, Bool) -> Void, requestMessageActionUrlAuth: @escaping (String, MessageId, Int32) -> Void, activateSwitchInline: @escaping (PeerId?, String) -> Void, openUrl: @escaping (String, Bool, Bool?) -> Void, shareCurrentLocation: @escaping () -> Void, shareAccountContact: @escaping () -> Void, sendBotCommand: @escaping (MessageId?, String) -> Void, openInstantPage: @escaping (Message, ChatMessageItemAssociatedData?) -> Void, openWallpaper: @escaping (Message) -> Void, openHashtag: @escaping (String?, String) -> Void, updateInputState: @escaping ((ChatTextInputState) -> ChatTextInputState) -> Void, updateInputMode: @escaping ((ChatInputMode) -> ChatInputMode) -> Void, openMessageShareMenu: @escaping (MessageId) -> Void, presentController: @escaping (ViewController, Any?) -> Void, navigationController: @escaping () -> NavigationController?, presentGlobalOverlayController: @escaping (ViewController, Any?) -> Void, callPeer: @escaping (PeerId) -> Void, longTap: @escaping (ChatControllerInteractionLongTapAction, Message?) -> Void, openCheckoutOrReceipt: @escaping (MessageId) -> Void, openSearch: @escaping () -> Void, setupReply: @escaping (MessageId) -> Void, canSetupReply: @escaping (Message) -> Bool, navigateToFirstDateMessage: @escaping(Int32) ->Void, requestRedeliveryOfFailedMessages: @escaping (MessageId) -> Void, addContact: @escaping (String) -> Void, rateCall: @escaping (Message, CallId) -> Void, requestSelectMessagePollOption: @escaping (MessageId, Data) -> Void, openAppStorePage: @escaping () -> Void, displayMessageTooltip: @escaping (MessageId, String, ASDisplayNode?, CGRect?) -> Void, seekToTimecode: @escaping (Message, Double, Bool) -> Void, requestMessageUpdate: @escaping (MessageId) -> Void, cancelInteractiveKeyboardGestures: @escaping () -> Void, automaticMediaDownloadSettings: MediaAutoDownloadSettings, pollActionState: ChatInterfacePollActionState, stickerSettings: ChatInterfaceStickerSettings) {
self.openMessage = openMessage self.openMessage = openMessage
self.openPeer = openPeer self.openPeer = openPeer
self.openPeerMention = openPeerMention self.openPeerMention = openPeerMention
@ -154,6 +171,7 @@ public final class ChatControllerInteraction {
self.automaticMediaDownloadSettings = automaticMediaDownloadSettings self.automaticMediaDownloadSettings = automaticMediaDownloadSettings
self.pollActionState = pollActionState self.pollActionState = pollActionState
self.stickerSettings = stickerSettings
} }
static var `default`: ChatControllerInteraction { static var `default`: ChatControllerInteraction {
@ -175,6 +193,6 @@ public final class ChatControllerInteraction {
}, requestMessageUpdate: { _ in }, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: { }, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, }, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,
pollActionState: ChatInterfacePollActionState()) pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(loopAnimatedStickers: false))
} }
} }

View File

@ -1497,6 +1497,14 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.historyNode.prefetchManager.updateAutoDownloadSettings(settings) self.historyNode.prefetchManager.updateAutoDownloadSettings(settings)
} }
func updateStickerSettings(_ settings: ChatInterfaceStickerSettings) {
self.historyNode.forEachItemNode { itemNode in
if let itemNode = itemNode as? ChatMessageItemView {
itemNode.updateStickerSettings()
}
}
}
var isInputViewFocused: Bool { var isInputViewFocused: Bool {
if let inputPanelNode = self.inputPanelNode as? ChatTextInputPanelNode { if let inputPanelNode = self.inputPanelNode as? ChatTextInputPanelNode {
return inputPanelNode.isFocused return inputPanelNode.isFocused

View File

@ -145,7 +145,6 @@ final class ChatMediaInputStickerGridItem: GridItem {
let node = ChatMediaInputStickerGridItemNode() let node = ChatMediaInputStickerGridItemNode()
node.interfaceInteraction = self.interfaceInteraction node.interfaceInteraction = self.interfaceInteraction
node.inputNodeInteraction = self.inputNodeInteraction node.inputNodeInteraction = self.inputNodeInteraction
node.setup(account: self.account, stickerItem: self.stickerItem)
node.selected = self.selected node.selected = self.selected
return node return node
} }
@ -157,7 +156,6 @@ final class ChatMediaInputStickerGridItem: GridItem {
} }
node.interfaceInteraction = self.interfaceInteraction node.interfaceInteraction = self.interfaceInteraction
node.inputNodeInteraction = self.inputNodeInteraction node.inputNodeInteraction = self.inputNodeInteraction
node.setup(account: self.account, stickerItem: self.stickerItem)
node.selected = self.selected node.selected = self.selected
} }
} }
@ -209,11 +207,6 @@ final class ChatMediaInputStickerGridItemNode: GridItemNode {
self.imageNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.imageNodeTap(_:)))) self.imageNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.imageNodeTap(_:))))
} }
func setup(account: Account, stickerItem: StickerPackItem) {
//self.updateSelectionState(animated: false)
//self.updateHiddenMedia()
}
override func updateLayout(item: GridItem, size: CGSize, isVisible: Bool, synchronousLoads: Bool) { override func updateLayout(item: GridItem, size: CGSize, isVisible: Bool, synchronousLoads: Bool) {
guard let item = item as? ChatMediaInputStickerGridItem else { guard let item = item as? ChatMediaInputStickerGridItem else {
return return
@ -232,13 +225,7 @@ final class ChatMediaInputStickerGridItemNode: GridItemNode {
self.addSubnode(animationNode) self.addSubnode(animationNode)
} }
self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: item.account.postbox, file: item.stickerItem.file, small: false, size: CGSize(width: 160.0, height: 160.0))) self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: item.account.postbox, file: item.stickerItem.file, small: false, size: CGSize(width: 160.0, height: 160.0)))
if self.isPlaying { self.updateVisibility()
self.didSetUpAnimationNode = true
self.animationNode?.setup(account: item.account, resource: item.stickerItem.file.resource, width: 160, height: 160, mode: .cached)
} else {
self.didSetUpAnimationNode = false
}
self.animationNode?.visibility = self.isPlaying
self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: item.account, fileReference: stickerPackFileReference(item.stickerItem.file), resource: item.stickerItem.file.resource).start()) self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: item.account, fileReference: stickerPackFileReference(item.stickerItem.file), resource: item.stickerItem.file.resource).start())
} else { } else {
if let animationNode = self.animationNode { if let animationNode = self.animationNode {
@ -297,7 +284,10 @@ final class ChatMediaInputStickerGridItemNode: GridItemNode {
} }
func updateVisibility() { func updateVisibility() {
let isPlaying = self.isPanelVisible && self.isVisibleInGrid guard let item = self.item else {
return
}
let isPlaying = self.isPanelVisible && self.isVisibleInGrid && (item.interfaceInteraction?.stickerSettings.loopAnimatedStickers ?? true)
if self.isPlaying != isPlaying { if self.isPlaying != isPlaying {
self.isPlaying = isPlaying self.isPlaying = isPlaying
self.animationNode?.visibility = isPlaying self.animationNode?.visibility = isPlaying

View File

@ -103,7 +103,7 @@ final class ChatMediaInputStickerPackItemNode: ListViewItemNode {
override var visibility: ListViewItemNodeVisibility { override var visibility: ListViewItemNodeVisibility {
didSet { didSet {
self.visibilityStatus = self.visibility != .none self.visibilityStatus = self.visibility != .none && false
} }
} }
@ -171,30 +171,30 @@ final class ChatMediaInputStickerPackItemNode: ListViewItemNode {
self.currentThumbnailItem = thumbnailItem self.currentThumbnailItem = thumbnailItem
if let thumbnailItem = thumbnailItem { if let thumbnailItem = thumbnailItem {
switch thumbnailItem { switch thumbnailItem {
case let .still(representation): case let .still(representation):
let imageSize = representation.dimensions.aspectFitted(boundingImageSize) let imageSize = representation.dimensions.aspectFitted(boundingImageSize)
let imageApply = self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: imageSize, boundingSize: imageSize, intrinsicInsets: UIEdgeInsets())) let imageApply = self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: imageSize, boundingSize: imageSize, intrinsicInsets: UIEdgeInsets()))
imageApply() imageApply()
self.imageNode.setSignal(chatMessageStickerPackThumbnail(postbox: account.postbox, representation: representation)) self.imageNode.setSignal(chatMessageStickerPackThumbnail(postbox: account.postbox, representation: representation))
self.imageNode.frame = CGRect(origin: CGPoint(x: floor((boundingSize.width - imageSize.width) / 2.0) + verticalOffset, y: floor((boundingSize.height - imageSize.height) / 2.0)), size: imageSize) self.imageNode.frame = CGRect(origin: CGPoint(x: floor((boundingSize.width - imageSize.width) / 2.0) + verticalOffset, y: floor((boundingSize.height - imageSize.height) / 2.0)), size: imageSize)
case let .animated(resource): case let .animated(resource):
let imageSize = boundingImageSize let imageSize = boundingImageSize
let animatedStickerNode: AnimatedStickerNode let animatedStickerNode: AnimatedStickerNode
if let current = self.animatedStickerNode { if let current = self.animatedStickerNode {
animatedStickerNode = current animatedStickerNode = current
} else { } else {
animatedStickerNode = AnimatedStickerNode() animatedStickerNode = AnimatedStickerNode()
self.animatedStickerNode = animatedStickerNode self.animatedStickerNode = animatedStickerNode
animatedStickerNode.transform = CATransform3DMakeRotation(CGFloat.pi / 2.0, 0.0, 0.0, 1.0) animatedStickerNode.transform = CATransform3DMakeRotation(CGFloat.pi / 2.0, 0.0, 0.0, 1.0)
self.addSubnode(animatedStickerNode) self.addSubnode(animatedStickerNode)
animatedStickerNode.setup(account: account, resource: resource, width: 80, height: 80, mode: .cached) animatedStickerNode.setup(account: account, resource: resource, width: 80, height: 80, mode: .cached)
animatedStickerNode.visibility = self.visibilityStatus animatedStickerNode.visibility = self.visibilityStatus && false
} }
if let animatedStickerNode = self.animatedStickerNode { if let animatedStickerNode = self.animatedStickerNode {
animatedStickerNode.frame = CGRect(origin: CGPoint(x: floor((boundingSize.width - imageSize.width) / 2.0) + verticalOffset, y: floor((boundingSize.height - imageSize.height) / 2.0)), size: imageSize) animatedStickerNode.frame = CGRect(origin: CGPoint(x: floor((boundingSize.width - imageSize.width) / 2.0) + verticalOffset, y: floor((boundingSize.height - imageSize.height) / 2.0)), size: imageSize)
} }
} }
if let resourceReference = resourceReference { if let resourceReference = resourceReference {
self.stickerFetchedDisposable.set(fetchedMediaResource(postbox: account.postbox, reference: resourceReference).start()) self.stickerFetchedDisposable.set(fetchedMediaResource(postbox: account.postbox, reference: resourceReference).start())

View File

@ -17,6 +17,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
let imageNode: TransformImageNode let imageNode: TransformImageNode
private let animationNode: AnimatedStickerNode private let animationNode: AnimatedStickerNode
private var didSetUpAnimationNode = false private var didSetUpAnimationNode = false
private var isPlaying = false
private var swipeToReplyNode: ChatMessageSwipeToReplyNode? private var swipeToReplyNode: ChatMessageSwipeToReplyNode?
private var swipeToReplyFeedback: HapticFeedback? private var swipeToReplyFeedback: HapticFeedback?
@ -90,8 +91,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
} }
self.view.addGestureRecognizer(replyRecognizer) self.view.addGestureRecognizer(replyRecognizer)
} }
private var visibilityPromise = ValuePromise<Bool>(false, ignoreRepeated: true)
override var visibility: ListViewItemNodeVisibility { override var visibility: ListViewItemNodeVisibility {
didSet { didSet {
let wasVisible = oldValue != .none let wasVisible = oldValue != .none
@ -106,21 +106,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
private var visibilityStatus: Bool = false { private var visibilityStatus: Bool = false {
didSet { didSet {
if self.visibilityStatus != oldValue { if self.visibilityStatus != oldValue {
if self.visibilityStatus { self.updateVisibility()
self.animationNode.visibility = true
self.visibilityPromise.set(true)
if let item = self.item, !self.didSetUpAnimationNode {
for media in item.message.media {
if let telegramFile = media as? TelegramMediaFile {
self.didSetUpAnimationNode = true
self.animationNode.setup(account: item.context.account, resource: telegramFile.resource, width: 384, height: 384, mode: .cached)
}
}
}
} else {
self.animationNode.visibility = false
self.visibilityPromise.set(false)
}
} }
} }
} }
@ -133,7 +119,8 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
if self.telegramFile?.id != telegramFile.id { if self.telegramFile?.id != telegramFile.id {
self.telegramFile = telegramFile self.telegramFile = telegramFile
self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: item.context.account.postbox, file: telegramFile, small: false, size: CGSize(width: 384.0, height: 384.0), thumbnail: false)) self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: item.context.account.postbox, file: telegramFile, small: false, size: CGSize(width: 384.0, height: 384.0), thumbnail: false))
if self.visibilityStatus { self.updateVisibility()
if self.visibilityStatus && false {
self.didSetUpAnimationNode = true self.didSetUpAnimationNode = true
self.animationNode.setup(account: item.context.account, resource: telegramFile.resource, width: 384, height: 384, mode: .cached) self.animationNode.setup(account: item.context.account, resource: telegramFile.resource, width: 384, height: 384, mode: .cached)
} }
@ -144,6 +131,31 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
} }
} }
func updateVisibility() {
guard let item = self.item else {
return
}
let isPlaying = self.visibilityStatus && item.controllerInteraction.stickerSettings.loopAnimatedStickers
if self.isPlaying != isPlaying {
self.isPlaying = isPlaying
self.animationNode.visibility = isPlaying
if let item = self.item, isPlaying, !self.didSetUpAnimationNode {
self.didSetUpAnimationNode = true
for media in item.message.media {
if let telegramFile = media as? TelegramMediaFile {
self.animationNode.setup(account: item.context.account, resource: telegramFile.resource, width: 384, height: 384, mode: .cached)
break
}
}
}
}
}
override func updateStickerSettings() {
self.updateVisibility()
}
override func asyncLayout() -> (_ item: ChatMessageItem, _ params: ListViewItemLayoutParams, _ mergedTop: ChatMessageMerge, _ mergedBottom: ChatMessageMerge, _ dateHeaderAtBottom: Bool) -> (ListViewItemNodeLayout, (ListViewItemUpdateAnimation, Bool) -> Void) { override func asyncLayout() -> (_ item: ChatMessageItem, _ params: ListViewItemLayoutParams, _ mergedTop: ChatMessageMerge, _ mergedBottom: ChatMessageMerge, _ dateHeaderAtBottom: Bool) -> (ListViewItemNodeLayout, (ListViewItemUpdateAnimation, Bool) -> Void) {
let displaySize = CGSize(width: 184.0, height: 184.0) let displaySize = CGSize(width: 184.0, height: 184.0)
let telegramFile = self.telegramFile let telegramFile = self.telegramFile

View File

@ -2191,7 +2191,6 @@ class ChatMessageBubbleItemNode: ChatMessageItemView {
} }
} }
override func playMediaWithSound() -> ((Double?) -> Void, Bool, Bool, Bool, ASDisplayNode?)? { override func playMediaWithSound() -> ((Double?) -> Void, Bool, Bool, Bool, ASDisplayNode?)? {
for contentNode in self.contentNodes { for contentNode in self.contentNodes {
if let playMediaWithSound = contentNode.playMediaWithSound() { if let playMediaWithSound = contentNode.playMediaWithSound() {

View File

@ -698,6 +698,9 @@ public class ChatMessageItemView: ListViewItemNode {
func updateAutomaticMediaDownloadSettings() { func updateAutomaticMediaDownloadSettings() {
} }
func updateStickerSettings() {
}
func playMediaWithSound() -> ((Double?) -> Void, Bool, Bool, Bool, ASDisplayNode?)? { func playMediaWithSound() -> ((Double?) -> Void, Bool, Bool, Bool, ASDisplayNode?)? {
return nil return nil
} }

View File

@ -5,6 +5,7 @@ import SwiftSignalKit
import Postbox import Postbox
import TelegramCore import TelegramCore
import TelegramPresentationData import TelegramPresentationData
import TelegramUIPreferences
private final class FeaturedStickerPacksControllerArguments { private final class FeaturedStickerPacksControllerArguments {
let account: Account let account: Account
@ -46,7 +47,7 @@ private enum FeaturedStickerPacksEntryId: Hashable {
} }
private enum FeaturedStickerPacksEntry: ItemListNodeEntry { private enum FeaturedStickerPacksEntry: ItemListNodeEntry {
case pack(Int32, PresentationTheme, PresentationStrings, StickerPackCollectionInfo, Bool, StickerPackItem?, String, Bool) case pack(Int32, PresentationTheme, PresentationStrings, StickerPackCollectionInfo, Bool, StickerPackItem?, String, Bool, Bool)
var section: ItemListSectionId { var section: ItemListSectionId {
switch self { switch self {
@ -57,15 +58,15 @@ private enum FeaturedStickerPacksEntry: ItemListNodeEntry {
var stableId: FeaturedStickerPacksEntryId { var stableId: FeaturedStickerPacksEntryId {
switch self { switch self {
case let .pack(_, _, _, info, _, _, _, _): case let .pack(_, _, _, info, _, _, _, _, _):
return .pack(info.id) return .pack(info.id)
} }
} }
static func ==(lhs: FeaturedStickerPacksEntry, rhs: FeaturedStickerPacksEntry) -> Bool { static func ==(lhs: FeaturedStickerPacksEntry, rhs: FeaturedStickerPacksEntry) -> Bool {
switch lhs { switch lhs {
case let .pack(lhsIndex, lhsTheme, lhsStrings, lhsInfo, lhsUnread, lhsTopItem, lhsCount, lhsInstalled): case let .pack(lhsIndex, lhsTheme, lhsStrings, lhsInfo, lhsUnread, lhsTopItem, lhsCount, lhsPlayAnimatedStickers, lhsInstalled):
if case let .pack(rhsIndex, rhsTheme, rhsStrings, rhsInfo, rhsUnread, rhsTopItem, rhsCount, rhsInstalled) = rhs { if case let .pack(rhsIndex, rhsTheme, rhsStrings, rhsInfo, rhsUnread, rhsTopItem, rhsCount, rhsPlayAnimatedStickers, rhsInstalled) = rhs {
if lhsIndex != rhsIndex { if lhsIndex != rhsIndex {
return false return false
} }
@ -87,6 +88,9 @@ private enum FeaturedStickerPacksEntry: ItemListNodeEntry {
if lhsCount != rhsCount { if lhsCount != rhsCount {
return false return false
} }
if lhsPlayAnimatedStickers != rhsPlayAnimatedStickers {
return false
}
if lhsInstalled != rhsInstalled { if lhsInstalled != rhsInstalled {
return false return false
} }
@ -99,9 +103,9 @@ private enum FeaturedStickerPacksEntry: ItemListNodeEntry {
static func <(lhs: FeaturedStickerPacksEntry, rhs: FeaturedStickerPacksEntry) -> Bool { static func <(lhs: FeaturedStickerPacksEntry, rhs: FeaturedStickerPacksEntry) -> Bool {
switch lhs { switch lhs {
case let .pack(lhsIndex, _, _, _, _, _, _, _): case let .pack(lhsIndex, _, _, _, _, _, _, _, _):
switch rhs { switch rhs {
case let .pack(rhsIndex, _, _, _, _, _, _, _): case let .pack(rhsIndex, _, _, _, _, _, _, _, _):
return lhsIndex < rhsIndex return lhsIndex < rhsIndex
} }
} }
@ -109,8 +113,8 @@ private enum FeaturedStickerPacksEntry: ItemListNodeEntry {
func item(_ arguments: FeaturedStickerPacksControllerArguments) -> ListViewItem { func item(_ arguments: FeaturedStickerPacksControllerArguments) -> ListViewItem {
switch self { switch self {
case let .pack(_, theme, strings, info, unread, topItem, count, installed): case let .pack(_, theme, strings, info, unread, topItem, count, playAnimatedStickers, installed):
return ItemListStickerPackItem(theme: theme, strings: strings, account: arguments.account, packInfo: info, itemCount: count, topItem: topItem, unread: unread, control: .installation(installed: installed), editing: ItemListStickerPackItemEditing(editable: false, editing: false, revealed: false, reorderable: false), enabled: true, sectionId: self.section, action: { return ItemListStickerPackItem(theme: theme, strings: strings, account: arguments.account, packInfo: info, itemCount: count, topItem: topItem, unread: unread, control: .installation(installed: installed), editing: ItemListStickerPackItemEditing(editable: false, editing: false, revealed: false, reorderable: false), enabled: true, playAnimatedStickers: playAnimatedStickers, sectionId: self.section, action: {
arguments.openStickerPack(info) arguments.openStickerPack(info)
}, setPackIdWithRevealedOptions: { _, _ in }, setPackIdWithRevealedOptions: { _, _ in
}, addPack: { }, addPack: {
@ -130,7 +134,7 @@ private struct FeaturedStickerPacksControllerState: Equatable {
} }
} }
private func featuredStickerPacksControllerEntries(presentationData: PresentationData, state: FeaturedStickerPacksControllerState, view: CombinedView, featured: [FeaturedStickerPackItem], unreadPacks: [ItemCollectionId: Bool]) -> [FeaturedStickerPacksEntry] { private func featuredStickerPacksControllerEntries(presentationData: PresentationData, state: FeaturedStickerPacksControllerState, view: CombinedView, featured: [FeaturedStickerPackItem], unreadPacks: [ItemCollectionId: Bool], stickerSettings: StickerSettings) -> [FeaturedStickerPacksEntry] {
var entries: [FeaturedStickerPacksEntry] = [] var entries: [FeaturedStickerPacksEntry] = []
if let stickerPacksView = view.views[.itemCollectionInfos(namespaces: [Namespaces.ItemCollection.CloudStickerPacks])] as? ItemCollectionInfosView, !featured.isEmpty { if let stickerPacksView = view.views[.itemCollectionInfos(namespaces: [Namespaces.ItemCollection.CloudStickerPacks])] as? ItemCollectionInfosView, !featured.isEmpty {
@ -145,7 +149,7 @@ private func featuredStickerPacksControllerEntries(presentationData: Presentatio
if let value = unreadPacks[item.info.id] { if let value = unreadPacks[item.info.id] {
unread = value unread = value
} }
entries.append(.pack(index, presentationData.theme, presentationData.strings, item.info, unread, item.topItems.first, presentationData.strings.StickerPack_StickerCount(item.info.count), installedPacks.contains(item.info.id))) entries.append(.pack(index, presentationData.theme, presentationData.strings, item.info, unread, item.topItems.first, presentationData.strings.StickerPack_StickerCount(item.info.count), stickerSettings.loopAnimatedStickers, installedPacks.contains(item.info.id)))
index += 1 index += 1
} }
} }
@ -195,9 +199,14 @@ public func featuredStickerPacksController(context: AccountContext) -> ViewContr
var previousPackCount: Int? var previousPackCount: Int?
var initialUnreadPacks: [ItemCollectionId: Bool] = [:] var initialUnreadPacks: [ItemCollectionId: Bool] = [:]
let signal = combineLatest(context.sharedContext.presentationData, statePromise.get() |> deliverOnMainQueue, stickerPacks.get() |> deliverOnMainQueue, featured.get() |> deliverOnMainQueue) let signal = combineLatest(context.sharedContext.presentationData, statePromise.get() |> deliverOnMainQueue, stickerPacks.get() |> deliverOnMainQueue, featured.get() |> deliverOnMainQueue, context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.stickerSettings]) |> deliverOnMainQueue)
|> deliverOnMainQueue |> deliverOnMainQueue
|> map { presentationData, state, view, featured -> (ItemListControllerState, (ItemListNodeState<FeaturedStickerPacksEntry>, FeaturedStickerPacksEntry.ItemGenerationArguments)) in |> map { presentationData, state, view, featured, sharedData -> (ItemListControllerState, (ItemListNodeState<FeaturedStickerPacksEntry>, FeaturedStickerPacksEntry.ItemGenerationArguments)) in
var stickerSettings = StickerSettings.defaultSettings
if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.stickerSettings] as? StickerSettings {
stickerSettings = value
}
let packCount: Int? = featured.count let packCount: Int? = featured.count
for item in featured { for item in featured {
@ -212,7 +221,7 @@ public func featuredStickerPacksController(context: AccountContext) -> ViewContr
let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(presentationData.strings.FeaturedStickerPacks_Title), leftNavigationButton: nil, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true) let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(presentationData.strings.FeaturedStickerPacks_Title), leftNavigationButton: nil, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true)
let listState = ItemListNodeState(entries: featuredStickerPacksControllerEntries(presentationData: presentationData, state: state, view: view, featured: featured, unreadPacks: initialUnreadPacks), style: .blocks, animateChanges: false) let listState = ItemListNodeState(entries: featuredStickerPacksControllerEntries(presentationData: presentationData, state: state, view: view, featured: featured, unreadPacks: initialUnreadPacks, stickerSettings: stickerSettings), style: .blocks, animateChanges: false)
return (controllerState, (listState, arguments)) return (controllerState, (listState, arguments))
} |> afterDisposed { } |> afterDisposed {
actionsDisposable.dispose() actionsDisposable.dispose()
@ -226,7 +235,7 @@ public func featuredStickerPacksController(context: AccountContext) -> ViewContr
var unreadIds: [ItemCollectionId] = [] var unreadIds: [ItemCollectionId] = []
for entry in entries { for entry in entries {
switch entry { switch entry {
case let .pack(_, _, _, info, unread, _, _, _): case let .pack(_, _, _, info, unread, _, _, _, _):
if unread && !alreadyReadIds.contains(info.id) { if unread && !alreadyReadIds.contains(info.id) {
unreadIds.append(info.id) unreadIds.append(info.id)
} }

View File

@ -5,6 +5,7 @@ import SwiftSignalKit
import Postbox import Postbox
import TelegramCore import TelegramCore
import TelegramPresentationData import TelegramPresentationData
import TelegramUIPreferences
private final class GroupStickerPackSetupControllerArguments { private final class GroupStickerPackSetupControllerArguments {
let account: Account let account: Account
@ -64,7 +65,7 @@ private enum GroupStickerPackEntry: ItemListNodeEntry {
case currentPack(Int32, PresentationTheme, PresentationStrings, GroupStickerPackCurrentItemContent) case currentPack(Int32, PresentationTheme, PresentationStrings, GroupStickerPackCurrentItemContent)
case searchInfo(PresentationTheme, String) case searchInfo(PresentationTheme, String)
case packsTitle(PresentationTheme, String) case packsTitle(PresentationTheme, String)
case pack(Int32, PresentationTheme, PresentationStrings, StickerPackCollectionInfo, StickerPackItem?, String, Bool) case pack(Int32, PresentationTheme, PresentationStrings, StickerPackCollectionInfo, StickerPackItem?, String, Bool, Bool)
var section: ItemListSectionId { var section: ItemListSectionId {
switch self { switch self {
@ -85,7 +86,7 @@ private enum GroupStickerPackEntry: ItemListNodeEntry {
return .index(2) return .index(2)
case .packsTitle: case .packsTitle:
return .index(3) return .index(3)
case let .pack(_, _, _, info, _, _, _): case let .pack(_, _, _, info, _, _, _, _):
return .pack(info.id) return .pack(info.id)
} }
} }
@ -128,8 +129,8 @@ private enum GroupStickerPackEntry: ItemListNodeEntry {
} else { } else {
return false return false
} }
case let .pack(lhsIndex, lhsTheme, lhsStrings, lhsInfo, lhsTopItem, lhsCount, lhsSelected): case let .pack(lhsIndex, lhsTheme, lhsStrings, lhsInfo, lhsTopItem, lhsCount, lhsPlayAnimatedStickers, lhsSelected):
if case let .pack(rhsIndex, rhsTheme, rhsStrings, rhsInfo, rhsTopItem, rhsCount, rhsSelected) = rhs { if case let .pack(rhsIndex, rhsTheme, rhsStrings, rhsInfo, rhsTopItem, rhsCount, rhsPlayAnimatedStickers, rhsSelected) = rhs {
if lhsIndex != rhsIndex { if lhsIndex != rhsIndex {
return false return false
} }
@ -148,6 +149,9 @@ private enum GroupStickerPackEntry: ItemListNodeEntry {
if lhsCount != rhsCount { if lhsCount != rhsCount {
return false return false
} }
if lhsPlayAnimatedStickers != rhsPlayAnimatedStickers {
return false
}
if lhsSelected != rhsSelected { if lhsSelected != rhsSelected {
return false return false
} }
@ -188,9 +192,9 @@ private enum GroupStickerPackEntry: ItemListNodeEntry {
default: default:
return true return true
} }
case let .pack(lhsIndex, _, _, _, _, _, _): case let .pack(lhsIndex, _, _, _, _, _, _, _):
switch rhs { switch rhs {
case let .pack(rhsIndex, _, _, _, _, _, _): case let .pack(rhsIndex, _, _, _, _, _, _, _):
return lhsIndex < rhsIndex return lhsIndex < rhsIndex
default: default:
return false return false
@ -216,8 +220,8 @@ private enum GroupStickerPackEntry: ItemListNodeEntry {
return ItemListTextItem(theme: theme, text: .plain(text), sectionId: self.section, linkAction: nil) return ItemListTextItem(theme: theme, text: .plain(text), sectionId: self.section, linkAction: nil)
case let .packsTitle(theme, text): case let .packsTitle(theme, text):
return ItemListSectionHeaderItem(theme: theme, text: text, sectionId: self.section) return ItemListSectionHeaderItem(theme: theme, text: text, sectionId: self.section)
case let .pack(_, theme, strings, info, topItem, count, selected): case let .pack(_, theme, strings, info, topItem, count, playAnimatedStickers, selected):
return ItemListStickerPackItem(theme: theme, strings: strings, account: arguments.account, packInfo: info, itemCount: count, topItem: topItem, unread: false, control: selected ? .selection : .none, editing: ItemListStickerPackItemEditing(editable: false, editing: false, revealed: false, reorderable: false), enabled: true, sectionId: self.section, action: { return ItemListStickerPackItem(theme: theme, strings: strings, account: arguments.account, packInfo: info, itemCount: count, topItem: topItem, unread: false, control: selected ? .selection : .none, editing: ItemListStickerPackItemEditing(editable: false, editing: false, revealed: false, reorderable: false), enabled: true, playAnimatedStickers: playAnimatedStickers, sectionId: self.section, action: {
if selected { if selected {
arguments.openStickerPack(info) arguments.openStickerPack(info)
} else { } else {
@ -258,7 +262,7 @@ private struct GroupStickerPackSetupControllerState: Equatable {
var isSaving: Bool var isSaving: Bool
} }
private func groupStickerPackSetupControllerEntries(presentationData: PresentationData, searchText: String, view: CombinedView, initialData: InitialStickerPackData?, searchState: GroupStickerPackSearchState) -> [GroupStickerPackEntry] { private func groupStickerPackSetupControllerEntries(presentationData: PresentationData, searchText: String, view: CombinedView, initialData: InitialStickerPackData?, searchState: GroupStickerPackSearchState, stickerSettings: StickerSettings) -> [GroupStickerPackEntry] {
if initialData == nil { if initialData == nil {
return [] return []
} }
@ -288,7 +292,7 @@ private func groupStickerPackSetupControllerEntries(presentationData: Presentati
if case let .found(found) = searchState { if case let .found(found) = searchState {
selected = found.info.id == info.id selected = found.info.id == info.id
} }
entries.append(.pack(index, presentationData.theme, presentationData.strings, info, entry.firstItem as? StickerPackItem, presentationData.strings.StickerPack_StickerCount(info.count == 0 ? entry.count : info.count), selected)) entries.append(.pack(index, presentationData.theme, presentationData.strings, info, entry.firstItem as? StickerPackItem, presentationData.strings.StickerPack_StickerCount(info.count == 0 ? entry.count : info.count), stickerSettings.loopAnimatedStickers, selected))
index += 1 index += 1
} }
} }
@ -400,66 +404,71 @@ public func groupStickerPackSetupController(context: AccountContext, peerId: Pee
let previousHadData = Atomic<Bool>(value: false) let previousHadData = Atomic<Bool>(value: false)
let signal = combineLatest(context.sharedContext.presentationData, statePromise.get() |> deliverOnMainQueue, initialData.get() |> deliverOnMainQueue, stickerPacks.get() |> deliverOnMainQueue, searchState.get() |> deliverOnMainQueue) let signal = combineLatest(context.sharedContext.presentationData, statePromise.get() |> deliverOnMainQueue, initialData.get() |> deliverOnMainQueue, stickerPacks.get() |> deliverOnMainQueue, searchState.get() |> deliverOnMainQueue, context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.stickerSettings]) |> deliverOnMainQueue)
|> map { presentationData, state, initialData, view, searchState -> (ItemListControllerState, (ItemListNodeState<GroupStickerPackEntry>, GroupStickerPackEntry.ItemGenerationArguments)) in |> map { presentationData, state, initialData, view, searchState, sharedData -> (ItemListControllerState, (ItemListNodeState<GroupStickerPackEntry>, GroupStickerPackEntry.ItemGenerationArguments)) in
let leftNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Cancel), style: .regular, enabled: true, action: { var stickerSettings = StickerSettings.defaultSettings
dismissImpl?() if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.stickerSettings] as? StickerSettings {
}) stickerSettings = value
}
var rightNavigationButton: ItemListNavigationButton?
if initialData != nil { let leftNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Cancel), style: .regular, enabled: true, action: {
if state.isSaving { dismissImpl?()
rightNavigationButton = ItemListNavigationButton(content: .text(""), style: .activity, enabled: true, action: {}) })
} else {
let enabled: Bool var rightNavigationButton: ItemListNavigationButton?
var info: StickerPackCollectionInfo? if initialData != nil {
switch searchState.1 { if state.isSaving {
case .searching, .notFound: rightNavigationButton = ItemListNavigationButton(content: .text(""), style: .activity, enabled: true, action: {})
enabled = false } else {
case .none: let enabled: Bool
enabled = true var info: StickerPackCollectionInfo?
case let .found(data): switch searchState.1 {
enabled = true case .searching, .notFound:
info = data.info enabled = false
} case .none:
rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Done), style: .bold, enabled: enabled, action: { enabled = true
if info?.id == currentPackInfo?.id { case let .found(data):
dismissImpl?() enabled = true
} else { info = data.info
}
rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Done), style: .bold, enabled: enabled, action: {
if info?.id == currentPackInfo?.id {
dismissImpl?()
} else {
updateState { state in
var state = state
state.isSaving = true
return state
}
saveDisposable.set((updateGroupSpecificStickerset(postbox: context.account.postbox, network: context.account.network, peerId: peerId, info: info)
|> deliverOnMainQueue).start(error: { _ in
updateState { state in updateState { state in
var state = state var state = state
state.isSaving = true state.isSaving = false
return state return state
} }
saveDisposable.set((updateGroupSpecificStickerset(postbox: context.account.postbox, network: context.account.network, peerId: peerId, info: info) }, completed: {
|> deliverOnMainQueue).start(error: { _ in dismissImpl?()
updateState { state in }))
var state = state }
state.isSaving = false })
return state
}
}, completed: {
dismissImpl?()
}))
}
})
}
} }
}
let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(presentationData.strings.Channel_Info_Stickers), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true)
let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(presentationData.strings.Channel_Info_Stickers), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true)
let hasData = initialData != nil
let hadData = previousHadData.swap(hasData) let hasData = initialData != nil
let hadData = previousHadData.swap(hasData)
var emptyStateItem: ItemListLoadingIndicatorEmptyStateItem?
if !hasData { var emptyStateItem: ItemListLoadingIndicatorEmptyStateItem?
emptyStateItem = ItemListLoadingIndicatorEmptyStateItem(theme: presentationData.theme) if !hasData {
} emptyStateItem = ItemListLoadingIndicatorEmptyStateItem(theme: presentationData.theme)
}
let listState = ItemListNodeState(entries: groupStickerPackSetupControllerEntries(presentationData: presentationData, searchText: searchState.0, view: view, initialData: initialData, searchState: searchState.1), style: .blocks, emptyStateItem: emptyStateItem, animateChanges: hasData && hadData)
return (controllerState, (listState, arguments)) let listState = ItemListNodeState(entries: groupStickerPackSetupControllerEntries(presentationData: presentationData, searchText: searchState.0, view: view, initialData: initialData, searchState: searchState.1, stickerSettings: stickerSettings), style: .blocks, emptyStateItem: emptyStateItem, animateChanges: hasData && hadData)
} |> afterDisposed { return (controllerState, (listState, arguments))
actionsDisposable.dispose() } |> afterDisposed {
actionsDisposable.dispose()
} }
let controller = ItemListController(context: context, state: signal) let controller = ItemListController(context: context, state: signal)

View File

@ -18,8 +18,9 @@ private final class InstalledStickerPacksControllerArguments {
let openFeatured: () -> Void let openFeatured: () -> Void
let openArchived: ([ArchivedStickerPackItem]?) -> Void let openArchived: ([ArchivedStickerPackItem]?) -> Void
let openSuggestOptions: () -> Void let openSuggestOptions: () -> Void
let toggleAnimatedStickers: (Bool) -> Void
init(account: Account, openStickerPack: @escaping (StickerPackCollectionInfo) -> Void, setPackIdWithRevealedOptions: @escaping (ItemCollectionId?, ItemCollectionId?) -> Void, removePack: @escaping (ArchivedStickerPackItem) -> Void, openStickersBot: @escaping () -> Void, openMasks: @escaping () -> Void, openFeatured: @escaping () -> Void, openArchived: @escaping ([ArchivedStickerPackItem]?) -> Void, openSuggestOptions: @escaping () -> Void) { init(account: Account, openStickerPack: @escaping (StickerPackCollectionInfo) -> Void, setPackIdWithRevealedOptions: @escaping (ItemCollectionId?, ItemCollectionId?) -> Void, removePack: @escaping (ArchivedStickerPackItem) -> Void, openStickersBot: @escaping () -> Void, openMasks: @escaping () -> Void, openFeatured: @escaping () -> Void, openArchived: @escaping ([ArchivedStickerPackItem]?) -> Void, openSuggestOptions: @escaping () -> Void, toggleAnimatedStickers: @escaping (Bool) -> Void) {
self.account = account self.account = account
self.openStickerPack = openStickerPack self.openStickerPack = openStickerPack
self.setPackIdWithRevealedOptions = setPackIdWithRevealedOptions self.setPackIdWithRevealedOptions = setPackIdWithRevealedOptions
@ -29,6 +30,7 @@ private final class InstalledStickerPacksControllerArguments {
self.openFeatured = openFeatured self.openFeatured = openFeatured
self.openArchived = openArchived self.openArchived = openArchived
self.openSuggestOptions = openSuggestOptions self.openSuggestOptions = openSuggestOptions
self.toggleAnimatedStickers = toggleAnimatedStickers
} }
} }
@ -85,13 +87,15 @@ private enum InstalledStickerPacksEntry: ItemListNodeEntry {
case trending(PresentationTheme, String, Int32) case trending(PresentationTheme, String, Int32)
case archived(PresentationTheme, String, Int32, [ArchivedStickerPackItem]?) case archived(PresentationTheme, String, Int32, [ArchivedStickerPackItem]?)
case masks(PresentationTheme, String) case masks(PresentationTheme, String)
case animatedStickers(PresentationTheme, String, Bool)
case animatedStickersInfo(PresentationTheme, String)
case packsTitle(PresentationTheme, String) case packsTitle(PresentationTheme, String)
case pack(Int32, PresentationTheme, PresentationStrings, StickerPackCollectionInfo, StickerPackItem?, String, Bool, ItemListStickerPackItemEditing) case pack(Int32, PresentationTheme, PresentationStrings, StickerPackCollectionInfo, StickerPackItem?, String, Bool, Bool, ItemListStickerPackItemEditing)
case packsInfo(PresentationTheme, String) case packsInfo(PresentationTheme, String)
var section: ItemListSectionId { var section: ItemListSectionId {
switch self { switch self {
case .suggestOptions, .trending, .masks, .archived: case .suggestOptions, .trending, .masks, .archived, .animatedStickers, .animatedStickersInfo:
return InstalledStickerPacksSection.service.rawValue return InstalledStickerPacksSection.service.rawValue
case .packsTitle, .pack, .packsInfo: case .packsTitle, .pack, .packsInfo:
return InstalledStickerPacksSection.stickers.rawValue return InstalledStickerPacksSection.stickers.rawValue
@ -108,12 +112,16 @@ private enum InstalledStickerPacksEntry: ItemListNodeEntry {
return .index(2) return .index(2)
case .masks: case .masks:
return .index(3) return .index(3)
case .packsTitle: case .animatedStickers:
return .index(4) return .index(4)
case let .pack(_, _, _, info, _, _, _, _): case .animatedStickersInfo:
return .index(5)
case .packsTitle:
return .index(6)
case let .pack(_, _, _, info, _, _, _, _, _):
return .pack(info.id) return .pack(info.id)
case .packsInfo: case .packsInfo:
return .index(5) return .index(7)
} }
} }
@ -143,14 +151,26 @@ private enum InstalledStickerPacksEntry: ItemListNodeEntry {
} else { } else {
return false return false
} }
case let .animatedStickers(lhsTheme, lhsText, lhsValue):
if case let .animatedStickers(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
return true
} else {
return false
}
case let .animatedStickersInfo(lhsTheme, lhsText):
if case let .animatedStickersInfo(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true
} else {
return false
}
case let .packsTitle(lhsTheme, lhsText): case let .packsTitle(lhsTheme, lhsText):
if case let .packsTitle(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { if case let .packsTitle(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true return true
} else { } else {
return false return false
} }
case let .pack(lhsIndex, lhsTheme, lhsStrings, lhsInfo, lhsTopItem, lhsCount, lhsEnabled, lhsEditing): case let .pack(lhsIndex, lhsTheme, lhsStrings, lhsInfo, lhsTopItem, lhsCount, lhsAnimatedStickers, lhsEnabled, lhsEditing):
if case let .pack(rhsIndex, rhsTheme, rhsStrings, rhsInfo, rhsTopItem, rhsCount, rhsEnabled, rhsEditing) = rhs { if case let .pack(rhsIndex, rhsTheme, rhsStrings, rhsInfo, rhsTopItem, rhsCount, rhsAnimatedStickers, rhsEnabled, rhsEditing) = rhs {
if lhsIndex != rhsIndex { if lhsIndex != rhsIndex {
return false return false
} }
@ -169,6 +189,9 @@ private enum InstalledStickerPacksEntry: ItemListNodeEntry {
if lhsCount != rhsCount { if lhsCount != rhsCount {
return false return false
} }
if lhsAnimatedStickers != rhsAnimatedStickers {
return false
}
if lhsEnabled != rhsEnabled { if lhsEnabled != rhsEnabled {
return false return false
} }
@ -218,16 +241,30 @@ private enum InstalledStickerPacksEntry: ItemListNodeEntry {
default: default:
return true return true
} }
case .packsTitle: case .animatedStickers:
switch rhs { switch rhs {
case .suggestOptions, .trending, .masks, .archived, .packsTitle: case .suggestOptions, .trending, .archived, .masks, .animatedStickers:
return false return false
default: default:
return true return true
} }
case let .pack(lhsIndex, _, _, _, _, _, _, _): case .animatedStickersInfo:
switch rhs { switch rhs {
case let .pack(rhsIndex, _, _, _, _, _, _, _): case .suggestOptions, .trending, .archived, .masks, .animatedStickers, .animatedStickersInfo:
return false
default:
return true
}
case .packsTitle:
switch rhs {
case .suggestOptions, .trending, .masks, .archived, .animatedStickers, .animatedStickersInfo, .packsTitle:
return false
default:
return true
}
case let .pack(lhsIndex, _, _, _, _, _, _, _, _):
switch rhs {
case let .pack(rhsIndex, _, _, _, _, _, _, _, _):
return lhsIndex < rhsIndex return lhsIndex < rhsIndex
case .packsInfo: case .packsInfo:
return true return true
@ -262,10 +299,16 @@ private enum InstalledStickerPacksEntry: ItemListNodeEntry {
return ItemListDisclosureItem(theme: theme, title: text, label: count == 0 ? "" : "\(count)", sectionId: self.section, style: .blocks, action: { return ItemListDisclosureItem(theme: theme, title: text, label: count == 0 ? "" : "\(count)", sectionId: self.section, style: .blocks, action: {
arguments.openArchived(archived) arguments.openArchived(archived)
}) })
case let .animatedStickers(theme, text, value):
return ItemListSwitchItem(theme: theme, title: text, value: value, sectionId: self.section, style: .blocks, updated: { value in
arguments.toggleAnimatedStickers(value)
})
case let .animatedStickersInfo(theme, text):
return ItemListTextItem(theme: theme, text: .plain(text), sectionId: self.section)
case let .packsTitle(theme, text): case let .packsTitle(theme, text):
return ItemListSectionHeaderItem(theme: theme, text: text, sectionId: self.section) return ItemListSectionHeaderItem(theme: theme, text: text, sectionId: self.section)
case let .pack(_, theme, strings, info, topItem, count, enabled, editing): case let .pack(_, theme, strings, info, topItem, count, animatedStickers, enabled, editing):
return ItemListStickerPackItem(theme: theme, strings: strings, account: arguments.account, packInfo: info, itemCount: count, topItem: topItem, unread: false, control: .none, editing: editing, enabled: enabled, sectionId: self.section, action: { return ItemListStickerPackItem(theme: theme, strings: strings, account: arguments.account, packInfo: info, itemCount: count, topItem: topItem, unread: false, control: .none, editing: editing, enabled: enabled, playAnimatedStickers: animatedStickers, sectionId: self.section, action: {
arguments.openStickerPack(info) arguments.openStickerPack(info)
}, setPackIdWithRevealedOptions: { current, previous in }, setPackIdWithRevealedOptions: { current, previous in
arguments.setPackIdWithRevealedOptions(current, previous) arguments.setPackIdWithRevealedOptions(current, previous)
@ -353,6 +396,10 @@ private func installedStickerPacksControllerEntries(presentationData: Presentati
entries.append(.archived(presentationData.theme, presentationData.strings.StickerPacksSettings_ArchivedPacks, Int32(archived.count), archived)) entries.append(.archived(presentationData.theme, presentationData.strings.StickerPacksSettings_ArchivedPacks, Int32(archived.count), archived))
} }
entries.append(.masks(presentationData.theme, presentationData.strings.MaskStickerSettings_Title)) entries.append(.masks(presentationData.theme, presentationData.strings.MaskStickerSettings_Title))
entries.append(.animatedStickers(presentationData.theme, presentationData.strings.StickerPacksSettings_AnimatedStickers, stickerSettings.loopAnimatedStickers))
entries.append(.animatedStickersInfo(presentationData.theme, presentationData.strings.StickerPacksSettings_AnimatedStickersInfo))
entries.append(.packsTitle(presentationData.theme, presentationData.strings.StickerPacksSettings_StickerPacksSection)) entries.append(.packsTitle(presentationData.theme, presentationData.strings.StickerPacksSettings_StickerPacksSection))
case .masks: case .masks:
if let archived = archived, !archived.isEmpty { if let archived = archived, !archived.isEmpty {
@ -365,7 +412,7 @@ private func installedStickerPacksControllerEntries(presentationData: Presentati
var index: Int32 = 0 var index: Int32 = 0
for entry in packsEntries { for entry in packsEntries {
if let info = entry.info as? StickerPackCollectionInfo { if let info = entry.info as? StickerPackCollectionInfo {
entries.append(.pack(index, presentationData.theme, presentationData.strings, info, entry.firstItem as? StickerPackItem, presentationData.strings.StickerPack_StickerCount(info.count == 0 ? entry.count : info.count), true, ItemListStickerPackItemEditing(editable: true, editing: state.editing, revealed: state.packIdWithRevealedOptions == entry.id, reorderable: true))) entries.append(.pack(index, presentationData.theme, presentationData.strings, info, entry.firstItem as? StickerPackItem, presentationData.strings.StickerPack_StickerCount(info.count == 0 ? entry.count : info.count), stickerSettings.loopAnimatedStickers, true, ItemListStickerPackItemEditing(editable: true, editing: state.editing, revealed: state.packIdWithRevealedOptions == entry.id, reorderable: true)))
index += 1 index += 1
} }
} }
@ -505,18 +552,10 @@ public func installedStickerPacksController(context: AccountContext, mode: Insta
ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { dismissAction() })]) ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { dismissAction() })])
]) ])
presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
/* }, toggleAnimatedStickers: { value in
let suggestString: String let _ = updateStickerSettingsInteractively(accountManager: context.sharedContext.accountManager, { current in
switch stickerSettings.emojiStickerSuggestionMode { return current.withUpdatedLoopAnimatedStickers(value)
case .none: }).start()
suggestString = presentationData.strings.Stickers_SuggestNone
case .all:
case .installed:
suggestString = presentationData.strings.Stickers_SuggestAdded
}
*/
}) })
let stickerPacks = Promise<CombinedView>() let stickerPacks = Promise<CombinedView>()
stickerPacks.set(context.account.postbox.combinedView(keys: [.itemCollectionInfos(namespaces: [namespaceForMode(mode)])])) stickerPacks.set(context.account.postbox.combinedView(keys: [.itemCollectionInfos(namespaces: [namespaceForMode(mode)])]))
@ -531,10 +570,8 @@ public func installedStickerPacksController(context: AccountContext, mode: Insta
featured.set(.single([])) featured.set(.single([]))
archivedPromise.set(.single(nil) |> then(archivedStickerPacks(account: context.account, namespace: .masks) |> map(Optional.init))) archivedPromise.set(.single(nil) |> then(archivedStickerPacks(account: context.account, namespace: .masks) |> map(Optional.init)))
} }
var previousPackCount: Int? var previousPackCount: Int?
let signal = combineLatest(queue: .mainQueue(), context.sharedContext.presentationData, statePromise.get(), stickerPacks.get(), combineLatest(queue: .mainQueue(), featured.get(), archivedPromise.get()), context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.stickerSettings])) let signal = combineLatest(queue: .mainQueue(), context.sharedContext.presentationData, statePromise.get(), stickerPacks.get(), combineLatest(queue: .mainQueue(), featured.get(), archivedPromise.get()), context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.stickerSettings]))
|> deliverOnMainQueue |> deliverOnMainQueue
|> map { presentationData, state, view, featuredAndArchived, sharedData -> (ItemListControllerState, (ItemListNodeState<InstalledStickerPacksEntry>, InstalledStickerPacksEntry.ItemGenerationArguments)) in |> map { presentationData, state, view, featuredAndArchived, sharedData -> (ItemListControllerState, (ItemListNodeState<InstalledStickerPacksEntry>, InstalledStickerPacksEntry.ItemGenerationArguments)) in
@ -549,12 +586,6 @@ public func installedStickerPacksController(context: AccountContext, mode: Insta
} }
let leftNavigationButton: ItemListNavigationButton? = nil let leftNavigationButton: ItemListNavigationButton? = nil
/*if case .modal = mode {
leftNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Cancel), style: .regular, enabled: true, action: {
dismissImpl?()
})
}*/
var rightNavigationButton: ItemListNavigationButton? var rightNavigationButton: ItemListNavigationButton?
if let packCount = packCount, packCount != 0 { if let packCount = packCount, packCount != 0 {
if case .modal = mode { if case .modal = mode {
@ -603,7 +634,7 @@ public func installedStickerPacksController(context: AccountContext, mode: Insta
controller.reorderEntry = { fromIndex, toIndex, entries in controller.reorderEntry = { fromIndex, toIndex, entries in
let fromEntry = entries[fromIndex] let fromEntry = entries[fromIndex]
guard case let .pack(_, _, _, fromPackInfo, _, _, _, _) = fromEntry else { guard case let .pack(_, _, _, fromPackInfo, _, _, _, _, _) = fromEntry else {
return return
} }
var referenceId: ItemCollectionId? var referenceId: ItemCollectionId?
@ -611,7 +642,7 @@ public func installedStickerPacksController(context: AccountContext, mode: Insta
var afterAll = false var afterAll = false
if toIndex < entries.count { if toIndex < entries.count {
switch entries[toIndex] { switch entries[toIndex] {
case let .pack(_, _, _, toPackInfo, _, _, _, _): case let .pack(_, _, _, toPackInfo, _, _, _, _, _):
referenceId = toPackInfo.id referenceId = toPackInfo.id
default: default:
if entries[toIndex] < fromEntry { if entries[toIndex] < fromEntry {

View File

@ -47,13 +47,14 @@ final class ItemListStickerPackItem: ListViewItem, ItemListItem {
let control: ItemListStickerPackItemControl let control: ItemListStickerPackItemControl
let editing: ItemListStickerPackItemEditing let editing: ItemListStickerPackItemEditing
let enabled: Bool let enabled: Bool
let playAnimatedStickers: Bool
let sectionId: ItemListSectionId let sectionId: ItemListSectionId
let action: (() -> Void)? let action: (() -> Void)?
let setPackIdWithRevealedOptions: (ItemCollectionId?, ItemCollectionId?) -> Void let setPackIdWithRevealedOptions: (ItemCollectionId?, ItemCollectionId?) -> Void
let addPack: () -> Void let addPack: () -> Void
let removePack: () -> Void let removePack: () -> Void
init(theme: PresentationTheme, strings: PresentationStrings, account: Account, packInfo: StickerPackCollectionInfo, itemCount: String, topItem: StickerPackItem?, unread: Bool, control: ItemListStickerPackItemControl, editing: ItemListStickerPackItemEditing, enabled: Bool, sectionId: ItemListSectionId, action: (() -> Void)?, setPackIdWithRevealedOptions: @escaping (ItemCollectionId?, ItemCollectionId?) -> Void, addPack: @escaping () -> Void, removePack: @escaping () -> Void) { init(theme: PresentationTheme, strings: PresentationStrings, account: Account, packInfo: StickerPackCollectionInfo, itemCount: String, topItem: StickerPackItem?, unread: Bool, control: ItemListStickerPackItemControl, editing: ItemListStickerPackItemEditing, enabled: Bool, playAnimatedStickers: Bool, sectionId: ItemListSectionId, action: (() -> Void)?, setPackIdWithRevealedOptions: @escaping (ItemCollectionId?, ItemCollectionId?) -> Void, addPack: @escaping () -> Void, removePack: @escaping () -> Void) {
self.theme = theme self.theme = theme
self.strings = strings self.strings = strings
self.account = account self.account = account
@ -64,6 +65,7 @@ final class ItemListStickerPackItem: ListViewItem, ItemListItem {
self.control = control self.control = control
self.editing = editing self.editing = editing
self.enabled = enabled self.enabled = enabled
self.playAnimatedStickers = playAnimatedStickers
self.sectionId = sectionId self.sectionId = sectionId
self.action = action self.action = action
self.setPackIdWithRevealedOptions = setPackIdWithRevealedOptions self.setPackIdWithRevealedOptions = setPackIdWithRevealedOptions
@ -162,7 +164,7 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode {
let isVisible = self.visibility != .none let isVisible = self.visibility != .none
if wasVisible != isVisible { if wasVisible != isVisible {
self.animationNode?.visibility = isVisible self.animationNode?.visibility = isVisible && (self.layoutParams?.0.playAnimatedStickers ?? true)
} }
} }
} }
@ -558,8 +560,8 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode {
strongSelf.animationNode = animationNode strongSelf.animationNode = animationNode
strongSelf.addSubnode(animationNode) strongSelf.addSubnode(animationNode)
animationNode.setup(account: item.account, resource: resource, width: 80, height: 80, mode: .cached) animationNode.setup(account: item.account, resource: resource, width: 80, height: 80, mode: .cached)
animationNode.visibility = strongSelf.visibility != .none
} }
animationNode.visibility = strongSelf.visibility != .none && item.playAnimatedStickers
if let animationNode = strongSelf.animationNode { if let animationNode = strongSelf.animationNode {
transition.updateFrame(node: animationNode, frame: imageFrame) transition.updateFrame(node: animationNode, frame: imageFrame)
} }

View File

@ -101,7 +101,7 @@ final class OverlayPlayerControllerNode: ViewControllerTracingNode, UIGestureRec
}, seekToTimecode: { _, _, _ in }, seekToTimecode: { _, _, _ in
}, requestMessageUpdate: { _ in }, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: { }, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, pollActionState: ChatInterfacePollActionState()) }, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(loopAnimatedStickers: false))
self.dimNode = ASDisplayNode() self.dimNode = ASDisplayNode()
self.dimNode.backgroundColor = UIColor(white: 0.0, alpha: 0.5) self.dimNode.backgroundColor = UIColor(white: 0.0, alpha: 0.5)

View File

@ -272,7 +272,7 @@ public class PeerMediaCollectionController: TelegramController {
}, requestMessageUpdate: { _ in }, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: { }, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, }, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,
pollActionState: ChatInterfacePollActionState()) pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(loopAnimatedStickers: false))
self.controllerInteraction = controllerInteraction self.controllerInteraction = controllerInteraction

View File

@ -5,6 +5,7 @@ import AsyncDisplayKit
import Postbox import Postbox
import TelegramCore import TelegramCore
import SwiftSignalKit import SwiftSignalKit
import TelegramUIPreferences
enum StickerPackPreviewControllerMode { enum StickerPackPreviewControllerMode {
case `default` case `default`
@ -140,8 +141,13 @@ final class StickerPackPreviewController: ViewController {
} }
let account = self.context.account let account = self.context.account
self.displayNodeDidLoad() self.displayNodeDidLoad()
self.stickerPackDisposable.set((self.stickerPackContents.get() self.stickerPackDisposable.set((combineLatest(self.stickerPackContents.get(), self.context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.stickerSettings]) |> take(1))
|> mapToSignal { next -> Signal<LoadedStickerPack, NoError> in |> mapToSignal { next, sharedData -> Signal<(LoadedStickerPack, StickerSettings), NoError> in
var stickerSettings = StickerSettings.defaultSettings
if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.stickerSettings] as? StickerSettings {
stickerSettings = value
}
switch next { switch next {
case let .result(_, items, _): case let .result(_, items, _):
var preloadSignals: [Signal<Bool, NoError>] = [] var preloadSignals: [Signal<Bool, NoError>] = []
@ -172,26 +178,26 @@ final class StickerPackPreviewController: ViewController {
return !values.contains(false) return !values.contains(false)
} }
|> distinctUntilChanged |> distinctUntilChanged
|> mapToSignal { loaded -> Signal<LoadedStickerPack, NoError> in |> mapToSignal { loaded -> Signal<(LoadedStickerPack, StickerSettings), NoError> in
if !loaded { if !loaded {
return .single(.fetching) return .single((.fetching, stickerSettings))
} else { } else {
return .single(next) return .single((next, stickerSettings))
} }
} }
default: default:
return .single(next) return .single((next, stickerSettings))
} }
} }
|> deliverOnMainQueue).start(next: { [weak self] next in |> deliverOnMainQueue).start(next: { [weak self] next in
if let strongSelf = self { if let strongSelf = self {
if case .none = next { if case .none = next.0 {
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 } let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
strongSelf.present(textAlertController(context: strongSelf.context, title: nil, text: presentationData.strings.StickerPack_ErrorNotFound, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root)) strongSelf.present(textAlertController(context: strongSelf.context, title: nil, text: presentationData.strings.StickerPack_ErrorNotFound, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
strongSelf.dismiss() strongSelf.dismiss()
} else { } else {
strongSelf.controllerNode.updateStickerPack(next) strongSelf.controllerNode.updateStickerPack(next.0, stickerSettings: next.1)
strongSelf.stickerPackContentsValue = next strongSelf.stickerPackContentsValue = next.0
} }
} }
})) }))

View File

@ -6,6 +6,7 @@ import SwiftSignalKit
import Postbox import Postbox
import TelegramCore import TelegramCore
import TelegramPresentationData import TelegramPresentationData
import TelegramUIPreferences
private struct StickerPackPreviewGridEntry: Comparable, Identifiable { private struct StickerPackPreviewGridEntry: Comparable, Identifiable {
let index: Int let index: Int
@ -75,6 +76,7 @@ final class StickerPackPreviewControllerNode: ViewControllerTracingNode, UIScrol
private var stickerPack: LoadedStickerPack? private var stickerPack: LoadedStickerPack?
private var stickerPackUpdated = false private var stickerPackUpdated = false
private var stickerPackInitiallyInstalled : Bool? private var stickerPackInitiallyInstalled : Bool?
private var stickerSettings: StickerSettings?
private var currentItems: [StickerPackPreviewGridEntry] = [] private var currentItems: [StickerPackPreviewGridEntry] = []
@ -131,13 +133,7 @@ final class StickerPackPreviewControllerNode: ViewControllerTracingNode, UIScrol
super.init() super.init()
self.interaction = StickerPackPreviewInteraction(sendSticker: { [weak self] item in self.interaction = StickerPackPreviewInteraction(playAnimatedStickers: false)
if let strongSelf = self, let sendSticker = strongSelf.sendSticker {
/*if sendSticker(item.file) {
strongSelf.cancel?()
}*/
}
})
self.backgroundColor = nil self.backgroundColor = nil
self.isOpaque = false self.isOpaque = false
@ -510,16 +506,16 @@ final class StickerPackPreviewControllerNode: ViewControllerTracingNode, UIScrol
} else { } else {
dismissOnAction = true dismissOnAction = true
} }
if let stickerPack = self.stickerPack { if let stickerPack = self.stickerPack, let stickerSettings = self.stickerSettings {
switch stickerPack { switch stickerPack {
case let .result(info, items, installed): case let .result(info, items, installed):
if installed { if installed {
let _ = removeStickerPackInteractively(postbox: self.context.account.postbox, id: info.id, option: .delete).start() let _ = removeStickerPackInteractively(postbox: self.context.account.postbox, id: info.id, option: .delete).start()
updateStickerPack(.result(info: info, items: items, installed: false)) self.updateStickerPack(.result(info: info, items: items, installed: false), stickerSettings: stickerSettings)
} else { } else {
let _ = addStickerPackInteractively(postbox: self.context.account.postbox, info: info, items: items).start() let _ = addStickerPackInteractively(postbox: self.context.account.postbox, info: info, items: items).start()
if !dismissOnAction { if !dismissOnAction {
updateStickerPack(.result(info: info, items: items, installed: true)) self.updateStickerPack(.result(info: info, items: items, installed: true), stickerSettings: stickerSettings)
} }
} }
if dismissOnAction { if dismissOnAction {
@ -566,9 +562,13 @@ final class StickerPackPreviewControllerNode: ViewControllerTracingNode, UIScrol
}) })
} }
func updateStickerPack(_ stickerPack: LoadedStickerPack) { func updateStickerPack(_ stickerPack: LoadedStickerPack, stickerSettings: StickerSettings) {
self.stickerPack = stickerPack self.stickerPack = stickerPack
self.stickerSettings = stickerSettings
self.stickerPackUpdated = true self.stickerPackUpdated = true
self.interaction.playAnimatedStickers = stickerSettings.loopAnimatedStickers
if let _ = self.containerLayout { if let _ = self.containerLayout {
self.dequeueUpdateStickerPack() self.dequeueUpdateStickerPack()
} }

View File

@ -8,11 +8,10 @@ import Postbox
final class StickerPackPreviewInteraction { final class StickerPackPreviewInteraction {
var previewedItem: StickerPreviewPeekItem? var previewedItem: StickerPreviewPeekItem?
var playAnimatedStickers: Bool
let sendSticker: (StickerPackItem) -> Void init(playAnimatedStickers: Bool) {
self.playAnimatedStickers = playAnimatedStickers
init(sendSticker: @escaping (StickerPackItem) -> Void) {
self.sendSticker = sendSticker
} }
} }
@ -53,12 +52,10 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
override var isVisibleInGrid: Bool { override var isVisibleInGrid: Bool {
didSet { didSet {
self.animationNode?.visibility = self.isVisibleInGrid self.animationNode?.visibility = self.isVisibleInGrid && self.interaction?.playAnimatedStickers ?? true
} }
} }
private let textNode: ASTextNode
private var currentIsPreviewing = false private var currentIsPreviewing = false
private let stickerFetchedDisposable = MetaDisposable() private let stickerFetchedDisposable = MetaDisposable()
@ -74,16 +71,10 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
override init() { override init() {
self.imageNode = TransformImageNode() self.imageNode = TransformImageNode()
self.imageNode.isLayerBacked = !smartInvertColorsEnabled() self.imageNode.isLayerBacked = !smartInvertColorsEnabled()
//self.imageNode.alphaTransitionOnFirstUpdate = true
self.textNode = ASTextNode()
self.textNode.isUserInteractionEnabled = false
self.textNode.displaysAsynchronously = true
super.init() super.init()
self.addSubnode(self.imageNode) self.addSubnode(self.imageNode)
//self.addSubnode(self.textNode)
} }
deinit { deinit {
@ -100,14 +91,6 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
self.interaction = interaction self.interaction = interaction
if self.currentState == nil || self.currentState!.0 !== account || self.currentState!.1 != stickerItem { if self.currentState == nil || self.currentState!.0 !== account || self.currentState!.1 != stickerItem {
var text = ""
for attribute in stickerItem.file.attributes {
if case let .Sticker(displayText, _, _) = attribute {
text = displayText
break
}
}
self.textNode.attributedText = NSAttributedString(string: text, font: textFont, textColor: .black, paragraphAlignment: .right)
if let dimensions = stickerItem.file.dimensions { if let dimensions = stickerItem.file.dimensions {
if stickerItem.file.isAnimatedSticker { if stickerItem.file.isAnimatedSticker {
self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: account.postbox, file: stickerItem.file, small: false, size: CGSize(width: 160.0, height: 160.0))) self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: account.postbox, file: stickerItem.file, small: false, size: CGSize(width: 160.0, height: 160.0)))
@ -121,7 +104,7 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
} }
} }
self.animationNode?.setup(account: account, resource: stickerItem.file.resource, width: 160, height: 160, mode: .cached) self.animationNode?.setup(account: account, resource: stickerItem.file.resource, width: 160, height: 160, mode: .cached)
self.animationNode?.visibility = self.isVisibleInGrid self.animationNode?.visibility = self.isVisibleInGrid && self.interaction?.playAnimatedStickers ?? true
self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: account, fileReference: stickerPackFileReference(stickerItem.file), resource: stickerItem.file.resource).start()) self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: account, fileReference: stickerPackFileReference(stickerItem.file), resource: stickerItem.file.resource).start())
} else { } else {
if let animationNode = self.animationNode { if let animationNode = self.animationNode {
@ -157,9 +140,6 @@ 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.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) animationNode.updateLayout(size: imageSize)
} }
let boundingFrame = CGRect(origin: CGPoint(x: floor((bounds.size.width - boundingSize.width) / 2.0), y: (bounds.size.height - boundingSize.height) / 2.0), size: boundingSize)
let textSize = CGSize(width: 32.0, height: 24.0)
self.textNode.frame = CGRect(origin: CGPoint(x: boundingFrame.maxX - 1.0 - textSize.width, y: boundingFrame.height + 10.0 - textSize.height), size: textSize)
} }
} }
@ -169,7 +149,7 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
@objc func imageNodeTap(_ recognizer: UITapGestureRecognizer) { @objc func imageNodeTap(_ recognizer: UITapGestureRecognizer) {
if let interaction = self.interaction, let (_, item, _) = self.currentState, case .ended = recognizer.state { if let interaction = self.interaction, let (_, item, _) = self.currentState, case .ended = recognizer.state {
interaction.sendSticker(item) //interaction.sendSticker(item)
} }
} }

View File

@ -151,14 +151,14 @@ public struct MediaAutoDownloadSettings: PreferencesEntry, Equatable {
public static var defaultSettings: MediaAutoDownloadSettings { public static var defaultSettings: MediaAutoDownloadSettings {
let mb: Int32 = 1024 * 1024 let mb: Int32 = 1024 * 1024
let presets = MediaAutoDownloadPresets(low: MediaAutoDownloadCategories(basePreset: .low, photo: MediaAutoDownloadCategory(contacts: true, otherPrivate: true, groups: true, channels: true, sizeLimit: 1 * mb, predownload: false), let presets = MediaAutoDownloadPresets(low: MediaAutoDownloadCategories(basePreset: .low, photo: MediaAutoDownloadCategory(contacts: true, otherPrivate: true, groups: true, channels: true, sizeLimit: 1 * mb, predownload: false),
video: MediaAutoDownloadCategory(contacts: false, otherPrivate: false, groups: false, channels: false, sizeLimit: 1 * mb, predownload: false), video: MediaAutoDownloadCategory(contacts: false, otherPrivate: false, groups: false, channels: false, sizeLimit: 1 * mb, predownload: false),
file: MediaAutoDownloadCategory(contacts: false, otherPrivate: false, groups: false, channels: false, sizeLimit: 1 * mb, predownload: false)), file: MediaAutoDownloadCategory(contacts: false, otherPrivate: false, groups: false, channels: false, sizeLimit: 1 * mb, predownload: false)),
medium: MediaAutoDownloadCategories(basePreset: .medium, photo: MediaAutoDownloadCategory(contacts: true, otherPrivate: true, groups: true, channels: true, sizeLimit: 1 * mb, predownload: false), medium: MediaAutoDownloadCategories(basePreset: .medium, photo: MediaAutoDownloadCategory(contacts: true, otherPrivate: true, groups: true, channels: true, sizeLimit: 1 * mb, predownload: false),
video: MediaAutoDownloadCategory(contacts: true, otherPrivate: true, groups: true, channels: true, sizeLimit: Int32(2.5 * CGFloat(mb)), predownload: false), video: MediaAutoDownloadCategory(contacts: true, otherPrivate: true, groups: true, channels: true, sizeLimit: Int32(2.5 * CGFloat(mb)), predownload: false),
file: MediaAutoDownloadCategory(contacts: true, otherPrivate: true, groups: true, channels: true, sizeLimit: 1 * mb, predownload: false)), file: MediaAutoDownloadCategory(contacts: true, otherPrivate: true, groups: true, channels: true, sizeLimit: 1 * mb, predownload: false)),
high: MediaAutoDownloadCategories(basePreset: .high, photo: MediaAutoDownloadCategory(contacts: true, otherPrivate: true, groups: true, channels: true, sizeLimit: 1 * mb, predownload: false), high: MediaAutoDownloadCategories(basePreset: .high, photo: MediaAutoDownloadCategory(contacts: true, otherPrivate: true, groups: true, channels: true, sizeLimit: 1 * mb, predownload: false),
video: MediaAutoDownloadCategory(contacts: true, otherPrivate: true, groups: true, channels: true, sizeLimit: 10 * mb, predownload: true), video: MediaAutoDownloadCategory(contacts: true, otherPrivate: true, groups: true, channels: true, sizeLimit: 10 * mb, predownload: true),
file: MediaAutoDownloadCategory(contacts: true, otherPrivate: true, groups: true, channels: true, sizeLimit: 3 * mb, predownload: false))) file: MediaAutoDownloadCategory(contacts: true, otherPrivate: true, groups: true, channels: true, sizeLimit: 3 * mb, predownload: false)))
let saveDownloadedPhotos = MediaAutoDownloadCategory(contacts: false, otherPrivate: false, groups: false, channels: false, sizeLimit: 0, predownload: false) let saveDownloadedPhotos = MediaAutoDownloadCategory(contacts: false, otherPrivate: false, groups: false, channels: false, sizeLimit: 0, predownload: false)
return MediaAutoDownloadSettings(presets: presets, cellular: MediaAutoDownloadConnection(enabled: true, preset: .medium, custom: nil), wifi: MediaAutoDownloadConnection(enabled: true, preset: .high, custom: nil), saveDownloadedPhotos: saveDownloadedPhotos, autoplayGifs: true, autoplayVideos: true, downloadInBackground: true) return MediaAutoDownloadSettings(presets: presets, cellular: MediaAutoDownloadConnection(enabled: true, preset: .medium, custom: nil), wifi: MediaAutoDownloadConnection(enabled: true, preset: .high, custom: nil), saveDownloadedPhotos: saveDownloadedPhotos, autoplayGifs: true, autoplayVideos: true, downloadInBackground: true)

View File

@ -10,21 +10,25 @@ public enum EmojiStickerSuggestionMode: Int32 {
public struct StickerSettings: PreferencesEntry, Equatable { public struct StickerSettings: PreferencesEntry, Equatable {
public var emojiStickerSuggestionMode: EmojiStickerSuggestionMode public var emojiStickerSuggestionMode: EmojiStickerSuggestionMode
public var loopAnimatedStickers: Bool
public static var defaultSettings: StickerSettings { public static var defaultSettings: StickerSettings {
return StickerSettings(emojiStickerSuggestionMode: .all) return StickerSettings(emojiStickerSuggestionMode: .all, loopAnimatedStickers: true)
} }
init(emojiStickerSuggestionMode: EmojiStickerSuggestionMode) { init(emojiStickerSuggestionMode: EmojiStickerSuggestionMode, loopAnimatedStickers: Bool) {
self.emojiStickerSuggestionMode = emojiStickerSuggestionMode self.emojiStickerSuggestionMode = emojiStickerSuggestionMode
self.loopAnimatedStickers = loopAnimatedStickers
} }
public init(decoder: PostboxDecoder) { public init(decoder: PostboxDecoder) {
self.emojiStickerSuggestionMode = EmojiStickerSuggestionMode(rawValue: decoder.decodeInt32ForKey("emojiStickerSuggestionMode", orElse: 0))! self.emojiStickerSuggestionMode = EmojiStickerSuggestionMode(rawValue: decoder.decodeInt32ForKey("emojiStickerSuggestionMode", orElse: 0))!
self.loopAnimatedStickers = decoder.decodeBoolForKey("loopAnimatedStickers", orElse: true)
} }
public func encode(_ encoder: PostboxEncoder) { public func encode(_ encoder: PostboxEncoder) {
encoder.encodeInt32(self.emojiStickerSuggestionMode.rawValue, forKey: "emojiStickerSuggestionMode") encoder.encodeInt32(self.emojiStickerSuggestionMode.rawValue, forKey: "emojiStickerSuggestionMode")
encoder.encodeBool(self.loopAnimatedStickers, forKey: "loopAnimatedStickers")
} }
public func isEqual(to: PreferencesEntry) -> Bool { public func isEqual(to: PreferencesEntry) -> Bool {
@ -36,11 +40,15 @@ public struct StickerSettings: PreferencesEntry, Equatable {
} }
public static func ==(lhs: StickerSettings, rhs: StickerSettings) -> Bool { public static func ==(lhs: StickerSettings, rhs: StickerSettings) -> Bool {
return lhs.emojiStickerSuggestionMode == rhs.emojiStickerSuggestionMode return lhs.emojiStickerSuggestionMode == rhs.emojiStickerSuggestionMode && lhs.loopAnimatedStickers == rhs.loopAnimatedStickers
} }
public func withUpdatedEmojiStickerSuggestionMode(_ emojiStickerSuggestionMode: EmojiStickerSuggestionMode) -> StickerSettings { public func withUpdatedEmojiStickerSuggestionMode(_ emojiStickerSuggestionMode: EmojiStickerSuggestionMode) -> StickerSettings {
return StickerSettings(emojiStickerSuggestionMode: emojiStickerSuggestionMode) return StickerSettings(emojiStickerSuggestionMode: emojiStickerSuggestionMode, loopAnimatedStickers: self.loopAnimatedStickers)
}
public func withUpdatedLoopAnimatedStickers(_ loopAnimatedStickers: Bool) -> StickerSettings {
return StickerSettings(emojiStickerSuggestionMode: self.emojiStickerSuggestionMode, loopAnimatedStickers: loopAnimatedStickers)
} }
} }