mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-04 21:41:45 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
f2a327cad7
50
.github/workflows/build.yml
vendored
50
.github/workflows/build.yml
vendored
@ -24,20 +24,19 @@ jobs:
|
||||
- name: Create canonical source directory
|
||||
run: |
|
||||
set -x
|
||||
sudo mkdir /Users/telegram
|
||||
sudo chown -R $(whoami) /Users/telegram
|
||||
cp -R $GITHUB_WORKSPACE /Users/telegram/
|
||||
mv /Users/telegram/$(basename $GITHUB_WORKSPACE) /Users/telegram/telegram-ios
|
||||
sudo mkdir -p /Users/Shared
|
||||
cp -R $GITHUB_WORKSPACE /Users/Shared/
|
||||
mv /Users/Shared/$(basename $GITHUB_WORKSPACE) /Users/Shared/telegram-ios
|
||||
|
||||
- name: Build the App
|
||||
run: |
|
||||
set -x
|
||||
|
||||
# source code paths are included in the final binary, so we need to make them stable across builds
|
||||
SOURCE_DIR=/Users/telegram/telegram-ios
|
||||
SOURCE_DIR=/Users/Shared/telegram-ios
|
||||
|
||||
# use canonical bazel root
|
||||
BAZEL_USER_ROOT="/private/var/tmp/_bazel_telegram"
|
||||
BAZEL_USER_ROOT="/private/var/tmp/_bazel_containerhost"
|
||||
|
||||
cd $SOURCE_DIR
|
||||
|
||||
@ -50,37 +49,14 @@ jobs:
|
||||
echo "BUILD_NUMBER=$(echo $BUILD_NUMBER)" >> $GITHUB_ENV
|
||||
echo "APP_VERSION=$(echo $APP_VERSION)" >> $GITHUB_ENV
|
||||
|
||||
# prepare temporary keychain
|
||||
export MY_KEYCHAIN="temp.keychain"
|
||||
export MY_KEYCHAIN_PASSWORD="secret"
|
||||
security create-keychain -p "$MY_KEYCHAIN_PASSWORD" "$MY_KEYCHAIN"
|
||||
security list-keychains -d user -s "$MY_KEYCHAIN" $(security list-keychains -d user | sed s/\"//g)
|
||||
security set-keychain-settings "$MY_KEYCHAIN"
|
||||
security unlock-keychain -p "$MY_KEYCHAIN_PASSWORD" "$MY_KEYCHAIN"
|
||||
|
||||
# install fake certificates
|
||||
export CERTS_PATH="build-system/fake-codesigning/certs/distribution"
|
||||
for f in "$CERTS_PATH"/*.p12; do
|
||||
security import "$f" -k "$MY_KEYCHAIN" -P "" -T /usr/bin/codesign -T /usr/bin/security || true
|
||||
done
|
||||
for f in "$CERTS_PATH"/*.cer; do
|
||||
security import "$f" -k "$MY_KEYCHAIN" -P "" -T /usr/bin/codesign -T /usr/bin/security || true
|
||||
done
|
||||
security set-key-partition-list -S apple-tool:,apple: -k "$MY_KEYCHAIN_PASSWORD" "$MY_KEYCHAIN"
|
||||
|
||||
# use the official release configuration
|
||||
rm -rf $HOME/telegram-configuration
|
||||
mkdir -p $HOME/telegram-configuration
|
||||
cp -R build-system/example-configuration/* $HOME/telegram-configuration/
|
||||
|
||||
# build the app
|
||||
python3 build-system/Make/Make.py \
|
||||
python3 build-system/Make/ImportCertificates.py --path build-system/fake-codesigning/certs
|
||||
python3 -u build-system/Make/Make.py \
|
||||
--bazelUserRoot="$BAZEL_USER_ROOT" \
|
||||
build \
|
||||
--disableParallelSwiftmoduleGeneration \
|
||||
--configurationPath="$HOME/telegram-configuration" \
|
||||
--buildNumber=$BUILD_NUMBER \
|
||||
--configuration=release_universal
|
||||
--configurationPath="build-system/appstore-configuration.json" \
|
||||
--codesigningInformationPath=build-system/fake-codesigning \
|
||||
--configuration=release_arm64 \
|
||||
--buildNumber="$BUILD_NUMBER"
|
||||
|
||||
# collect ipa
|
||||
OUTPUT_PATH="build/artifacts"
|
||||
@ -117,7 +93,7 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: /Users/telegram/telegram-ios/build/artifacts/Telegram.ipa
|
||||
asset_path: /Users/Shared/telegram-ios/build/artifacts/Telegram.ipa
|
||||
asset_name: Telegram.ipa
|
||||
asset_content_type: application/zip
|
||||
|
||||
@ -128,6 +104,6 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: /Users/telegram/telegram-ios/build/artifacts/Telegram.DSYMs.zip
|
||||
asset_path: /Users/Shared/telegram-ios/build/artifacts/Telegram.DSYMs.zip
|
||||
asset_name: Telegram.DSYMs.zip
|
||||
asset_content_type: application/zip
|
||||
|
||||
@ -718,7 +718,12 @@ private final class NotificationServiceHandler {
|
||||
|
||||
let _ = (combineLatest(queue: self.queue,
|
||||
self.accountManager.accountRecords(),
|
||||
self.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.inAppNotificationSettings, ApplicationSpecificSharedDataKeys.voiceCallSettings, SharedDataKeys.loggingSettings])
|
||||
self.accountManager.sharedData(keys: [
|
||||
ApplicationSpecificSharedDataKeys.inAppNotificationSettings,
|
||||
ApplicationSpecificSharedDataKeys.voiceCallSettings,
|
||||
ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings,
|
||||
SharedDataKeys.loggingSettings
|
||||
])
|
||||
)
|
||||
|> take(1)
|
||||
|> deliverOn(self.queue)).start(next: { [weak self] records, sharedData in
|
||||
@ -728,6 +733,14 @@ private final class NotificationServiceHandler {
|
||||
let loggingSettings = sharedData.entries[SharedDataKeys.loggingSettings]?.get(LoggingSettings.self) ?? LoggingSettings.defaultSettings
|
||||
Logger.shared.logToFile = loggingSettings.logToFile
|
||||
Logger.shared.logToConsole = loggingSettings.logToConsole
|
||||
|
||||
var automaticMediaDownloadSettings: MediaAutoDownloadSettings
|
||||
if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings]?.get(MediaAutoDownloadSettings.self) {
|
||||
automaticMediaDownloadSettings = value
|
||||
} else {
|
||||
automaticMediaDownloadSettings = MediaAutoDownloadSettings.defaultSettings
|
||||
}
|
||||
let shouldSynchronizeState = automaticMediaDownloadSettings.energyUsageSettings.synchronizeInBackground
|
||||
|
||||
if let keyId = notificationPayloadKeyId(data: payloadData) {
|
||||
outer: for listRecord in records.records {
|
||||
@ -1406,34 +1419,38 @@ private final class NotificationServiceHandler {
|
||||
|
||||
let pollSignal: Signal<Never, NoError>
|
||||
|
||||
stateManager.network.shouldKeepConnection.set(.single(true))
|
||||
if peerId.namespace == Namespaces.Peer.CloudChannel {
|
||||
Logger.shared.log("NotificationService \(episode)", "Will poll channel \(peerId)")
|
||||
|
||||
pollSignal = standalonePollChannelOnce(
|
||||
accountPeerId: stateManager.accountPeerId,
|
||||
postbox: stateManager.postbox,
|
||||
network: stateManager.network,
|
||||
peerId: peerId,
|
||||
stateManager: stateManager
|
||||
)
|
||||
if !shouldSynchronizeState {
|
||||
pollSignal = .complete()
|
||||
} else {
|
||||
Logger.shared.log("NotificationService \(episode)", "Will perform non-specific getDifference")
|
||||
enum ControlError {
|
||||
case restart
|
||||
}
|
||||
let signal = stateManager.standalonePollDifference()
|
||||
|> castError(ControlError.self)
|
||||
|> mapToSignal { result -> Signal<Never, ControlError> in
|
||||
if result {
|
||||
return .complete()
|
||||
} else {
|
||||
return .fail(.restart)
|
||||
stateManager.network.shouldKeepConnection.set(.single(true))
|
||||
if peerId.namespace == Namespaces.Peer.CloudChannel {
|
||||
Logger.shared.log("NotificationService \(episode)", "Will poll channel \(peerId)")
|
||||
|
||||
pollSignal = standalonePollChannelOnce(
|
||||
accountPeerId: stateManager.accountPeerId,
|
||||
postbox: stateManager.postbox,
|
||||
network: stateManager.network,
|
||||
peerId: peerId,
|
||||
stateManager: stateManager
|
||||
)
|
||||
} else {
|
||||
Logger.shared.log("NotificationService \(episode)", "Will perform non-specific getDifference")
|
||||
enum ControlError {
|
||||
case restart
|
||||
}
|
||||
let signal = stateManager.standalonePollDifference()
|
||||
|> castError(ControlError.self)
|
||||
|> mapToSignal { result -> Signal<Never, ControlError> in
|
||||
if result {
|
||||
return .complete()
|
||||
} else {
|
||||
return .fail(.restart)
|
||||
}
|
||||
}
|
||||
|> restartIfError
|
||||
|
||||
pollSignal = signal
|
||||
}
|
||||
|> restartIfError
|
||||
|
||||
pollSignal = signal
|
||||
}
|
||||
|
||||
let pollWithUpdatedContent: Signal<NotificationContent, NoError>
|
||||
|
||||
@ -744,13 +744,15 @@ public protocol SharedAccountContext: AnyObject {
|
||||
var currentPresentationData: Atomic<PresentationData> { get }
|
||||
var presentationData: Signal<PresentationData, NoError> { get }
|
||||
|
||||
var currentAutomaticMediaDownloadSettings: Atomic<MediaAutoDownloadSettings> { get }
|
||||
var currentAutomaticMediaDownloadSettings: MediaAutoDownloadSettings { get }
|
||||
var automaticMediaDownloadSettings: Signal<MediaAutoDownloadSettings, NoError> { get }
|
||||
var currentAutodownloadSettings: Atomic<AutodownloadSettings> { get }
|
||||
var immediateExperimentalUISettings: ExperimentalUISettings { get }
|
||||
var currentInAppNotificationSettings: Atomic<InAppNotificationSettings> { get }
|
||||
var currentMediaInputSettings: Atomic<MediaInputSettings> { get }
|
||||
|
||||
var energyUsageSettings: EnergyUsageSettings { get }
|
||||
|
||||
var applicationBindings: TelegramApplicationBindings { get }
|
||||
|
||||
var authorizationPushConfiguration: Signal<AuthorizationCodePushNotificationConfiguration?, NoError> { get }
|
||||
|
||||
@ -31,8 +31,8 @@ private struct ArchivedStickersNoticeEntry: Comparable, Identifiable {
|
||||
return lhs.index < rhs.index
|
||||
}
|
||||
|
||||
func item(account: Account, presentationData: PresentationData) -> ListViewItem {
|
||||
return ItemListStickerPackItem(presentationData: ItemListPresentationData(presentationData), account: account, packInfo: info, itemCount: self.count, topItem: topItem, unread: false, control: .none, editing: ItemListStickerPackItemEditing(editable: false, editing: false, revealed: false, reorderable: false, selectable: false), enabled: true, playAnimatedStickers: true, sectionId: 0, action: {
|
||||
func item(context: AccountContext, presentationData: PresentationData) -> ListViewItem {
|
||||
return ItemListStickerPackItem(presentationData: ItemListPresentationData(presentationData), context: context, packInfo: info, itemCount: self.count, topItem: topItem, unread: false, control: .none, editing: ItemListStickerPackItemEditing(editable: false, editing: false, revealed: false, reorderable: false, selectable: false), enabled: true, playAnimatedStickers: true, sectionId: 0, action: {
|
||||
}, setPackIdWithRevealedOptions: { current, previous in
|
||||
}, addPack: {
|
||||
}, removePack: {
|
||||
@ -47,12 +47,12 @@ private struct ArchivedStickersNoticeTransition {
|
||||
let updates: [ListViewUpdateItem]
|
||||
}
|
||||
|
||||
private func preparedTransition(from fromEntries: [ArchivedStickersNoticeEntry], to toEntries: [ArchivedStickersNoticeEntry], account: Account, presentationData: PresentationData) -> ArchivedStickersNoticeTransition {
|
||||
private func preparedTransition(from fromEntries: [ArchivedStickersNoticeEntry], to toEntries: [ArchivedStickersNoticeEntry], context: AccountContext, presentationData: PresentationData) -> ArchivedStickersNoticeTransition {
|
||||
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
|
||||
|
||||
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
|
||||
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, presentationData: presentationData), directionHint: nil) }
|
||||
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, presentationData: presentationData), directionHint: nil) }
|
||||
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData), directionHint: nil) }
|
||||
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData), directionHint: nil) }
|
||||
|
||||
return ArchivedStickersNoticeTransition(deletions: deletions, insertions: insertions, updates: updates)
|
||||
}
|
||||
@ -79,7 +79,7 @@ private final class ArchivedStickersNoticeAlertContentNode: AlertContentNode {
|
||||
return self.isUserInteractionEnabled
|
||||
}
|
||||
|
||||
init(theme: AlertControllerTheme, account: Account, presentationData: PresentationData, archivedStickerPacks: [(StickerPackCollectionInfo, StickerPackItem?)], actions: [TextAlertAction]) {
|
||||
init(theme: AlertControllerTheme, context: AccountContext, presentationData: PresentationData, archivedStickerPacks: [(StickerPackCollectionInfo, StickerPackItem?)], actions: [TextAlertAction]) {
|
||||
self.presentationData = presentationData
|
||||
self.archivedStickerPacks = archivedStickerPacks
|
||||
|
||||
@ -139,7 +139,7 @@ private final class ArchivedStickersNoticeAlertContentNode: AlertContentNode {
|
||||
index += 1
|
||||
}
|
||||
|
||||
let transition = preparedTransition(from: [], to: entries, account: account, presentationData: presentationData)
|
||||
let transition = preparedTransition(from: [], to: entries, context: context, presentationData: presentationData)
|
||||
self.enqueueTransition(transition)
|
||||
}
|
||||
|
||||
@ -304,7 +304,7 @@ public func archivedStickerPacksNoticeController(context: AccountContext, archiv
|
||||
|
||||
let disposable = MetaDisposable()
|
||||
|
||||
let contentNode = ArchivedStickersNoticeAlertContentNode(theme: AlertControllerTheme(presentationData: presentationData), account: context.account, presentationData: presentationData, archivedStickerPacks: archivedStickerPacks, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {
|
||||
let contentNode = ArchivedStickersNoticeAlertContentNode(theme: AlertControllerTheme(presentationData: presentationData), context: context, presentationData: presentationData, archivedStickerPacks: archivedStickerPacks, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {
|
||||
dismissImpl?()
|
||||
})])
|
||||
|
||||
|
||||
@ -1754,12 +1754,19 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
|
||||
Queue.mainQueue().after(1.0, {
|
||||
let _ = (
|
||||
self.context.engine.data.get(TelegramEngine.EngineData.Item.Notices.Notice(key: ApplicationSpecificNotice.forcedPasswordSetupKey()))
|
||||
|> map { entry -> Int32? in
|
||||
return entry?.get(ApplicationSpecificCounterNotice.self)?.value
|
||||
self.context.engine.data.get(
|
||||
TelegramEngine.EngineData.Item.Peer.Peer(id: self.context.account.peerId),
|
||||
TelegramEngine.EngineData.Item.Notices.Notice(key: ApplicationSpecificNotice.forcedPasswordSetupKey())
|
||||
)
|
||||
|> map { peer, entry -> (phoneNumber: String?, nortice: Int32?) in
|
||||
var phoneNumber: String?
|
||||
if case let .user(user) = peer {
|
||||
phoneNumber = user.phone
|
||||
}
|
||||
return (phoneNumber, entry?.get(ApplicationSpecificCounterNotice.self)?.value)
|
||||
}
|
||||
|> deliverOnMainQueue
|
||||
).start(next: { [weak self] value in
|
||||
).start(next: { [weak self] phoneNumber, value in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
@ -1772,7 +1779,8 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
title: strongSelf.presentationData.strings.ForcedPasswordSetup_Intro_Title,
|
||||
text: strongSelf.presentationData.strings.ForcedPasswordSetup_Intro_Text,
|
||||
actionText: strongSelf.presentationData.strings.ForcedPasswordSetup_Intro_Action,
|
||||
doneText: strongSelf.presentationData.strings.ForcedPasswordSetup_Intro_DoneAction
|
||||
doneText: strongSelf.presentationData.strings.ForcedPasswordSetup_Intro_DoneAction,
|
||||
phoneNumber: phoneNumber
|
||||
)))
|
||||
controller.dismissConfirmation = { [weak controller] f in
|
||||
guard let strongSelf = self, let controller = controller else {
|
||||
|
||||
@ -13,6 +13,7 @@ import SearchUI
|
||||
import ContextUI
|
||||
import AnimationCache
|
||||
import MultiAnimationRenderer
|
||||
import TelegramUIPreferences
|
||||
|
||||
public enum ChatListContainerNodeFilter: Equatable {
|
||||
case all
|
||||
@ -648,13 +649,26 @@ public final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDele
|
||||
return (state, filterId)
|
||||
})
|
||||
|
||||
let enablePreload = context.sharedContext.accountManager.sharedData(keys: Set([ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings]))
|
||||
|> map { sharedData -> Bool in
|
||||
var automaticMediaDownloadSettings: MediaAutoDownloadSettings
|
||||
if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings]?.get(MediaAutoDownloadSettings.self) {
|
||||
automaticMediaDownloadSettings = value
|
||||
} else {
|
||||
automaticMediaDownloadSettings = MediaAutoDownloadSettings.defaultSettings
|
||||
}
|
||||
return automaticMediaDownloadSettings.energyUsageSettings.autodownloadInBackground
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
|
||||
if self.controlsHistoryPreload, case .chatList(groupId: .root) = self.location {
|
||||
self.context.account.viewTracker.chatListPreloadItems.set(combineLatest(queue: .mainQueue(),
|
||||
context.sharedContext.hasOngoingCall.get(),
|
||||
itemNode.listNode.preloadItems.get()
|
||||
itemNode.listNode.preloadItems.get(),
|
||||
enablePreload
|
||||
)
|
||||
|> map { hasOngoingCall, preloadItems -> Set<ChatHistoryPreloadItem> in
|
||||
if hasOngoingCall {
|
||||
|> map { hasOngoingCall, preloadItems, enablePreload -> Set<ChatHistoryPreloadItem> in
|
||||
if hasOngoingCall || !enablePreload {
|
||||
return Set()
|
||||
} else {
|
||||
return Set(preloadItems)
|
||||
|
||||
@ -675,7 +675,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
animationCache: context.animationCache,
|
||||
animationRenderer: context.animationRenderer,
|
||||
content: titleTopicIconContent,
|
||||
isVisibleForAnimations: currentNode?.visibilityStatus ?? false,
|
||||
isVisibleForAnimations: (currentNode?.visibilityStatus ?? false) && context.sharedContext.energyUsageSettings.loopEmoji,
|
||||
action: nil
|
||||
)
|
||||
|
||||
@ -1318,7 +1318,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
|
||||
if isKnown {
|
||||
let photo = personalPhoto ?? profilePhoto
|
||||
if let photo = photo, !photo.videoRepresentations.isEmpty || photo.emojiMarkup != nil {
|
||||
if let photo = photo, item.context.sharedContext.energyUsageSettings.loopEmoji, (!photo.videoRepresentations.isEmpty || photo.emojiMarkup != nil) {
|
||||
let videoNode: AvatarVideoNode
|
||||
if let current = strongSelf.avatarVideoNode {
|
||||
videoNode = current
|
||||
@ -2788,7 +2788,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
animationCache: item.interaction.animationCache,
|
||||
animationRenderer: item.interaction.animationRenderer,
|
||||
content: avatarIconContent,
|
||||
isVisibleForAnimations: strongSelf.visibilityStatus,
|
||||
isVisibleForAnimations: strongSelf.visibilityStatus && item.context.sharedContext.energyUsageSettings.loopEmoji,
|
||||
action: nil
|
||||
)
|
||||
strongSelf.avatarIconComponent = avatarIconComponent
|
||||
@ -3285,7 +3285,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
animationCache: item.interaction.animationCache,
|
||||
animationRenderer: item.interaction.animationRenderer,
|
||||
content: currentCredibilityIconContent,
|
||||
isVisibleForAnimations: strongSelf.visibilityStatus,
|
||||
isVisibleForAnimations: strongSelf.visibilityStatus && item.context.sharedContext.energyUsageSettings.loopEmoji,
|
||||
action: nil
|
||||
)
|
||||
strongSelf.credibilityIconComponent = credibilityIconComponent
|
||||
|
||||
@ -170,7 +170,7 @@ public final class ReactionIconView: PortalSourceView {
|
||||
|
||||
animationLayer.frame = CGRect(origin: CGPoint(x: floor((size.width - iconSize.width) / 2.0), y: floor((size.height - iconSize.height) / 2.0)), size: iconSize)
|
||||
|
||||
animationLayer.isVisibleForAnimations = animateIdle
|
||||
animationLayer.isVisibleForAnimations = animateIdle && context.sharedContext.energyUsageSettings.loopEmoji
|
||||
}
|
||||
|
||||
func reset() {
|
||||
|
||||
@ -73,6 +73,7 @@ private enum DebugControllerEntry: ItemListNodeEntry {
|
||||
case crashOnSlowQueries(PresentationTheme, Bool)
|
||||
case clearTips(PresentationTheme)
|
||||
case resetTranslationStates(PresentationTheme)
|
||||
case resetNotifications
|
||||
case crash(PresentationTheme)
|
||||
case resetData(PresentationTheme)
|
||||
case resetDatabase(PresentationTheme)
|
||||
@ -116,7 +117,7 @@ private enum DebugControllerEntry: ItemListNodeEntry {
|
||||
return DebugControllerSection.logging.rawValue
|
||||
case .enableRaiseToSpeak, .keepChatNavigationStack, .skipReadHistory, .crashOnSlowQueries:
|
||||
return DebugControllerSection.experiments.rawValue
|
||||
case .clearTips, .resetTranslationStates, .crash, .resetData, .resetDatabase, .resetDatabaseAndCache, .resetHoles, .reindexUnread, .resetCacheIndex, .reindexCache, .resetBiometricsData, .resetWebViewCache, .optimizeDatabase, .photoPreview, .knockoutWallpaper, .playerEmbedding, .playlistPlayback, .enableQuickReactionSwitch, .voiceConference, .experimentalCompatibility, .enableDebugDataDisplay, .acceleratedStickers, .experimentalBackground, .inlineForums, .localTranscription, . enableReactionOverrides, .restorePurchases:
|
||||
case .clearTips, .resetTranslationStates, .resetNotifications, .crash, .resetData, .resetDatabase, .resetDatabaseAndCache, .resetHoles, .reindexUnread, .resetCacheIndex, .reindexCache, .resetBiometricsData, .resetWebViewCache, .optimizeDatabase, .photoPreview, .knockoutWallpaper, .playerEmbedding, .playlistPlayback, .enableQuickReactionSwitch, .voiceConference, .experimentalCompatibility, .enableDebugDataDisplay, .acceleratedStickers, .experimentalBackground, .inlineForums, .localTranscription, . enableReactionOverrides, .restorePurchases:
|
||||
return DebugControllerSection.experiments.rawValue
|
||||
case .preferredVideoCodec:
|
||||
return DebugControllerSection.videoExperiments.rawValue
|
||||
@ -167,58 +168,60 @@ private enum DebugControllerEntry: ItemListNodeEntry {
|
||||
return 17
|
||||
case .resetTranslationStates:
|
||||
return 18
|
||||
case .crash:
|
||||
case .resetNotifications:
|
||||
return 19
|
||||
case .resetData:
|
||||
case .crash:
|
||||
return 20
|
||||
case .resetDatabase:
|
||||
case .resetData:
|
||||
return 21
|
||||
case .resetDatabaseAndCache:
|
||||
case .resetDatabase:
|
||||
return 22
|
||||
case .resetHoles:
|
||||
case .resetDatabaseAndCache:
|
||||
return 23
|
||||
case .reindexUnread:
|
||||
case .resetHoles:
|
||||
return 24
|
||||
case .resetCacheIndex:
|
||||
case .reindexUnread:
|
||||
return 25
|
||||
case .reindexCache:
|
||||
case .resetCacheIndex:
|
||||
return 26
|
||||
case .resetBiometricsData:
|
||||
case .reindexCache:
|
||||
return 27
|
||||
case .resetWebViewCache:
|
||||
case .resetBiometricsData:
|
||||
return 28
|
||||
case .optimizeDatabase:
|
||||
case .resetWebViewCache:
|
||||
return 29
|
||||
case .photoPreview:
|
||||
case .optimizeDatabase:
|
||||
return 30
|
||||
case .knockoutWallpaper:
|
||||
case .photoPreview:
|
||||
return 31
|
||||
case .experimentalCompatibility:
|
||||
case .knockoutWallpaper:
|
||||
return 32
|
||||
case .enableDebugDataDisplay:
|
||||
case .experimentalCompatibility:
|
||||
return 33
|
||||
case .acceleratedStickers:
|
||||
case .enableDebugDataDisplay:
|
||||
return 34
|
||||
case .experimentalBackground:
|
||||
case .acceleratedStickers:
|
||||
return 35
|
||||
case .inlineForums:
|
||||
case .experimentalBackground:
|
||||
return 36
|
||||
case .localTranscription:
|
||||
case .inlineForums:
|
||||
return 37
|
||||
case .enableReactionOverrides:
|
||||
case .localTranscription:
|
||||
return 38
|
||||
case .restorePurchases:
|
||||
case .enableReactionOverrides:
|
||||
return 39
|
||||
case .playerEmbedding:
|
||||
case .restorePurchases:
|
||||
return 40
|
||||
case .playlistPlayback:
|
||||
case .playerEmbedding:
|
||||
return 41
|
||||
case .enableQuickReactionSwitch:
|
||||
case .playlistPlayback:
|
||||
return 42
|
||||
case .voiceConference:
|
||||
case .enableQuickReactionSwitch:
|
||||
return 43
|
||||
case .voiceConference:
|
||||
return 44
|
||||
case let .preferredVideoCodec(index, _, _, _):
|
||||
return 44 + index
|
||||
return 45 + index
|
||||
case .disableVideoAspectScaling:
|
||||
return 100
|
||||
case .enableVoipTcp:
|
||||
@ -952,6 +955,15 @@ private enum DebugControllerEntry: ItemListNodeEntry {
|
||||
]).start()
|
||||
}
|
||||
})
|
||||
case .resetNotifications:
|
||||
return ItemListActionItem(presentationData: presentationData, title: "Reset Notifications", kind: .generic, alignment: .natural, sectionId: self.section, style: .blocks, action: {
|
||||
UIApplication.shared.unregisterForRemoteNotifications()
|
||||
|
||||
if let context = arguments.context {
|
||||
let controller = textAlertController(context: context, title: nil, text: "Now restart the app", actions: [TextAlertAction(type: .genericAction, title: "OK", action: {})])
|
||||
arguments.presentController(controller, nil)
|
||||
}
|
||||
})
|
||||
case .crash:
|
||||
return ItemListActionItem(presentationData: presentationData, title: "Crash", kind: .generic, alignment: .natural, sectionId: self.section, style: .blocks, action: {
|
||||
preconditionFailure()
|
||||
@ -1340,6 +1352,7 @@ private func debugControllerEntries(sharedContext: SharedAccountContext, present
|
||||
if isMainApp {
|
||||
entries.append(.clearTips(presentationData.theme))
|
||||
entries.append(.resetTranslationStates(presentationData.theme))
|
||||
entries.append(.resetNotifications)
|
||||
}
|
||||
entries.append(.crash(presentationData.theme))
|
||||
entries.append(.resetData(presentationData.theme))
|
||||
|
||||
@ -14,10 +14,6 @@ public enum DeviceMetrics: CaseIterable, Equatable {
|
||||
var cpuCount: UInt32 = 0
|
||||
sysctlbyname("hw.ncpu", &cpuCount, &length, nil, 0)
|
||||
|
||||
#if DEBUG
|
||||
cpuCount = 2
|
||||
#endif
|
||||
|
||||
self.isGraphicallyCapable = cpuCount >= 6
|
||||
}
|
||||
}
|
||||
|
||||
@ -107,7 +107,7 @@ final class TrendingTopItemNode: ASDisplayNode {
|
||||
}
|
||||
|
||||
if let placeholderNode = self.placeholderNode, let file = self.file {
|
||||
placeholderNode.update(backgroundColor: backgroundColor, foregroundColor: foregroundColor, shimmeringColor: shimmeringColor, data: file.immediateThumbnailData, size: self.itemSize ?? CGSize(width: 75.0, height: 75.0))
|
||||
placeholderNode.update(backgroundColor: backgroundColor, foregroundColor: foregroundColor, shimmeringColor: shimmeringColor, data: file.immediateThumbnailData, size: self.itemSize ?? CGSize(width: 75.0, height: 75.0), enableEffect: true)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -76,7 +76,7 @@ final class InstantPageImageNode: ASDisplayNode, InstantPageNode {
|
||||
let imageReference = ImageMediaReference.webPage(webPage: WebpageReference(webPage), media: image)
|
||||
self.imageNode.setSignal(chatMessagePhoto(postbox: context.account.postbox, userLocation: sourceLocation.userLocation, photoReference: imageReference))
|
||||
|
||||
if !interactive || shouldDownloadMediaAutomatically(settings: context.sharedContext.currentAutomaticMediaDownloadSettings.with { $0 }, peerType: sourceLocation.peerType, networkType: MediaAutoDownloadNetworkType(context.account.immediateNetworkType), authorPeerId: nil, contactsPeerIds: Set(), media: image) {
|
||||
if !interactive || shouldDownloadMediaAutomatically(settings: context.sharedContext.currentAutomaticMediaDownloadSettings, peerType: sourceLocation.peerType, networkType: MediaAutoDownloadNetworkType(context.account.immediateNetworkType), authorPeerId: nil, contactsPeerIds: Set(), media: image) {
|
||||
self.fetchedDisposable.set(chatMessagePhotoInteractiveFetched(context: context, userLocation: sourceLocation.userLocation, photoReference: imageReference, displayAtSize: nil, storeToDownloadsPeerId: nil).start())
|
||||
}
|
||||
|
||||
@ -108,7 +108,7 @@ final class InstantPageImageNode: ASDisplayNode, InstantPageNode {
|
||||
} else if let file = media.media as? TelegramMediaFile {
|
||||
let fileReference = FileMediaReference.webPage(webPage: WebpageReference(webPage), media: file)
|
||||
if file.mimeType.hasPrefix("image/") {
|
||||
if !interactive || shouldDownloadMediaAutomatically(settings: context.sharedContext.currentAutomaticMediaDownloadSettings.with { $0 }, peerType: sourceLocation.peerType, networkType: MediaAutoDownloadNetworkType(context.account.immediateNetworkType), authorPeerId: nil, contactsPeerIds: Set(), media: file) {
|
||||
if !interactive || shouldDownloadMediaAutomatically(settings: context.sharedContext.currentAutomaticMediaDownloadSettings, peerType: sourceLocation.peerType, networkType: MediaAutoDownloadNetworkType(context.account.immediateNetworkType), authorPeerId: nil, contactsPeerIds: Set(), media: file) {
|
||||
_ = freeMediaFileInteractiveFetched(account: context.account, userLocation: sourceLocation.userLocation, fileReference: fileReference).start()
|
||||
}
|
||||
self.imageNode.setSignal(instantPageImageFile(account: context.account, userLocation: sourceLocation.userLocation, fileReference: fileReference, fetched: true))
|
||||
|
||||
@ -12,6 +12,7 @@ import StickerResources
|
||||
import AnimatedStickerNode
|
||||
import TelegramAnimatedStickerNode
|
||||
import ShimmerEffect
|
||||
import AccountContext
|
||||
|
||||
public struct ItemListStickerPackItemEditing: Equatable {
|
||||
public var editable: Bool
|
||||
@ -38,7 +39,7 @@ public enum ItemListStickerPackItemControl: Equatable {
|
||||
|
||||
public final class ItemListStickerPackItem: ListViewItem, ItemListItem {
|
||||
let presentationData: ItemListPresentationData
|
||||
let account: Account
|
||||
let context: AccountContext
|
||||
let packInfo: StickerPackCollectionInfo
|
||||
let itemCount: String
|
||||
let topItem: StickerPackItem?
|
||||
@ -54,9 +55,9 @@ public final class ItemListStickerPackItem: ListViewItem, ItemListItem {
|
||||
let removePack: () -> Void
|
||||
let toggleSelected: () -> Void
|
||||
|
||||
public init(presentationData: ItemListPresentationData, 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, toggleSelected: @escaping () -> Void) {
|
||||
public init(presentationData: ItemListPresentationData, context: AccountContext, 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, toggleSelected: @escaping () -> Void) {
|
||||
self.presentationData = presentationData
|
||||
self.account = account
|
||||
self.context = context
|
||||
self.packInfo = packInfo
|
||||
self.itemCount = itemCount
|
||||
self.topItem = topItem
|
||||
@ -506,18 +507,18 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode {
|
||||
|
||||
if fileUpdated {
|
||||
imageApply = makeImageLayout(TransformImageArguments(corners: ImageCorners(), imageSize: stillImageSize, boundingSize: stillImageSize, intrinsicInsets: UIEdgeInsets()))
|
||||
updatedImageSignal = chatMessageStickerPackThumbnail(postbox: item.account.postbox, resource: representation.resource, nilIfEmpty: true)
|
||||
updatedImageSignal = chatMessageStickerPackThumbnail(postbox: item.context.account.postbox, resource: representation.resource, nilIfEmpty: true)
|
||||
}
|
||||
case let .animated(resource, dimensions, _):
|
||||
imageSize = dimensions.cgSize.aspectFitted(imageBoundingSize)
|
||||
|
||||
if fileUpdated {
|
||||
imageApply = makeImageLayout(TransformImageArguments(corners: ImageCorners(), imageSize: imageBoundingSize, boundingSize: imageBoundingSize, intrinsicInsets: UIEdgeInsets()))
|
||||
updatedImageSignal = chatMessageStickerPackThumbnail(postbox: item.account.postbox, resource: resource, animated: true, nilIfEmpty: true)
|
||||
updatedImageSignal = chatMessageStickerPackThumbnail(postbox: item.context.account.postbox, resource: resource, animated: true, nilIfEmpty: true)
|
||||
}
|
||||
}
|
||||
if fileUpdated, let resourceReference = resourceReference {
|
||||
updatedFetchSignal = fetchedMediaResource(mediaBox: item.account.postbox.mediaBox, userLocation: .other, userContentType: .sticker, reference: resourceReference)
|
||||
updatedFetchSignal = fetchedMediaResource(mediaBox: item.context.account.postbox.mediaBox, userLocation: .other, userContentType: .sticker, reference: resourceReference)
|
||||
}
|
||||
} else {
|
||||
updatedImageSignal = .single({ _ in return nil })
|
||||
@ -768,7 +769,7 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode {
|
||||
strongSelf.animationNode = animationNode
|
||||
strongSelf.addSubnode(animationNode)
|
||||
|
||||
animationNode.setup(source: AnimatedStickerResourceSource(account: item.account, resource: resource, isVideo: isVideo), width: 80, height: 80, playbackMode: .loop, mode: .direct(cachePathPrefix: nil))
|
||||
animationNode.setup(source: AnimatedStickerResourceSource(account: item.context.account, resource: resource, isVideo: isVideo), width: 80, height: 80, playbackMode: .loop, mode: .direct(cachePathPrefix: nil))
|
||||
}
|
||||
animationNode.visibility = strongSelf.visibility != .none && item.playAnimatedStickers
|
||||
animationNode.isHidden = !item.playAnimatedStickers
|
||||
@ -794,7 +795,7 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode {
|
||||
|
||||
placeholderNode.frame = imageFrame
|
||||
|
||||
placeholderNode.update(backgroundColor: nil, foregroundColor: item.presentationData.theme.list.disclosureArrowColor.blitOver(item.presentationData.theme.list.itemBlocksBackgroundColor, alpha: 0.55), shimmeringColor: item.presentationData.theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.4), data: immediateThumbnailData, size: imageFrame.size, imageSize: imageSize.cgSize)
|
||||
placeholderNode.update(backgroundColor: nil, foregroundColor: item.presentationData.theme.list.disclosureArrowColor.blitOver(item.presentationData.theme.list.itemBlocksBackgroundColor, alpha: 0.55), shimmeringColor: item.presentationData.theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.4), data: immediateThumbnailData, size: imageFrame.size, enableEffect: item.context.sharedContext.energyUsageSettings.fullTranslucency, imageSize: imageSize.cgSize)
|
||||
}
|
||||
|
||||
if let updatedImageSignal = updatedImageSignal {
|
||||
|
||||
@ -35,7 +35,7 @@ public enum TwoFactorDataInputMode {
|
||||
case authorized
|
||||
}
|
||||
|
||||
case password(doneText: String)
|
||||
case password(phoneNumber: String?, doneText: String)
|
||||
case passwordRecoveryEmail(emailPattern: String, mode: PasswordRecoveryEmailMode, doneText: String)
|
||||
case passwordRecovery(recovery: Recovery, doneText: String)
|
||||
case emailAddress(password: String, hint: String, doneText: String)
|
||||
@ -99,8 +99,11 @@ public final class TwoFactorDataInputScreen: ViewController {
|
||||
public override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
|
||||
if case .rememberPassword = self.mode {
|
||||
switch self.mode {
|
||||
case .rememberPassword, .password:
|
||||
(self.displayNode as? TwoFactorDataInputScreenNode)?.focus()
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@ -110,7 +113,7 @@ public final class TwoFactorDataInputScreen: ViewController {
|
||||
return
|
||||
}
|
||||
switch strongSelf.mode {
|
||||
case let .password(doneText):
|
||||
case let .password(_, doneText):
|
||||
let values = (strongSelf.displayNode as! TwoFactorDataInputScreenNode).inputText
|
||||
if values.count != 2 {
|
||||
return
|
||||
@ -924,7 +927,7 @@ public final class TwoFactorDataInputScreen: ViewController {
|
||||
}
|
||||
|
||||
private enum TwoFactorDataInputTextNodeType {
|
||||
case password(confirmation: Bool)
|
||||
case password(phoneNumber: String?, confirmation: Bool)
|
||||
case email
|
||||
case code
|
||||
case hint
|
||||
@ -984,6 +987,7 @@ private final class TwoFactorDataInputTextNode: ASDisplayNode, UITextFieldDelega
|
||||
private let toggleTextHidden: (TwoFactorDataInputTextNode) -> Void
|
||||
|
||||
private let backgroundNode: ASImageNode
|
||||
private var shadowInputNode: TextFieldNode?
|
||||
private let inputNode: TextFieldNode
|
||||
private let hideButtonNode: HighlightableButtonNode
|
||||
private let clearButtonNode: HighlightableButtonNode
|
||||
@ -1068,7 +1072,7 @@ private final class TwoFactorDataInputTextNode: ASDisplayNode, UITextFieldDelega
|
||||
self.hideButtonNode = HighlightableButtonNode()
|
||||
|
||||
switch mode {
|
||||
case let .password(confirmation):
|
||||
case let .password(phoneNumber, confirmation):
|
||||
self.inputNode.textField.keyboardType = .default
|
||||
self.inputNode.textField.isSecureTextEntry = true
|
||||
if confirmation {
|
||||
@ -1076,29 +1080,68 @@ private final class TwoFactorDataInputTextNode: ASDisplayNode, UITextFieldDelega
|
||||
} else {
|
||||
self.inputNode.textField.returnKeyType = .next
|
||||
}
|
||||
if #available(iOS 12.0, *) {
|
||||
if !confirmation, let phoneNumber {
|
||||
let shadowInputNode = TextFieldNode()
|
||||
shadowInputNode.textField.font = Font.regular(17.0)
|
||||
shadowInputNode.textField.textColor = theme.list.freePlainInputField.primaryColor
|
||||
shadowInputNode.textField.attributedPlaceholder = NSAttributedString(string: placeholder, font: Font.regular(17.0), textColor: theme.list.freePlainInputField.placeholderColor)
|
||||
self.shadowInputNode = shadowInputNode
|
||||
|
||||
|
||||
shadowInputNode.textField.textContentType = .username
|
||||
shadowInputNode.textField.text = phoneNumber
|
||||
}
|
||||
|
||||
self.inputNode.textField.textContentType = .newPassword
|
||||
self.inputNode.textField.passwordRules = UITextInputPasswordRules(descriptor: "minlength: 8;")
|
||||
}
|
||||
self.hideButtonNode.isHidden = confirmation
|
||||
case .email:
|
||||
self.inputNode.textField.keyboardType = .emailAddress
|
||||
self.inputNode.textField.returnKeyType = .done
|
||||
self.hideButtonNode.isHidden = true
|
||||
|
||||
if #available(iOS 12.0, *) {
|
||||
self.inputNode.textField.textContentType = .emailAddress
|
||||
}
|
||||
|
||||
self.inputNode.textField.autocorrectionType = .no
|
||||
self.inputNode.textField.autocapitalizationType = .none
|
||||
self.inputNode.textField.spellCheckingType = .no
|
||||
if #available(iOS 11.0, *) {
|
||||
self.inputNode.textField.smartQuotesType = .no
|
||||
self.inputNode.textField.smartDashesType = .no
|
||||
self.inputNode.textField.smartInsertDeleteType = .no
|
||||
}
|
||||
case .code:
|
||||
self.inputNode.textField.keyboardType = .numberPad
|
||||
self.inputNode.textField.returnKeyType = .done
|
||||
self.hideButtonNode.isHidden = true
|
||||
|
||||
self.inputNode.textField.autocorrectionType = .no
|
||||
self.inputNode.textField.autocapitalizationType = .none
|
||||
self.inputNode.textField.spellCheckingType = .no
|
||||
if #available(iOS 11.0, *) {
|
||||
self.inputNode.textField.smartQuotesType = .no
|
||||
self.inputNode.textField.smartDashesType = .no
|
||||
self.inputNode.textField.smartInsertDeleteType = .no
|
||||
}
|
||||
case .hint:
|
||||
self.inputNode.textField.keyboardType = .asciiCapable
|
||||
self.inputNode.textField.returnKeyType = .done
|
||||
self.hideButtonNode.isHidden = true
|
||||
|
||||
self.inputNode.textField.autocorrectionType = .no
|
||||
self.inputNode.textField.autocapitalizationType = .none
|
||||
self.inputNode.textField.spellCheckingType = .no
|
||||
if #available(iOS 11.0, *) {
|
||||
self.inputNode.textField.smartQuotesType = .no
|
||||
self.inputNode.textField.smartDashesType = .no
|
||||
self.inputNode.textField.smartInsertDeleteType = .no
|
||||
}
|
||||
}
|
||||
|
||||
self.inputNode.textField.autocorrectionType = .no
|
||||
self.inputNode.textField.autocapitalizationType = .none
|
||||
self.inputNode.textField.spellCheckingType = .no
|
||||
if #available(iOS 11.0, *) {
|
||||
self.inputNode.textField.smartQuotesType = .no
|
||||
self.inputNode.textField.smartDashesType = .no
|
||||
self.inputNode.textField.smartInsertDeleteType = .no
|
||||
}
|
||||
self.inputNode.textField.keyboardAppearance = theme.rootController.keyboardColor.keyboardAppearance
|
||||
|
||||
self.hideButtonNode.setImage(generateTextHiddenImage(color: theme.list.freePlainInputField.controlColor, on: false), for: [])
|
||||
@ -1110,6 +1153,10 @@ private final class TwoFactorDataInputTextNode: ASDisplayNode, UITextFieldDelega
|
||||
super.init()
|
||||
|
||||
self.addSubnode(self.backgroundNode)
|
||||
if let shadowInputNode = self.shadowInputNode {
|
||||
shadowInputNode.alpha = 0.001
|
||||
self.addSubnode(shadowInputNode)
|
||||
}
|
||||
self.addSubnode(self.inputNode)
|
||||
self.addSubnode(self.hideButtonNode)
|
||||
|
||||
@ -1179,6 +1226,10 @@ private final class TwoFactorDataInputTextNode: ASDisplayNode, UITextFieldDelega
|
||||
let leftInset: CGFloat = 16.0
|
||||
let rightInset: CGFloat = 38.0
|
||||
|
||||
if let shadowInputNode = self.shadowInputNode {
|
||||
transition.updateFrame(node: shadowInputNode, frame: CGRect(origin: CGPoint(x: leftInset, y: 0.0), size: CGSize(width: size.width - leftInset - rightInset, height: size.height)))
|
||||
}
|
||||
|
||||
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: size))
|
||||
transition.updateFrame(node: self.inputNode, frame: CGRect(origin: CGPoint(x: leftInset, y: 0.0), size: CGSize(width: size.width - leftInset - rightInset, height: size.height)))
|
||||
transition.updateFrame(node: self.hideButtonNode, frame: CGRect(origin: CGPoint(x: size.width - rightInset - 4.0, y: 0.0), size: CGSize(width: rightInset + 4.0, height: size.height)))
|
||||
@ -1299,7 +1350,7 @@ private final class TwoFactorDataInputScreenNode: ViewControllerTracingNode, UIS
|
||||
var toggleTextHidden: ((TwoFactorDataInputTextNode) -> Void)?
|
||||
|
||||
switch mode {
|
||||
case .password:
|
||||
case let .password(phoneNumber, _):
|
||||
title = presentationData.strings.TwoFactorSetup_Password_Title
|
||||
text = NSAttributedString(string: "", font: Font.regular(16.0), textColor: presentationData.theme.list.itemPrimaryTextColor)
|
||||
buttonText = presentationData.strings.TwoFactorSetup_Password_Action
|
||||
@ -1307,7 +1358,7 @@ private final class TwoFactorDataInputScreenNode: ViewControllerTracingNode, UIS
|
||||
changeEmailActionText = ""
|
||||
resendCodeActionText = ""
|
||||
inputNodes = [
|
||||
TwoFactorDataInputTextNode(theme: presentationData.theme, mode: .password(confirmation: false), placeholder: presentationData.strings.TwoFactorSetup_Password_PlaceholderPassword, focusUpdated: { node, focused in
|
||||
TwoFactorDataInputTextNode(theme: presentationData.theme, mode: .password(phoneNumber: phoneNumber, confirmation: false), placeholder: presentationData.strings.TwoFactorSetup_Password_PlaceholderPassword, focusUpdated: { node, focused in
|
||||
focusUpdated?(node, focused)
|
||||
}, next: { node in
|
||||
next?(node)
|
||||
@ -1316,7 +1367,7 @@ private final class TwoFactorDataInputScreenNode: ViewControllerTracingNode, UIS
|
||||
}, toggleTextHidden: { node in
|
||||
toggleTextHidden?(node)
|
||||
}),
|
||||
TwoFactorDataInputTextNode(theme: presentationData.theme, mode: .password(confirmation: true), placeholder: presentationData.strings.TwoFactorSetup_Password_PlaceholderConfirmPassword, focusUpdated: { node, focused in
|
||||
TwoFactorDataInputTextNode(theme: presentationData.theme, mode: .password(phoneNumber: phoneNumber, confirmation: true), placeholder: presentationData.strings.TwoFactorSetup_Password_PlaceholderConfirmPassword, focusUpdated: { node, focused in
|
||||
focusUpdated?(node, focused)
|
||||
}, next: { node in
|
||||
next?(node)
|
||||
@ -1334,7 +1385,7 @@ private final class TwoFactorDataInputScreenNode: ViewControllerTracingNode, UIS
|
||||
changeEmailActionText = ""
|
||||
resendCodeActionText = ""
|
||||
inputNodes = [
|
||||
TwoFactorDataInputTextNode(theme: presentationData.theme, mode: .password(confirmation: false), placeholder: presentationData.strings.TwoFactorSetup_PasswordRecovery_PlaceholderPassword, focusUpdated: { node, focused in
|
||||
TwoFactorDataInputTextNode(theme: presentationData.theme, mode: .password(phoneNumber: nil, confirmation: false), placeholder: presentationData.strings.TwoFactorSetup_PasswordRecovery_PlaceholderPassword, focusUpdated: { node, focused in
|
||||
focusUpdated?(node, focused)
|
||||
}, next: { node in
|
||||
next?(node)
|
||||
@ -1343,7 +1394,7 @@ private final class TwoFactorDataInputScreenNode: ViewControllerTracingNode, UIS
|
||||
}, toggleTextHidden: { node in
|
||||
toggleTextHidden?(node)
|
||||
}),
|
||||
TwoFactorDataInputTextNode(theme: presentationData.theme, mode: .password(confirmation: true), placeholder: presentationData.strings.TwoFactorSetup_PasswordRecovery_PlaceholderConfirmPassword, focusUpdated: { node, focused in
|
||||
TwoFactorDataInputTextNode(theme: presentationData.theme, mode: .password(phoneNumber: nil, confirmation: true), placeholder: presentationData.strings.TwoFactorSetup_PasswordRecovery_PlaceholderConfirmPassword, focusUpdated: { node, focused in
|
||||
focusUpdated?(node, focused)
|
||||
}, next: { node in
|
||||
next?(node)
|
||||
@ -1453,7 +1504,7 @@ private final class TwoFactorDataInputScreenNode: ViewControllerTracingNode, UIS
|
||||
changeEmailActionText = ""
|
||||
resendCodeActionText = ""
|
||||
inputNodes = [
|
||||
TwoFactorDataInputTextNode(theme: presentationData.theme, mode: .password(confirmation: false), placeholder: presentationData.strings.TwoFactorRemember_Placeholder, focusUpdated: { node, focused in
|
||||
TwoFactorDataInputTextNode(theme: presentationData.theme, mode: .password(phoneNumber: nil, confirmation: false), placeholder: presentationData.strings.TwoFactorRemember_Placeholder, focusUpdated: { node, focused in
|
||||
focusUpdated?(node, focused)
|
||||
}, next: { node in
|
||||
next?(node)
|
||||
|
||||
@ -18,17 +18,20 @@ public enum TwoFactorAuthSplashMode {
|
||||
public var text: String
|
||||
public var actionText: String
|
||||
public var doneText: String
|
||||
public var phoneNumber: String?
|
||||
|
||||
public init(
|
||||
title: String,
|
||||
text: String,
|
||||
actionText: String,
|
||||
doneText: String
|
||||
doneText: String,
|
||||
phoneNumber: String?
|
||||
) {
|
||||
self.title = title
|
||||
self.text = text
|
||||
self.actionText = actionText
|
||||
self.doneText = doneText
|
||||
self.phoneNumber = phoneNumber
|
||||
}
|
||||
}
|
||||
|
||||
@ -100,7 +103,7 @@ public final class TwoFactorAuthSplashScreen: ViewController {
|
||||
}
|
||||
switch strongSelf.mode {
|
||||
case let .intro(intro):
|
||||
strongSelf.push(TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .password(doneText: intro.doneText), stateUpdated: { _ in
|
||||
strongSelf.push(TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .password(phoneNumber: intro.phoneNumber, doneText: intro.doneText), stateUpdated: { _ in
|
||||
}, presentation: strongSelf.navigationPresentation))
|
||||
case .done, .remember:
|
||||
guard let navigationController = strongSelf.navigationController as? NavigationController else {
|
||||
|
||||
@ -13,15 +13,15 @@ import StickerPackPreviewUI
|
||||
import ItemListStickerPackItem
|
||||
|
||||
private final class GroupStickerPackSetupControllerArguments {
|
||||
let account: Account
|
||||
let context: AccountContext
|
||||
|
||||
let selectStickerPack: (StickerPackCollectionInfo) -> Void
|
||||
let openStickerPack: (StickerPackCollectionInfo) -> Void
|
||||
let updateSearchText: (String) -> Void
|
||||
let openStickersBot: () -> Void
|
||||
|
||||
init(account: Account, selectStickerPack: @escaping (StickerPackCollectionInfo) -> Void, openStickerPack: @escaping (StickerPackCollectionInfo) -> Void, updateSearchText: @escaping (String) -> Void, openStickersBot: @escaping () -> Void) {
|
||||
self.account = account
|
||||
init(context: AccountContext, selectStickerPack: @escaping (StickerPackCollectionInfo) -> Void, openStickerPack: @escaping (StickerPackCollectionInfo) -> Void, updateSearchText: @escaping (String) -> Void, openStickersBot: @escaping () -> Void) {
|
||||
self.context = context
|
||||
self.selectStickerPack = selectStickerPack
|
||||
self.openStickerPack = openStickerPack
|
||||
self.updateSearchText = updateSearchText
|
||||
@ -218,7 +218,7 @@ private enum GroupStickerPackEntry: ItemListNodeEntry {
|
||||
case let .packsTitle(_, text):
|
||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
|
||||
case let .pack(_, _, _, info, topItem, count, playAnimatedStickers, selected):
|
||||
return ItemListStickerPackItem(presentationData: presentationData, 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, selectable: false), enabled: true, playAnimatedStickers: playAnimatedStickers, sectionId: self.section, action: {
|
||||
return ItemListStickerPackItem(presentationData: presentationData, context: arguments.context, packInfo: info, itemCount: count, topItem: topItem, unread: false, control: selected ? .selection : .none, editing: ItemListStickerPackItemEditing(editable: false, editing: false, revealed: false, reorderable: false, selectable: false), enabled: true, playAnimatedStickers: playAnimatedStickers, sectionId: self.section, action: {
|
||||
if selected {
|
||||
arguments.openStickerPack(info)
|
||||
} else {
|
||||
@ -230,7 +230,7 @@ private enum GroupStickerPackEntry: ItemListNodeEntry {
|
||||
}, toggleSelected: {
|
||||
})
|
||||
case let .currentPack(_, theme, strings, content):
|
||||
return GroupStickerPackCurrentItem(theme: theme, strings: strings, account: arguments.account, content: content, sectionId: self.section, action: {
|
||||
return GroupStickerPackCurrentItem(theme: theme, strings: strings, account: arguments.context.account, content: content, sectionId: self.section, action: {
|
||||
if case let .found(packInfo, _, _) = content {
|
||||
arguments.openStickerPack(packInfo)
|
||||
}
|
||||
@ -385,7 +385,7 @@ public func groupStickerPackSetupController(context: AccountContext, updatedPres
|
||||
|
||||
var presentStickerPackController: ((StickerPackCollectionInfo) -> Void)?
|
||||
|
||||
let arguments = GroupStickerPackSetupControllerArguments(account: context.account, selectStickerPack: { info in
|
||||
let arguments = GroupStickerPackSetupControllerArguments(context: context, selectStickerPack: { info in
|
||||
searchText.set(info.shortName)
|
||||
}, openStickerPack: { info in
|
||||
presentStickerPackController?(info)
|
||||
|
||||
@ -268,7 +268,7 @@ private class StickerNode: ASDisplayNode {
|
||||
if self.placeholderNode.supernode != nil {
|
||||
let placeholderFrame = CGRect(origin: CGPoint(x: -10.0, y: 0.0), size: imageSize)
|
||||
let thumbnailDimensions = PixelDimensions(width: 512, height: 512)
|
||||
self.placeholderNode.update(backgroundColor: nil, foregroundColor: UIColor(rgb: 0xffffff, alpha: 0.2), shimmeringColor: UIColor(rgb: 0xffffff, alpha: 0.3), data: self.file.immediateThumbnailData, size: placeholderFrame.size, imageSize: thumbnailDimensions.cgSize)
|
||||
self.placeholderNode.update(backgroundColor: nil, foregroundColor: UIColor(rgb: 0xffffff, alpha: 0.2), shimmeringColor: UIColor(rgb: 0xffffff, alpha: 0.3), data: self.file.immediateThumbnailData, size: placeholderFrame.size, enableEffect: true, imageSize: thumbnailDimensions.cgSize)
|
||||
self.placeholderNode.frame = placeholderFrame
|
||||
}
|
||||
}
|
||||
|
||||
@ -735,9 +735,9 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
loopIdle = true
|
||||
#endif
|
||||
if !self.context.sharedContext.energyUsageSettings.loopEmoji {
|
||||
loopIdle = false
|
||||
}
|
||||
|
||||
var validIndices = Set<Int>()
|
||||
var nextX: CGFloat = sideInset
|
||||
|
||||
@ -33,12 +33,13 @@ private final class DataAndStorageControllerArguments {
|
||||
let toggleRaiseToListen: (Bool) -> Void
|
||||
let toggleAutoplayGifs: (Bool) -> Void
|
||||
let toggleAutoplayVideos: (Bool) -> Void
|
||||
let openEnergySavingSettings: () -> Void
|
||||
let toggleDownloadInBackground: (Bool) -> Void
|
||||
let openBrowserSelection: () -> Void
|
||||
let openIntents: () -> Void
|
||||
let toggleEnableSensitiveContent: (Bool) -> Void
|
||||
|
||||
init(openStorageUsage: @escaping () -> Void, openNetworkUsage: @escaping () -> Void, openProxy: @escaping () -> Void, openAutomaticDownloadConnectionType: @escaping (AutomaticDownloadConnectionType) -> Void, resetAutomaticDownload: @escaping () -> Void, toggleVoiceUseLessData: @escaping (Bool) -> Void, openSaveIncoming: @escaping (AutomaticSaveIncomingPeerType) -> Void, toggleSaveEditedPhotos: @escaping (Bool) -> Void, togglePauseMusicOnRecording: @escaping (Bool) -> Void, toggleRaiseToListen: @escaping (Bool) -> Void, toggleAutoplayGifs: @escaping (Bool) -> Void, toggleAutoplayVideos: @escaping (Bool) -> Void, toggleDownloadInBackground: @escaping (Bool) -> Void, openBrowserSelection: @escaping () -> Void, openIntents: @escaping () -> Void, toggleEnableSensitiveContent: @escaping (Bool) -> Void) {
|
||||
init(openStorageUsage: @escaping () -> Void, openNetworkUsage: @escaping () -> Void, openProxy: @escaping () -> Void, openAutomaticDownloadConnectionType: @escaping (AutomaticDownloadConnectionType) -> Void, resetAutomaticDownload: @escaping () -> Void, toggleVoiceUseLessData: @escaping (Bool) -> Void, openSaveIncoming: @escaping (AutomaticSaveIncomingPeerType) -> Void, toggleSaveEditedPhotos: @escaping (Bool) -> Void, togglePauseMusicOnRecording: @escaping (Bool) -> Void, toggleRaiseToListen: @escaping (Bool) -> Void, toggleAutoplayGifs: @escaping (Bool) -> Void, toggleAutoplayVideos: @escaping (Bool) -> Void, openEnergySavingSettings: @escaping () -> Void, toggleDownloadInBackground: @escaping (Bool) -> Void, openBrowserSelection: @escaping () -> Void, openIntents: @escaping () -> Void, toggleEnableSensitiveContent: @escaping (Bool) -> Void) {
|
||||
self.openStorageUsage = openStorageUsage
|
||||
self.openNetworkUsage = openNetworkUsage
|
||||
self.openProxy = openProxy
|
||||
@ -51,6 +52,7 @@ private final class DataAndStorageControllerArguments {
|
||||
self.toggleRaiseToListen = toggleRaiseToListen
|
||||
self.toggleAutoplayGifs = toggleAutoplayGifs
|
||||
self.toggleAutoplayVideos = toggleAutoplayVideos
|
||||
self.openEnergySavingSettings = openEnergySavingSettings
|
||||
self.toggleDownloadInBackground = toggleDownloadInBackground
|
||||
self.openBrowserSelection = openBrowserSelection
|
||||
self.openIntents = openIntents
|
||||
@ -64,6 +66,7 @@ private enum DataAndStorageSection: Int32 {
|
||||
case autoSave
|
||||
case backgroundDownload
|
||||
case autoPlay
|
||||
case energySaving
|
||||
case voiceCalls
|
||||
case other
|
||||
case connection
|
||||
@ -107,6 +110,9 @@ private enum DataAndStorageEntry: ItemListNodeEntry {
|
||||
case autoplayHeader(PresentationTheme, String)
|
||||
case autoplayGifs(PresentationTheme, String, Bool)
|
||||
case autoplayVideos(PresentationTheme, String, Bool)
|
||||
|
||||
case energySaving
|
||||
|
||||
case useLessVoiceData(PresentationTheme, String, Bool)
|
||||
case useLessVoiceDataInfo(PresentationTheme, String)
|
||||
case otherHeader(PresentationTheme, String)
|
||||
@ -135,6 +141,8 @@ private enum DataAndStorageEntry: ItemListNodeEntry {
|
||||
return DataAndStorageSection.voiceCalls.rawValue
|
||||
case .autoplayHeader, .autoplayGifs, .autoplayVideos:
|
||||
return DataAndStorageSection.autoPlay.rawValue
|
||||
case .energySaving:
|
||||
return DataAndStorageSection.energySaving.rawValue
|
||||
case .otherHeader, .shareSheet, .saveEditedPhotos, .openLinksIn, .pauseMusicOnRecording, .raiseToListen, .raiseToListenInfo:
|
||||
return DataAndStorageSection.other.rawValue
|
||||
case .connectionHeader, .connectionProxy:
|
||||
@ -178,10 +186,12 @@ private enum DataAndStorageEntry: ItemListNodeEntry {
|
||||
return 26
|
||||
case .autoplayVideos:
|
||||
return 27
|
||||
case .otherHeader:
|
||||
case .energySaving:
|
||||
return 28
|
||||
case .shareSheet:
|
||||
case .otherHeader:
|
||||
return 29
|
||||
case .shareSheet:
|
||||
return 30
|
||||
case .saveEditedPhotos:
|
||||
return 31
|
||||
case .openLinksIn:
|
||||
@ -275,6 +285,12 @@ private enum DataAndStorageEntry: ItemListNodeEntry {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case .energySaving:
|
||||
if case .energySaving = rhs {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .useLessVoiceData(lhsTheme, lhsText, lhsValue):
|
||||
if case let .useLessVoiceData(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
|
||||
return true
|
||||
@ -424,6 +440,11 @@ private enum DataAndStorageEntry: ItemListNodeEntry {
|
||||
return ItemListSwitchItem(presentationData: presentationData, title: text, value: value, sectionId: self.section, style: .blocks, updated: { value in
|
||||
arguments.toggleAutoplayVideos(value)
|
||||
}, tag: DataAndStorageEntryTag.autoplayVideos)
|
||||
case .energySaving:
|
||||
//TODO:localize
|
||||
return ItemListDisclosureItem(presentationData: presentationData, title: "Energy Saving", label: "", sectionId: self.section, style: .blocks, action: {
|
||||
arguments.openEnergySavingSettings()
|
||||
})
|
||||
case let .useLessVoiceData(_, text, value):
|
||||
return ItemListSwitchItem(presentationData: presentationData, title: text, value: value, sectionId: self.section, style: .blocks, updated: { value in
|
||||
arguments.toggleVoiceUseLessData(value)
|
||||
@ -667,6 +688,8 @@ private func dataAndStorageControllerEntries(state: DataAndStorageControllerStat
|
||||
entries.append(.autoplayGifs(presentationData.theme, presentationData.strings.ChatSettings_AutoPlayGifs, data.automaticMediaDownloadSettings.autoplayGifs))
|
||||
entries.append(.autoplayVideos(presentationData.theme, presentationData.strings.ChatSettings_AutoPlayVideos, data.automaticMediaDownloadSettings.autoplayVideos))
|
||||
|
||||
entries.append(.energySaving)
|
||||
|
||||
entries.append(.otherHeader(presentationData.theme, presentationData.strings.ChatSettings_Other))
|
||||
if #available(iOSApplicationExtension 13.2, iOS 13.2, *) {
|
||||
entries.append(.shareSheet(presentationData.theme, presentationData.strings.ChatSettings_IntentsSettings))
|
||||
@ -922,6 +945,8 @@ public func dataAndStorageController(context: AccountContext, focusOnItemTag: Da
|
||||
settings.autoplayVideos = value
|
||||
return settings
|
||||
}).start()
|
||||
}, openEnergySavingSettings: {
|
||||
pushControllerImpl?(energySavingSettingsScreen(context: context))
|
||||
}, toggleDownloadInBackground: { value in
|
||||
let _ = updateMediaDownloadSettingsInteractively(accountManager: context.sharedContext.accountManager, { settings in
|
||||
var settings = settings
|
||||
|
||||
@ -0,0 +1,199 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import TelegramPresentationData
|
||||
import TelegramUIPreferences
|
||||
import ItemListUI
|
||||
import PresentationDataUtils
|
||||
import AccountContext
|
||||
|
||||
enum ItemType: CaseIterable {
|
||||
case loopEmoji
|
||||
case playVideoAvatars
|
||||
case fullTranslucency
|
||||
case extendBackgroundWork
|
||||
case synchronizeInBackground
|
||||
case autodownloadInBackground
|
||||
|
||||
var settingsKeyPath: WritableKeyPath<EnergyUsageSettings, Bool> {
|
||||
switch self {
|
||||
case .loopEmoji:
|
||||
return \.loopEmoji
|
||||
case .playVideoAvatars:
|
||||
return \.playVideoAvatars
|
||||
case .fullTranslucency:
|
||||
return \.fullTranslucency
|
||||
case .extendBackgroundWork:
|
||||
return \.extendBackgroundWork
|
||||
case .synchronizeInBackground:
|
||||
return \.synchronizeInBackground
|
||||
case .autodownloadInBackground:
|
||||
return \.autodownloadInBackground
|
||||
}
|
||||
}
|
||||
|
||||
func title(strings: PresentationStrings) -> String {
|
||||
//TODO:localize
|
||||
switch self {
|
||||
case .loopEmoji:
|
||||
return "Loop Animated Emoji"
|
||||
case .playVideoAvatars:
|
||||
return "Play Video Avatars"
|
||||
case .fullTranslucency:
|
||||
return "Translucency Effects"
|
||||
case .extendBackgroundWork:
|
||||
return "Extended Background Time"
|
||||
case .synchronizeInBackground:
|
||||
return "Background Sync"
|
||||
case .autodownloadInBackground:
|
||||
return "Preload Media in Chats"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class EnergeSavingSettingsScreenArguments {
|
||||
let toggleAll: (Bool) -> Void
|
||||
let toggleItem: (ItemType) -> Void
|
||||
|
||||
init(toggleAll: @escaping (Bool) -> Void, toggleItem: @escaping (ItemType) -> Void) {
|
||||
self.toggleAll = toggleAll
|
||||
self.toggleItem = toggleItem
|
||||
}
|
||||
}
|
||||
|
||||
private enum EnergeSavingSettingsScreenSection: Int32 {
|
||||
case all
|
||||
case items
|
||||
}
|
||||
|
||||
private enum EnergeSavingSettingsScreenEntry: ItemListNodeEntry {
|
||||
enum StableId: Hashable {
|
||||
case all
|
||||
case item(ItemType)
|
||||
}
|
||||
|
||||
case all(Bool)
|
||||
case item(index: Int, type: ItemType, value: Bool)
|
||||
|
||||
var section: ItemListSectionId {
|
||||
switch self {
|
||||
case .all:
|
||||
return EnergeSavingSettingsScreenSection.all.rawValue
|
||||
case .item:
|
||||
return EnergeSavingSettingsScreenSection.items.rawValue
|
||||
}
|
||||
}
|
||||
|
||||
var sortIndex: Int {
|
||||
switch self {
|
||||
case .all:
|
||||
return -1
|
||||
case let .item(index, _, _):
|
||||
return index
|
||||
}
|
||||
}
|
||||
|
||||
var stableId: StableId {
|
||||
switch self {
|
||||
case .all:
|
||||
return .all
|
||||
case let .item(_, type, _):
|
||||
return .item(type)
|
||||
}
|
||||
}
|
||||
|
||||
static func <(lhs: EnergeSavingSettingsScreenEntry, rhs: EnergeSavingSettingsScreenEntry) -> Bool {
|
||||
return lhs.sortIndex < rhs.sortIndex
|
||||
}
|
||||
|
||||
func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem {
|
||||
let arguments = arguments as! EnergeSavingSettingsScreenArguments
|
||||
switch self {
|
||||
case let .all(value):
|
||||
//TODO:localize
|
||||
return ItemListSwitchItem(presentationData: presentationData, title: "Enable All", value: value, enableInteractiveChanges: true, enabled: true, sectionId: self.section, style: .blocks, updated: { value in
|
||||
arguments.toggleAll(value)
|
||||
})
|
||||
case let .item(_, type, value):
|
||||
return ItemListSwitchItem(presentationData: presentationData, title: type.title(strings: presentationData.strings), value: value, enableInteractiveChanges: true, enabled: true, sectionId: self.section, style: .blocks, updated: { value in
|
||||
arguments.toggleItem(type)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func energeSavingSettingsScreenEntries(
|
||||
presentationData: PresentationData,
|
||||
settings: MediaAutoDownloadSettings
|
||||
) -> [EnergeSavingSettingsScreenEntry] {
|
||||
var entries: [EnergeSavingSettingsScreenEntry] = []
|
||||
|
||||
entries.append(.all(ItemType.allCases.allSatisfy({ item in settings.energyUsageSettings[keyPath: item.settingsKeyPath] })))
|
||||
|
||||
for type in ItemType.allCases {
|
||||
entries.append(.item(index: entries.count, type: type, value: settings.energyUsageSettings[keyPath: type.settingsKeyPath]))
|
||||
}
|
||||
|
||||
return entries
|
||||
}
|
||||
|
||||
func energySavingSettingsScreen(context: AccountContext) -> ViewController {
|
||||
var pushControllerImpl: ((ViewController) -> Void)?
|
||||
let _ = pushControllerImpl
|
||||
|
||||
let arguments = EnergeSavingSettingsScreenArguments(
|
||||
toggleAll: { value in
|
||||
let _ = updateMediaDownloadSettingsInteractively(accountManager: context.sharedContext.accountManager, { settings in
|
||||
var settings = settings
|
||||
for type in ItemType.allCases {
|
||||
settings.energyUsageSettings[keyPath: type.settingsKeyPath] = value
|
||||
}
|
||||
return settings
|
||||
}).start()
|
||||
},
|
||||
toggleItem: { type in
|
||||
let _ = updateMediaDownloadSettingsInteractively(accountManager: context.sharedContext.accountManager, { settings in
|
||||
var settings = settings
|
||||
settings.energyUsageSettings[keyPath: type.settingsKeyPath] = !settings.energyUsageSettings[keyPath: type.settingsKeyPath]
|
||||
return settings
|
||||
}).start()
|
||||
}
|
||||
)
|
||||
|
||||
let signal = combineLatest(
|
||||
context.sharedContext.presentationData,
|
||||
context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings]))
|
||||
|> deliverOnMainQueue
|
||||
|> map { presentationData, sharedData -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
||||
var automaticMediaDownloadSettings: MediaAutoDownloadSettings
|
||||
if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings]?.get(MediaAutoDownloadSettings.self) {
|
||||
automaticMediaDownloadSettings = value
|
||||
} else {
|
||||
automaticMediaDownloadSettings = MediaAutoDownloadSettings.defaultSettings
|
||||
}
|
||||
|
||||
//TODO:localize
|
||||
let controllerState = ItemListControllerState(
|
||||
presentationData: ItemListPresentationData(presentationData),
|
||||
title: .text("Energy Saving"),
|
||||
leftNavigationButton: nil,
|
||||
rightNavigationButton: nil,
|
||||
backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back),
|
||||
animateChanges: false
|
||||
)
|
||||
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: energeSavingSettingsScreenEntries(presentationData: presentationData, settings: automaticMediaDownloadSettings), style: .blocks, emptyStateItem: nil, animateChanges: true)
|
||||
|
||||
return (controllerState, (listState, arguments))
|
||||
}
|
||||
|
||||
let controller = ItemListController(context: context, state: signal)
|
||||
pushControllerImpl = { [weak controller] c in
|
||||
if let controller = controller {
|
||||
(controller.navigationController as? NavigationController)?.pushViewController(c)
|
||||
}
|
||||
}
|
||||
return controller
|
||||
}
|
||||
@ -248,7 +248,8 @@ public func deleteAccountOptionsController(context: AccountContext, navigationCo
|
||||
title: presentationData.strings.TwoFactorSetup_Intro_Title,
|
||||
text: presentationData.strings.TwoFactorSetup_Intro_Text,
|
||||
actionText: presentationData.strings.TwoFactorSetup_Intro_Action,
|
||||
doneText: presentationData.strings.TwoFactorSetup_Done_Action
|
||||
doneText: presentationData.strings.TwoFactorSetup_Done_Action,
|
||||
phoneNumber: nil
|
||||
)))
|
||||
|
||||
replaceTopControllerImpl?(controller, false)
|
||||
|
||||
@ -944,28 +944,37 @@ public func privacyAndSecurityController(
|
||||
}
|
||||
})
|
||||
}, openTwoStepVerification: { data in
|
||||
if let data = data {
|
||||
switch data {
|
||||
case .set:
|
||||
break
|
||||
case let .notSet(pendingEmail):
|
||||
if pendingEmail == nil {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let controller = TwoFactorAuthSplashScreen(sharedContext: context.sharedContext, engine: .authorized(context.engine), mode: .intro(.init(
|
||||
title: presentationData.strings.TwoFactorSetup_Intro_Title,
|
||||
text: presentationData.strings.TwoFactorSetup_Intro_Text,
|
||||
actionText: presentationData.strings.TwoFactorSetup_Intro_Action,
|
||||
doneText: presentationData.strings.TwoFactorSetup_Done_Action
|
||||
)))
|
||||
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId))
|
||||
|> deliverOnMainQueue).start(next: { peer in
|
||||
if let data = data {
|
||||
switch data {
|
||||
case .set:
|
||||
break
|
||||
case let .notSet(pendingEmail):
|
||||
if pendingEmail == nil {
|
||||
var phoneNumber: String?
|
||||
if case let .user(user) = peer {
|
||||
phoneNumber = user.phone
|
||||
}
|
||||
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let controller = TwoFactorAuthSplashScreen(sharedContext: context.sharedContext, engine: .authorized(context.engine), mode: .intro(.init(
|
||||
title: presentationData.strings.TwoFactorSetup_Intro_Title,
|
||||
text: presentationData.strings.TwoFactorSetup_Intro_Text,
|
||||
actionText: presentationData.strings.TwoFactorSetup_Intro_Action,
|
||||
doneText: presentationData.strings.TwoFactorSetup_Done_Action,
|
||||
phoneNumber: phoneNumber
|
||||
)))
|
||||
|
||||
pushControllerImpl?(controller, true)
|
||||
return
|
||||
pushControllerImpl?(controller, true)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let controller = twoStepVerificationUnlockSettingsController(context: context, mode: .access(intro: false, data: data.flatMap({ Signal<TwoStepVerificationUnlockSettingsControllerData, NoError>.single(.access(configuration: $0)) })))
|
||||
pushControllerImpl?(controller, true)
|
||||
let controller = twoStepVerificationUnlockSettingsController(context: context, mode: .access(intro: false, data: data.flatMap({ Signal<TwoStepVerificationUnlockSettingsControllerData, NoError>.single(.access(configuration: $0)) })))
|
||||
pushControllerImpl?(controller, true)
|
||||
})
|
||||
}, openActiveSessions: {
|
||||
pushControllerImpl?(recentSessionsController(context: context, activeSessionsContext: activeSessionsContext, webSessionsContext: webSessionsContext, websitesOnly: true), true)
|
||||
}, toggleArchiveAndMuteNonContacts: { archiveValue in
|
||||
|
||||
@ -21,7 +21,8 @@ public func makeSetupTwoFactorAuthController(context: AccountContext) -> ViewCon
|
||||
title: presentationData.strings.TwoFactorSetup_Intro_Title,
|
||||
text: presentationData.strings.TwoFactorSetup_Intro_Text,
|
||||
actionText: presentationData.strings.TwoFactorSetup_Intro_Action,
|
||||
doneText: presentationData.strings.TwoFactorSetup_Done_Action
|
||||
doneText: presentationData.strings.TwoFactorSetup_Done_Action,
|
||||
phoneNumber: nil
|
||||
)))
|
||||
return controller
|
||||
}
|
||||
|
||||
@ -21,15 +21,15 @@ public enum ArchivedStickerPacksControllerMode {
|
||||
}
|
||||
|
||||
private final class ArchivedStickerPacksControllerArguments {
|
||||
let account: Account
|
||||
let context: AccountContext
|
||||
|
||||
let openStickerPack: (StickerPackCollectionInfo) -> Void
|
||||
let setPackIdWithRevealedOptions: (ItemCollectionId?, ItemCollectionId?) -> Void
|
||||
let addPack: (StickerPackCollectionInfo) -> Void
|
||||
let removePack: (StickerPackCollectionInfo) -> Void
|
||||
|
||||
init(account: Account, openStickerPack: @escaping (StickerPackCollectionInfo) -> Void, setPackIdWithRevealedOptions: @escaping (ItemCollectionId?, ItemCollectionId?) -> Void, addPack: @escaping (StickerPackCollectionInfo) -> Void, removePack: @escaping (StickerPackCollectionInfo) -> Void) {
|
||||
self.account = account
|
||||
init(context: AccountContext, openStickerPack: @escaping (StickerPackCollectionInfo) -> Void, setPackIdWithRevealedOptions: @escaping (ItemCollectionId?, ItemCollectionId?) -> Void, addPack: @escaping (StickerPackCollectionInfo) -> Void, removePack: @escaping (StickerPackCollectionInfo) -> Void) {
|
||||
self.context = context
|
||||
self.openStickerPack = openStickerPack
|
||||
self.setPackIdWithRevealedOptions = setPackIdWithRevealedOptions
|
||||
self.addPack = addPack
|
||||
@ -135,7 +135,7 @@ private enum ArchivedStickerPacksEntry: ItemListNodeEntry {
|
||||
case let .info(_, text):
|
||||
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section)
|
||||
case let .pack(_, _, _, info, topItem, count, animatedStickers, enabled, editing):
|
||||
return ItemListStickerPackItem(presentationData: presentationData, 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: {
|
||||
return ItemListStickerPackItem(presentationData: presentationData, context: arguments.context, 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)
|
||||
}, setPackIdWithRevealedOptions: { current, previous in
|
||||
arguments.setPackIdWithRevealedOptions(current, previous)
|
||||
@ -264,7 +264,7 @@ public func archivedStickerPacksController(context: AccountContext, mode: Archiv
|
||||
|
||||
var presentStickerPackController: ((StickerPackCollectionInfo) -> Void)?
|
||||
|
||||
let arguments = ArchivedStickerPacksControllerArguments(account: context.account, openStickerPack: { info in
|
||||
let arguments = ArchivedStickerPacksControllerArguments(context: context, openStickerPack: { info in
|
||||
presentStickerPackController?(info)
|
||||
}, setPackIdWithRevealedOptions: { packId, fromPackId in
|
||||
updateState { state in
|
||||
|
||||
@ -13,13 +13,13 @@ import StickerPackPreviewUI
|
||||
import ItemListStickerPackItem
|
||||
|
||||
private final class FeaturedStickerPacksControllerArguments {
|
||||
let account: Account
|
||||
let context: AccountContext
|
||||
|
||||
let openStickerPack: (StickerPackCollectionInfo) -> Void
|
||||
let addPack: (StickerPackCollectionInfo) -> Void
|
||||
|
||||
init(account: Account, openStickerPack: @escaping (StickerPackCollectionInfo) -> Void, addPack: @escaping (StickerPackCollectionInfo) -> Void) {
|
||||
self.account = account
|
||||
init(context: AccountContext, openStickerPack: @escaping (StickerPackCollectionInfo) -> Void, addPack: @escaping (StickerPackCollectionInfo) -> Void) {
|
||||
self.context = context
|
||||
self.openStickerPack = openStickerPack
|
||||
self.addPack = addPack
|
||||
}
|
||||
@ -102,7 +102,7 @@ private enum FeaturedStickerPacksEntry: ItemListNodeEntry {
|
||||
let arguments = arguments as! FeaturedStickerPacksControllerArguments
|
||||
switch self {
|
||||
case let .pack(_, _, _, info, unread, topItem, count, playAnimatedStickers, installed):
|
||||
return ItemListStickerPackItem(presentationData: presentationData, 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, selectable: false), enabled: true, playAnimatedStickers: playAnimatedStickers, sectionId: self.section, action: {
|
||||
return ItemListStickerPackItem(presentationData: presentationData, context: arguments.context, packInfo: info, itemCount: count, topItem: topItem, unread: unread, control: .installation(installed: installed), editing: ItemListStickerPackItemEditing(editable: false, editing: false, revealed: false, reorderable: false, selectable: false), enabled: true, playAnimatedStickers: playAnimatedStickers, sectionId: self.section, action: {
|
||||
arguments.openStickerPack(info)
|
||||
}, setPackIdWithRevealedOptions: { _, _ in
|
||||
}, addPack: {
|
||||
@ -168,7 +168,7 @@ public func featuredStickerPacksController(context: AccountContext) -> ViewContr
|
||||
|
||||
var presentStickerPackController: ((StickerPackCollectionInfo) -> Void)?
|
||||
|
||||
let arguments = FeaturedStickerPacksControllerArguments(account: context.account, openStickerPack: { info in
|
||||
let arguments = FeaturedStickerPacksControllerArguments(context: context, openStickerPack: { info in
|
||||
presentStickerPackController?(info)
|
||||
}, addPack: { info in
|
||||
let _ = (context.engine.stickers.loadedStickerPack(reference: .id(id: info.id.id, accessHash: info.accessHash), forceActualized: false)
|
||||
|
||||
@ -451,7 +451,7 @@ private indirect enum InstalledStickerPacksEntry: ItemListNodeEntry {
|
||||
case let .trendingPacksTitle(_, text):
|
||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
|
||||
case let .trendingPack(_, _, _, info, topItem, count, animatedStickers, unread, installed):
|
||||
return ItemListStickerPackItem(presentationData: presentationData, account: arguments.context.account, packInfo: info, itemCount: count, topItem: topItem, unread: unread, control: .installation(installed: installed), editing: ItemListStickerPackItemEditing(editable: false, editing: false, revealed: false, reorderable: false, selectable: false), enabled: true, playAnimatedStickers: animatedStickers, sectionId: self.section, action: {
|
||||
return ItemListStickerPackItem(presentationData: presentationData, context: arguments.context, packInfo: info, itemCount: count, topItem: topItem, unread: unread, control: .installation(installed: installed), editing: ItemListStickerPackItemEditing(editable: false, editing: false, revealed: false, reorderable: false, selectable: false), enabled: true, playAnimatedStickers: animatedStickers, sectionId: self.section, action: {
|
||||
arguments.openStickerPack(info)
|
||||
}, setPackIdWithRevealedOptions: { _, _ in
|
||||
}, addPack: {
|
||||
@ -466,7 +466,7 @@ private indirect enum InstalledStickerPacksEntry: ItemListNodeEntry {
|
||||
case let .packsTitle(_, text):
|
||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
|
||||
case let .pack(_, _, _, info, topItem, count, animatedStickers, enabled, editing, selected):
|
||||
return ItemListStickerPackItem(presentationData: presentationData, account: arguments.context.account, packInfo: info, itemCount: count, topItem: topItem, unread: false, control: editing.editing ? .check(checked: selected ?? false) : .none, editing: editing, enabled: enabled, playAnimatedStickers: animatedStickers, sectionId: self.section, action: {
|
||||
return ItemListStickerPackItem(presentationData: presentationData, context: arguments.context, packInfo: info, itemCount: count, topItem: topItem, unread: false, control: editing.editing ? .check(checked: selected ?? false) : .none, editing: editing, enabled: enabled, playAnimatedStickers: animatedStickers, sectionId: self.section, action: {
|
||||
arguments.openStickerPack(info)
|
||||
}, setPackIdWithRevealedOptions: { current, previous in
|
||||
arguments.setPackIdWithRevealedOptions(current, previous)
|
||||
|
||||
@ -440,7 +440,7 @@ private final class ThemeCarouselThemeItemIconNode : ListViewItemNode {
|
||||
strongSelf.stickerFetchedDisposable.set(fetchedMediaResource(mediaBox: item.context.account.postbox.mediaBox, userLocation: .other, userContentType: .sticker, reference: MediaResourceReference.media(media: .standalone(media: file), resource: file.resource)).start())
|
||||
|
||||
let thumbnailDimensions = PixelDimensions(width: 512, height: 512)
|
||||
strongSelf.placeholderNode.update(backgroundColor: nil, foregroundColor: UIColor(rgb: 0xffffff, alpha: 0.2), shimmeringColor: UIColor(rgb: 0xffffff, alpha: 0.3), data: file.immediateThumbnailData, size: emojiFrame.size, imageSize: thumbnailDimensions.cgSize)
|
||||
strongSelf.placeholderNode.update(backgroundColor: nil, foregroundColor: UIColor(rgb: 0xffffff, alpha: 0.2), shimmeringColor: UIColor(rgb: 0xffffff, alpha: 0.3), data: file.immediateThumbnailData, size: emojiFrame.size, enableEffect: item.context.sharedContext.energyUsageSettings.fullTranslucency, imageSize: thumbnailDimensions.cgSize)
|
||||
strongSelf.placeholderNode.frame = emojiFrame
|
||||
}
|
||||
|
||||
|
||||
@ -275,7 +275,7 @@ private final class ThemeGridThemeItemIconNode : ASDisplayNode {
|
||||
self.stickerFetchedDisposable.set(fetchedMediaResource(mediaBox: item.context.account.postbox.mediaBox, userLocation: .other, userContentType: .other, reference: MediaResourceReference.media(media: .standalone(media: file), resource: file.resource)).start())
|
||||
|
||||
let thumbnailDimensions = PixelDimensions(width: 512, height: 512)
|
||||
self.placeholderNode.update(backgroundColor: nil, foregroundColor: UIColor(rgb: 0xffffff, alpha: 0.2), shimmeringColor: UIColor(rgb: 0xffffff, alpha: 0.3), data: file.immediateThumbnailData, size: emojiFrame.size, imageSize: thumbnailDimensions.cgSize)
|
||||
self.placeholderNode.update(backgroundColor: nil, foregroundColor: UIColor(rgb: 0xffffff, alpha: 0.2), shimmeringColor: UIColor(rgb: 0xffffff, alpha: 0.3), data: file.immediateThumbnailData, size: emojiFrame.size, enableEffect: item.context.sharedContext.energyUsageSettings.fullTranslucency, imageSize: thumbnailDimensions.cgSize)
|
||||
self.placeholderNode.frame = emojiFrame
|
||||
}
|
||||
|
||||
|
||||
@ -90,6 +90,8 @@ public class StickerShimmerEffectNode: ASDisplayNode {
|
||||
self.backdropNode = backdropNode
|
||||
self.insertSubnode(backdropNode, at: 0)
|
||||
|
||||
backdropNode.isHidden = self.effectNode.isHidden
|
||||
|
||||
self.effectNode.layer.compositingFilter = "screenBlendMode"
|
||||
}
|
||||
|
||||
@ -97,7 +99,7 @@ public class StickerShimmerEffectNode: ASDisplayNode {
|
||||
self.effectNode.updateAbsoluteRect(rect, within: containerSize)
|
||||
}
|
||||
|
||||
public func update(backgroundColor: UIColor?, foregroundColor: UIColor, shimmeringColor: UIColor, data: Data?, size: CGSize, imageSize: CGSize = CGSize(width: 512.0, height: 512.0)) {
|
||||
public func update(backgroundColor: UIColor?, foregroundColor: UIColor, shimmeringColor: UIColor, data: Data?, size: CGSize, enableEffect: Bool, imageSize: CGSize = CGSize(width: 512.0, height: 512.0)) {
|
||||
if data == nil {
|
||||
return
|
||||
}
|
||||
@ -112,13 +114,18 @@ public class StickerShimmerEffectNode: ASDisplayNode {
|
||||
self.currentSize = size
|
||||
|
||||
self.backgroundNode.backgroundColor = foregroundColor
|
||||
self.backgroundNode.isHidden = !enableEffect
|
||||
|
||||
self.effectNode.update(backgroundColor: backgroundColor == nil ? .clear : foregroundColor, foregroundColor: shimmeringColor, horizontal: true, effectSize: nil, globalTimeOffset: true, duration: nil)
|
||||
if enableEffect {
|
||||
self.effectNode.update(backgroundColor: backgroundColor == nil ? .clear : foregroundColor, foregroundColor: shimmeringColor, horizontal: true, effectSize: nil, globalTimeOffset: true, duration: nil)
|
||||
}
|
||||
self.effectNode.isHidden = !enableEffect
|
||||
self.backdropNode?.isHidden = !enableEffect
|
||||
|
||||
let bounds = CGRect(origin: CGPoint(), size: size)
|
||||
let image = generateStickerPlaceholderImage(data: data, size: size, imageSize: imageSize, backgroundColor: backgroundColor, foregroundColor: .black)
|
||||
let image = generateStickerPlaceholderImage(data: data, size: size, imageSize: imageSize, backgroundColor: backgroundColor, foregroundColor: enableEffect ? .black : foregroundColor)
|
||||
|
||||
if backgroundColor == nil {
|
||||
if backgroundColor == nil && enableEffect {
|
||||
self.foregroundNode.image = nil
|
||||
|
||||
let maskView: UIImageView
|
||||
|
||||
@ -13,6 +13,7 @@ import TextFormat
|
||||
import AccountContext
|
||||
import ContextUI
|
||||
import StickerPeekUI
|
||||
import AccountContext
|
||||
|
||||
private struct StickerPackPreviewGridEntry: Comparable, Identifiable {
|
||||
let index: Int
|
||||
@ -26,8 +27,8 @@ private struct StickerPackPreviewGridEntry: Comparable, Identifiable {
|
||||
return lhs.index < rhs.index
|
||||
}
|
||||
|
||||
func item(account: Account, interaction: StickerPackPreviewInteraction, theme: PresentationTheme) -> StickerPackPreviewGridItem {
|
||||
return StickerPackPreviewGridItem(account: account, stickerItem: self.stickerItem, interaction: interaction, theme: theme, isPremium: false, isLocked: false, isEmpty: false)
|
||||
func item(context: AccountContext, interaction: StickerPackPreviewInteraction, theme: PresentationTheme) -> StickerPackPreviewGridItem {
|
||||
return StickerPackPreviewGridItem(context: context, stickerItem: self.stickerItem, interaction: interaction, theme: theme, isPremium: false, isLocked: false, isEmpty: false)
|
||||
}
|
||||
}
|
||||
|
||||
@ -36,12 +37,12 @@ private struct StickerPackPreviewGridTransaction {
|
||||
let insertions: [GridNodeInsertItem]
|
||||
let updates: [GridNodeUpdateItem]
|
||||
|
||||
init(previousList: [StickerPackPreviewGridEntry], list: [StickerPackPreviewGridEntry], account: Account, interaction: StickerPackPreviewInteraction, theme: PresentationTheme) {
|
||||
init(previousList: [StickerPackPreviewGridEntry], list: [StickerPackPreviewGridEntry], context: AccountContext, interaction: StickerPackPreviewInteraction, theme: PresentationTheme) {
|
||||
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: previousList, rightList: list)
|
||||
|
||||
self.deletions = deleteIndices
|
||||
self.insertions = indicesAndItems.map { GridNodeInsertItem(index: $0.0, item: $0.1.item(account: account, interaction: interaction, theme: theme), previousIndex: $0.2) }
|
||||
self.updates = updateIndices.map { GridNodeUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, interaction: interaction, theme: theme)) }
|
||||
self.insertions = indicesAndItems.map { GridNodeInsertItem(index: $0.0, item: $0.1.item(context: context, interaction: interaction, theme: theme), previousIndex: $0.2) }
|
||||
self.updates = updateIndices.map { GridNodeUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, interaction: interaction, theme: theme)) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -403,7 +404,7 @@ final class StickerPackPreviewControllerNode: ViewControllerTracingNode, UIScrol
|
||||
self.contentTitleNode.attributedText = stringWithAppliedEntities(info.title, entities: entities, baseColor: self.presentationData.theme.actionSheet.primaryTextColor, linkColor: self.presentationData.theme.actionSheet.controlAccentColor, baseFont: font, linkFont: font, boldFont: font, italicFont: font, boldItalicFont: font, fixedFont: font, blockQuoteFont: font, message: nil)
|
||||
animateIn = true
|
||||
}
|
||||
transaction = StickerPackPreviewGridTransaction(previousList: self.currentItems, list: updatedItems, account: self.context.account, interaction: self.interaction, theme: self.presentationData.theme)
|
||||
transaction = StickerPackPreviewGridTransaction(previousList: self.currentItems, list: updatedItems, context: self.context, interaction: self.interaction, theme: self.presentationData.theme)
|
||||
self.currentItems = updatedItems
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,7 +33,7 @@ final class StickerPackPreviewInteraction {
|
||||
}
|
||||
|
||||
final class StickerPackPreviewGridItem: GridItem {
|
||||
let account: Account
|
||||
let context: AccountContext
|
||||
let stickerItem: StickerPackItem?
|
||||
let interaction: StickerPackPreviewInteraction
|
||||
let theme: PresentationTheme
|
||||
@ -43,8 +43,8 @@ final class StickerPackPreviewGridItem: GridItem {
|
||||
|
||||
let section: GridSection? = nil
|
||||
|
||||
init(account: Account, stickerItem: StickerPackItem?, interaction: StickerPackPreviewInteraction, theme: PresentationTheme, isPremium: Bool, isLocked: Bool, isEmpty: Bool) {
|
||||
self.account = account
|
||||
init(context: AccountContext, stickerItem: StickerPackItem?, interaction: StickerPackPreviewInteraction, theme: PresentationTheme, isPremium: Bool, isLocked: Bool, isEmpty: Bool) {
|
||||
self.context = context
|
||||
self.stickerItem = stickerItem
|
||||
self.interaction = interaction
|
||||
self.theme = theme
|
||||
@ -55,7 +55,7 @@ final class StickerPackPreviewGridItem: GridItem {
|
||||
|
||||
func node(layout: GridNodeLayout, synchronousLoad: Bool) -> GridItemNode {
|
||||
let node = StickerPackPreviewGridItemNode()
|
||||
node.setup(account: self.account, stickerItem: self.stickerItem, interaction: self.interaction, theme: self.theme, isLocked: self.isLocked, isPremium: self.isPremium, isEmpty: self.isEmpty)
|
||||
node.setup(context: self.context, stickerItem: self.stickerItem, interaction: self.interaction, theme: self.theme, isLocked: self.isLocked, isPremium: self.isPremium, isEmpty: self.isEmpty)
|
||||
return node
|
||||
}
|
||||
|
||||
@ -64,14 +64,14 @@ final class StickerPackPreviewGridItem: GridItem {
|
||||
assertionFailure()
|
||||
return
|
||||
}
|
||||
node.setup(account: self.account, stickerItem: self.stickerItem, interaction: self.interaction, theme: self.theme, isLocked: self.isLocked, isPremium: self.isPremium, isEmpty: self.isEmpty)
|
||||
node.setup(context: self.context, stickerItem: self.stickerItem, interaction: self.interaction, theme: self.theme, isLocked: self.isLocked, isPremium: self.isPremium, isEmpty: self.isEmpty)
|
||||
}
|
||||
}
|
||||
|
||||
private let textFont = Font.regular(20.0)
|
||||
|
||||
final class StickerPackPreviewGridItemNode: GridItemNode {
|
||||
private var currentState: (Account, StickerPackItem?)?
|
||||
private var currentState: (AccountContext, StickerPackItem?)?
|
||||
private var isLocked: Bool?
|
||||
private var isPremium: Bool?
|
||||
private var isEmpty: Bool?
|
||||
@ -173,11 +173,11 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
|
||||
}
|
||||
|
||||
private var setupTimestamp: Double?
|
||||
func setup(account: Account, stickerItem: StickerPackItem?, interaction: StickerPackPreviewInteraction, theme: PresentationTheme, isLocked: Bool, isPremium: Bool, isEmpty: Bool) {
|
||||
func setup(context: AccountContext, stickerItem: StickerPackItem?, interaction: StickerPackPreviewInteraction, theme: PresentationTheme, isLocked: Bool, isPremium: Bool, isEmpty: Bool) {
|
||||
self.interaction = interaction
|
||||
self.theme = theme
|
||||
|
||||
if self.currentState == nil || self.currentState!.0 !== account || self.currentState!.1 != stickerItem || self.isLocked != isLocked || self.isPremium != isPremium || self.isEmpty != isEmpty {
|
||||
if self.currentState == nil || self.currentState!.0 !== context || self.currentState!.1 != stickerItem || self.isLocked != isLocked || self.isPremium != isPremium || self.isEmpty != isEmpty {
|
||||
self.isLocked = isLocked
|
||||
|
||||
if isLocked {
|
||||
@ -229,9 +229,9 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
|
||||
if stickerItem.file.isAnimatedSticker || stickerItem.file.isVideoSticker {
|
||||
let dimensions = stickerItem.file.dimensions ?? PixelDimensions(width: 512, height: 512)
|
||||
if stickerItem.file.isVideoSticker {
|
||||
self.imageNode.setSignal(chatMessageSticker(account: account, userLocation: .other, file: stickerItem.file, small: true))
|
||||
self.imageNode.setSignal(chatMessageSticker(account: context.account, userLocation: .other, file: stickerItem.file, small: true))
|
||||
} else {
|
||||
self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: account.postbox, userLocation: .other, file: stickerItem.file, small: false, size: dimensions.cgSize.aspectFitted(CGSize(width: 160.0, height: 160.0))))
|
||||
self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: context.account.postbox, userLocation: .other, file: stickerItem.file, small: false, size: dimensions.cgSize.aspectFitted(CGSize(width: 160.0, height: 160.0))))
|
||||
}
|
||||
|
||||
if self.animationNode == nil {
|
||||
@ -255,14 +255,14 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
|
||||
}
|
||||
}
|
||||
let fittedDimensions = dimensions.cgSize.aspectFitted(CGSize(width: 160.0, height: 160.0))
|
||||
self.animationNode?.setup(source: AnimatedStickerResourceSource(account: account, resource: stickerItem.file.resource, isVideo: stickerItem.file.isVideoSticker), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), playbackMode: .loop, mode: .cached)
|
||||
self.animationNode?.setup(source: AnimatedStickerResourceSource(account: context.account, resource: stickerItem.file.resource, isVideo: stickerItem.file.isVideoSticker), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), playbackMode: .loop, mode: .cached)
|
||||
|
||||
self.animationNode?.visibility = visibility
|
||||
|
||||
self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: account, userLocation: .other, fileReference: stickerPackFileReference(stickerItem.file), resource: stickerItem.file.resource).start())
|
||||
self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: context.account, userLocation: .other, fileReference: stickerPackFileReference(stickerItem.file), resource: stickerItem.file.resource).start())
|
||||
|
||||
if stickerItem.file.isPremiumSticker, let effect = stickerItem.file.videoThumbnails.first {
|
||||
self.effectFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: account, userLocation: .other, fileReference: stickerPackFileReference(stickerItem.file), resource: effect.resource).start())
|
||||
self.effectFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: context.account, userLocation: .other, fileReference: stickerPackFileReference(stickerItem.file), resource: effect.resource).start())
|
||||
}
|
||||
} else {
|
||||
if let animationNode = self.animationNode {
|
||||
@ -270,8 +270,8 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
|
||||
self.animationNode = nil
|
||||
animationNode.removeFromSupernode()
|
||||
}
|
||||
self.imageNode.setSignal(chatMessageSticker(account: account, userLocation: .other, file: stickerItem.file, small: true))
|
||||
self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: account, userLocation: .other, fileReference: stickerPackFileReference(stickerItem.file), resource: chatMessageStickerResource(file: stickerItem.file, small: true)).start())
|
||||
self.imageNode.setSignal(chatMessageSticker(account: context.account, userLocation: .other, file: stickerItem.file, small: true))
|
||||
self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: context.account, userLocation: .other, fileReference: stickerPackFileReference(stickerItem.file), resource: chatMessageStickerResource(file: stickerItem.file, small: true)).start())
|
||||
}
|
||||
} else {
|
||||
if isEmpty {
|
||||
@ -287,7 +287,7 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
|
||||
self.animationNode?.alpha = isLocked ? 0.5 : 1.0
|
||||
self.imageNode.alpha = isLocked ? 0.5 : 1.0
|
||||
|
||||
self.currentState = (account, stickerItem)
|
||||
self.currentState = (context, stickerItem)
|
||||
self.setNeedsLayout()
|
||||
}
|
||||
self.isEmpty = isEmpty
|
||||
@ -322,8 +322,8 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
|
||||
let placeholderFrame = imageFrame
|
||||
self.placeholderNode.frame = imageFrame
|
||||
|
||||
if let theme = self.theme, let (_, stickerItem) = self.currentState, let item = stickerItem {
|
||||
self.placeholderNode.update(backgroundColor: theme.list.itemBlocksBackgroundColor, foregroundColor: theme.list.mediaPlaceholderColor, shimmeringColor: theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.4), data: item.file.immediateThumbnailData, size: placeholderFrame.size)
|
||||
if let theme = self.theme, let (context, stickerItem) = self.currentState, let item = stickerItem {
|
||||
self.placeholderNode.update(backgroundColor: theme.list.itemBlocksBackgroundColor, foregroundColor: theme.list.mediaPlaceholderColor, shimmeringColor: theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.4), data: item.file.immediateThumbnailData, size: placeholderFrame.size, enableEffect: context.sharedContext.energyUsageSettings.fullTranslucency)
|
||||
}
|
||||
|
||||
if let lockBackground = self.lockBackground, let lockTintView = self.lockTintView, let lockIconNode = self.lockIconNode {
|
||||
|
||||
@ -52,7 +52,7 @@ private enum StickerPackPreviewGridEntry: Comparable, Identifiable {
|
||||
func item(context: AccountContext, interaction: StickerPackPreviewInteraction, theme: PresentationTheme, strings: PresentationStrings, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer) -> GridItem {
|
||||
switch self {
|
||||
case let .sticker(_, _, stickerItem, isEmpty, isPremium, isLocked):
|
||||
return StickerPackPreviewGridItem(account: context.account, stickerItem: stickerItem, interaction: interaction, theme: theme, isPremium: isPremium, isLocked: isLocked, isEmpty: isEmpty)
|
||||
return StickerPackPreviewGridItem(context: context, stickerItem: stickerItem, interaction: interaction, theme: theme, isPremium: isPremium, isLocked: isLocked, isEmpty: isEmpty)
|
||||
case let .emojis(_, _, info, items, title, isInstalled):
|
||||
return StickerPackEmojisItem(context: context, animationCache: animationCache, animationRenderer: animationRenderer, interaction: interaction, info: info, items: items, theme: theme, strings: strings, title: title, isInstalled: isInstalled, isEmpty: false)
|
||||
}
|
||||
|
||||
@ -993,6 +993,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[1891070632] = { return Api.contacts.TopPeers.parse_topPeers($0) }
|
||||
dict[-1255369827] = { return Api.contacts.TopPeers.parse_topPeersDisabled($0) }
|
||||
dict[-567906571] = { return Api.contacts.TopPeers.parse_topPeersNotModified($0) }
|
||||
dict[-585598930] = { return Api.help.AppConfig.parse_appConfig($0) }
|
||||
dict[2094949405] = { return Api.help.AppConfig.parse_appConfigNotModified($0) }
|
||||
dict[-860107216] = { return Api.help.AppUpdate.parse_appUpdate($0) }
|
||||
dict[-1000708810] = { return Api.help.AppUpdate.parse_noAppUpdate($0) }
|
||||
dict[-2016381538] = { return Api.help.CountriesList.parse_countriesList($0) }
|
||||
@ -1775,6 +1777,8 @@ public extension Api {
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.contacts.TopPeers:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.help.AppConfig:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.help.AppUpdate:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.help.CountriesList:
|
||||
|
||||
@ -214,6 +214,60 @@ public extension Api.contacts {
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.help {
|
||||
enum AppConfig: TypeConstructorDescription {
|
||||
case appConfig(hash: Int32, config: Api.JSONValue)
|
||||
case appConfigNotModified
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .appConfig(let hash, let config):
|
||||
if boxed {
|
||||
buffer.appendInt32(-585598930)
|
||||
}
|
||||
serializeInt32(hash, buffer: buffer, boxed: false)
|
||||
config.serialize(buffer, true)
|
||||
break
|
||||
case .appConfigNotModified:
|
||||
if boxed {
|
||||
buffer.appendInt32(2094949405)
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .appConfig(let hash, let config):
|
||||
return ("appConfig", [("hash", hash as Any), ("config", config as Any)])
|
||||
case .appConfigNotModified:
|
||||
return ("appConfigNotModified", [])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_appConfig(_ reader: BufferReader) -> AppConfig? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
var _2: Api.JSONValue?
|
||||
if let signature = reader.readInt32() {
|
||||
_2 = Api.parse(reader, signature: signature) as? Api.JSONValue
|
||||
}
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
if _c1 && _c2 {
|
||||
return Api.help.AppConfig.appConfig(hash: _1!, config: _2!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_appConfigNotModified(_ reader: BufferReader) -> AppConfig? {
|
||||
return Api.help.AppConfig.appConfigNotModified
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.help {
|
||||
enum AppUpdate: TypeConstructorDescription {
|
||||
case appUpdate(flags: Int32, id: Int32, version: String, text: String, entities: [Api.MessageEntity], document: Api.Document?, url: String?, sticker: Api.Document?)
|
||||
@ -1274,61 +1328,3 @@ public extension Api.messages {
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.messages {
|
||||
enum AllStickers: TypeConstructorDescription {
|
||||
case allStickers(hash: Int64, sets: [Api.StickerSet])
|
||||
case allStickersNotModified
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .allStickers(let hash, let sets):
|
||||
if boxed {
|
||||
buffer.appendInt32(-843329861)
|
||||
}
|
||||
serializeInt64(hash, buffer: buffer, boxed: false)
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(sets.count))
|
||||
for item in sets {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
break
|
||||
case .allStickersNotModified:
|
||||
if boxed {
|
||||
buffer.appendInt32(-395967805)
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .allStickers(let hash, let sets):
|
||||
return ("allStickers", [("hash", hash as Any), ("sets", sets as Any)])
|
||||
case .allStickersNotModified:
|
||||
return ("allStickersNotModified", [])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_allStickers(_ reader: BufferReader) -> AllStickers? {
|
||||
var _1: Int64?
|
||||
_1 = reader.readInt64()
|
||||
var _2: [Api.StickerSet]?
|
||||
if let _ = reader.readInt32() {
|
||||
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StickerSet.self)
|
||||
}
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
if _c1 && _c2 {
|
||||
return Api.messages.AllStickers.allStickers(hash: _1!, sets: _2!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_allStickersNotModified(_ reader: BufferReader) -> AllStickers? {
|
||||
return Api.messages.AllStickers.allStickersNotModified
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,61 @@
|
||||
public extension Api.messages {
|
||||
enum AllStickers: TypeConstructorDescription {
|
||||
case allStickers(hash: Int64, sets: [Api.StickerSet])
|
||||
case allStickersNotModified
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .allStickers(let hash, let sets):
|
||||
if boxed {
|
||||
buffer.appendInt32(-843329861)
|
||||
}
|
||||
serializeInt64(hash, buffer: buffer, boxed: false)
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(sets.count))
|
||||
for item in sets {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
break
|
||||
case .allStickersNotModified:
|
||||
if boxed {
|
||||
buffer.appendInt32(-395967805)
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .allStickers(let hash, let sets):
|
||||
return ("allStickers", [("hash", hash as Any), ("sets", sets as Any)])
|
||||
case .allStickersNotModified:
|
||||
return ("allStickersNotModified", [])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_allStickers(_ reader: BufferReader) -> AllStickers? {
|
||||
var _1: Int64?
|
||||
_1 = reader.readInt64()
|
||||
var _2: [Api.StickerSet]?
|
||||
if let _ = reader.readInt32() {
|
||||
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StickerSet.self)
|
||||
}
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
if _c1 && _c2 {
|
||||
return Api.messages.AllStickers.allStickers(hash: _1!, sets: _2!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_allStickersNotModified(_ reader: BufferReader) -> AllStickers? {
|
||||
return Api.messages.AllStickers.allStickersNotModified
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.messages {
|
||||
enum ArchivedStickers: TypeConstructorDescription {
|
||||
case archivedStickers(count: Int32, sets: [Api.StickerSetCovered])
|
||||
@ -1346,79 +1404,3 @@ public extension Api.messages {
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.messages {
|
||||
enum HistoryImport: TypeConstructorDescription {
|
||||
case historyImport(id: Int64)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .historyImport(let id):
|
||||
if boxed {
|
||||
buffer.appendInt32(375566091)
|
||||
}
|
||||
serializeInt64(id, buffer: buffer, boxed: false)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .historyImport(let id):
|
||||
return ("historyImport", [("id", id as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_historyImport(_ reader: BufferReader) -> HistoryImport? {
|
||||
var _1: Int64?
|
||||
_1 = reader.readInt64()
|
||||
let _c1 = _1 != nil
|
||||
if _c1 {
|
||||
return Api.messages.HistoryImport.historyImport(id: _1!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.messages {
|
||||
enum HistoryImportParsed: TypeConstructorDescription {
|
||||
case historyImportParsed(flags: Int32, title: String?)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .historyImportParsed(let flags, let title):
|
||||
if boxed {
|
||||
buffer.appendInt32(1578088377)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 2) != 0 {serializeString(title!, buffer: buffer, boxed: false)}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .historyImportParsed(let flags, let title):
|
||||
return ("historyImportParsed", [("flags", flags as Any), ("title", title as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_historyImportParsed(_ reader: BufferReader) -> HistoryImportParsed? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
var _2: String?
|
||||
if Int(_1!) & Int(1 << 2) != 0 {_2 = parseString(reader) }
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = (Int(_1!) & Int(1 << 2) == 0) || _2 != nil
|
||||
if _c1 && _c2 {
|
||||
return Api.messages.HistoryImportParsed.historyImportParsed(flags: _1!, title: _2)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,79 @@
|
||||
public extension Api.messages {
|
||||
enum HistoryImport: TypeConstructorDescription {
|
||||
case historyImport(id: Int64)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .historyImport(let id):
|
||||
if boxed {
|
||||
buffer.appendInt32(375566091)
|
||||
}
|
||||
serializeInt64(id, buffer: buffer, boxed: false)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .historyImport(let id):
|
||||
return ("historyImport", [("id", id as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_historyImport(_ reader: BufferReader) -> HistoryImport? {
|
||||
var _1: Int64?
|
||||
_1 = reader.readInt64()
|
||||
let _c1 = _1 != nil
|
||||
if _c1 {
|
||||
return Api.messages.HistoryImport.historyImport(id: _1!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.messages {
|
||||
enum HistoryImportParsed: TypeConstructorDescription {
|
||||
case historyImportParsed(flags: Int32, title: String?)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .historyImportParsed(let flags, let title):
|
||||
if boxed {
|
||||
buffer.appendInt32(1578088377)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 2) != 0 {serializeString(title!, buffer: buffer, boxed: false)}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .historyImportParsed(let flags, let title):
|
||||
return ("historyImportParsed", [("flags", flags as Any), ("title", title as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_historyImportParsed(_ reader: BufferReader) -> HistoryImportParsed? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
var _2: String?
|
||||
if Int(_1!) & Int(1 << 2) != 0 {_2 = parseString(reader) }
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = (Int(_1!) & Int(1 << 2) == 0) || _2 != nil
|
||||
if _c1 && _c2 {
|
||||
return Api.messages.HistoryImportParsed.historyImportParsed(flags: _1!, title: _2)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.messages {
|
||||
enum InactiveChats: TypeConstructorDescription {
|
||||
case inactiveChats(dates: [Int32], chats: [Api.Chat], users: [Api.User])
|
||||
@ -1342,109 +1418,3 @@ public extension Api.messages {
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.messages {
|
||||
enum TranslatedText: TypeConstructorDescription {
|
||||
case translateResult(result: [Api.TextWithEntities])
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .translateResult(let result):
|
||||
if boxed {
|
||||
buffer.appendInt32(870003448)
|
||||
}
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(result.count))
|
||||
for item in result {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .translateResult(let result):
|
||||
return ("translateResult", [("result", result as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_translateResult(_ reader: BufferReader) -> TranslatedText? {
|
||||
var _1: [Api.TextWithEntities]?
|
||||
if let _ = reader.readInt32() {
|
||||
_1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.TextWithEntities.self)
|
||||
}
|
||||
let _c1 = _1 != nil
|
||||
if _c1 {
|
||||
return Api.messages.TranslatedText.translateResult(result: _1!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.messages {
|
||||
enum VotesList: TypeConstructorDescription {
|
||||
case votesList(flags: Int32, count: Int32, votes: [Api.MessageUserVote], users: [Api.User], nextOffset: String?)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .votesList(let flags, let count, let votes, let users, let nextOffset):
|
||||
if boxed {
|
||||
buffer.appendInt32(136574537)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeInt32(count, buffer: buffer, boxed: false)
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(votes.count))
|
||||
for item in votes {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(users.count))
|
||||
for item in users {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
if Int(flags) & Int(1 << 0) != 0 {serializeString(nextOffset!, buffer: buffer, boxed: false)}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .votesList(let flags, let count, let votes, let users, let nextOffset):
|
||||
return ("votesList", [("flags", flags as Any), ("count", count as Any), ("votes", votes as Any), ("users", users as Any), ("nextOffset", nextOffset as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_votesList(_ reader: BufferReader) -> VotesList? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
var _2: Int32?
|
||||
_2 = reader.readInt32()
|
||||
var _3: [Api.MessageUserVote]?
|
||||
if let _ = reader.readInt32() {
|
||||
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageUserVote.self)
|
||||
}
|
||||
var _4: [Api.User]?
|
||||
if let _ = reader.readInt32() {
|
||||
_4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
|
||||
}
|
||||
var _5: String?
|
||||
if Int(_1!) & Int(1 << 0) != 0 {_5 = parseString(reader) }
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
let _c4 = _4 != nil
|
||||
let _c5 = (Int(_1!) & Int(1 << 0) == 0) || _5 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 {
|
||||
return Api.messages.VotesList.votesList(flags: _1!, count: _2!, votes: _3!, users: _4!, nextOffset: _5)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,109 @@
|
||||
public extension Api.messages {
|
||||
enum TranslatedText: TypeConstructorDescription {
|
||||
case translateResult(result: [Api.TextWithEntities])
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .translateResult(let result):
|
||||
if boxed {
|
||||
buffer.appendInt32(870003448)
|
||||
}
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(result.count))
|
||||
for item in result {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .translateResult(let result):
|
||||
return ("translateResult", [("result", result as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_translateResult(_ reader: BufferReader) -> TranslatedText? {
|
||||
var _1: [Api.TextWithEntities]?
|
||||
if let _ = reader.readInt32() {
|
||||
_1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.TextWithEntities.self)
|
||||
}
|
||||
let _c1 = _1 != nil
|
||||
if _c1 {
|
||||
return Api.messages.TranslatedText.translateResult(result: _1!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.messages {
|
||||
enum VotesList: TypeConstructorDescription {
|
||||
case votesList(flags: Int32, count: Int32, votes: [Api.MessageUserVote], users: [Api.User], nextOffset: String?)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .votesList(let flags, let count, let votes, let users, let nextOffset):
|
||||
if boxed {
|
||||
buffer.appendInt32(136574537)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeInt32(count, buffer: buffer, boxed: false)
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(votes.count))
|
||||
for item in votes {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(users.count))
|
||||
for item in users {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
if Int(flags) & Int(1 << 0) != 0 {serializeString(nextOffset!, buffer: buffer, boxed: false)}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .votesList(let flags, let count, let votes, let users, let nextOffset):
|
||||
return ("votesList", [("flags", flags as Any), ("count", count as Any), ("votes", votes as Any), ("users", users as Any), ("nextOffset", nextOffset as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_votesList(_ reader: BufferReader) -> VotesList? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
var _2: Int32?
|
||||
_2 = reader.readInt32()
|
||||
var _3: [Api.MessageUserVote]?
|
||||
if let _ = reader.readInt32() {
|
||||
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageUserVote.self)
|
||||
}
|
||||
var _4: [Api.User]?
|
||||
if let _ = reader.readInt32() {
|
||||
_4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
|
||||
}
|
||||
var _5: String?
|
||||
if Int(_1!) & Int(1 << 0) != 0 {_5 = parseString(reader) }
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
let _c4 = _4 != nil
|
||||
let _c5 = (Int(_1!) & Int(1 << 0) == 0) || _5 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 {
|
||||
return Api.messages.VotesList.votesList(flags: _1!, count: _2!, votes: _3!, users: _4!, nextOffset: _5)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.payments {
|
||||
enum BankCardData: TypeConstructorDescription {
|
||||
case bankCardData(title: String, openUrls: [Api.BankCardOpenUrl])
|
||||
|
||||
@ -3334,15 +3334,15 @@ public extension Api.functions.help {
|
||||
}
|
||||
}
|
||||
public extension Api.functions.help {
|
||||
static func getAppConfig() -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.JSONValue>) {
|
||||
static func getAppConfig(hash: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.help.AppConfig>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(-1735311088)
|
||||
|
||||
return (FunctionDescription(name: "help.getAppConfig", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.JSONValue? in
|
||||
buffer.appendInt32(1642330196)
|
||||
serializeInt32(hash, buffer: buffer, boxed: false)
|
||||
return (FunctionDescription(name: "help.getAppConfig", parameters: [("hash", String(describing: hash))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.help.AppConfig? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.JSONValue?
|
||||
var result: Api.help.AppConfig?
|
||||
if let signature = reader.readInt32() {
|
||||
result = Api.parse(reader, signature: signature) as? Api.JSONValue
|
||||
result = Api.parse(reader, signature: signature) as? Api.help.AppConfig
|
||||
}
|
||||
return result
|
||||
})
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import Postbox
|
||||
|
||||
private func currentAppConfiguration(transaction: Transaction) -> AppConfiguration {
|
||||
func currentAppConfiguration(transaction: Transaction) -> AppConfiguration {
|
||||
if let entry = transaction.getPreferencesEntry(key: PreferencesKeys.appConfiguration)?.get(AppConfiguration.self) {
|
||||
return entry
|
||||
} else {
|
||||
|
||||
@ -5,22 +5,35 @@ import TelegramApi
|
||||
import MtProtoKit
|
||||
|
||||
func updateAppConfigurationOnce(postbox: Postbox, network: Network) -> Signal<Void, NoError> {
|
||||
return network.request(Api.functions.help.getAppConfig())
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<Api.JSONValue?, NoError> in
|
||||
return .single(nil)
|
||||
return postbox.transaction { transaction -> Int32 in
|
||||
return currentAppConfiguration(transaction: transaction).hash
|
||||
}
|
||||
|> mapToSignal { result -> Signal<Void, NoError> in
|
||||
guard let result = result else {
|
||||
return .complete()
|
||||
|> mapToSignal { hash -> Signal<Void, NoError> in
|
||||
return network.request(Api.functions.help.getAppConfig(hash: hash))
|
||||
|> map { result -> (data: Api.JSONValue, hash: Int32)? in
|
||||
switch result {
|
||||
case let .appConfig(updatedHash, config):
|
||||
return (config, updatedHash)
|
||||
case .appConfigNotModified:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return postbox.transaction { transaction -> Void in
|
||||
if let data = JSON(apiJson: result) {
|
||||
updateAppConfiguration(transaction: transaction, { configuration -> AppConfiguration in
|
||||
var configuration = configuration
|
||||
configuration.data = data
|
||||
return configuration
|
||||
})
|
||||
|> `catch` { _ -> Signal<(data: Api.JSONValue, hash: Int32)?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|> mapToSignal { result -> Signal<Void, NoError> in
|
||||
guard let result = result else {
|
||||
return .complete()
|
||||
}
|
||||
return postbox.transaction { transaction -> Void in
|
||||
if let data = JSON(apiJson: result.data) {
|
||||
updateAppConfiguration(transaction: transaction, { configuration -> AppConfiguration in
|
||||
var configuration = configuration
|
||||
configuration.data = data
|
||||
configuration.hash = result.hash
|
||||
return configuration
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,15 +15,21 @@ func addSynchronizeRecentlyUsedMediaOperation(transaction: Transaction, category
|
||||
}
|
||||
let peerId = PeerId(0)
|
||||
|
||||
var topOperation: (SynchronizeRecentlyUsedMediaOperation, Int32)?
|
||||
var removeOperations: [(SynchronizeRecentlyUsedMediaOperation, Int32)] = []
|
||||
transaction.operationLogEnumerateEntries(peerId: peerId, tag: tag, { entry in
|
||||
if let operation = entry.contents as? SynchronizeRecentlyUsedMediaOperation {
|
||||
topOperation = (operation, entry.tagLocalIndex)
|
||||
if case .sync = operation.content {
|
||||
removeOperations.append((operation, entry.tagLocalIndex))
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
if let (topOperation, topLocalIndex) = topOperation, case .sync = topOperation.content {
|
||||
for (_, topLocalIndex) in removeOperations {
|
||||
let _ = transaction.operationLogRemoveEntry(peerId: peerId, tag: tag, tagLocalIndex: topLocalIndex)
|
||||
}
|
||||
|
||||
|
||||
@ -3,24 +3,28 @@ import Postbox
|
||||
|
||||
public struct AppConfiguration: Codable, Equatable {
|
||||
public var data: JSON?
|
||||
public var hash: Int32
|
||||
|
||||
public static var defaultValue: AppConfiguration {
|
||||
return AppConfiguration(data: nil)
|
||||
return AppConfiguration(data: nil, hash: 0)
|
||||
}
|
||||
|
||||
init(data: JSON?) {
|
||||
init(data: JSON?, hash: Int32) {
|
||||
self.data = data
|
||||
self.hash = hash
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
self.data = try container.decodeIfPresent(JSON.self, forKey: "data")
|
||||
self.hash = (try container.decodeIfPresent(Int32.self, forKey: "storedHash")) ?? 0
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
try container.encodeIfPresent(self.data, forKey: "data")
|
||||
try container.encode(self.hash, forKey: "storedHash")
|
||||
}
|
||||
}
|
||||
|
||||
@ -289,7 +289,7 @@ public func currentPresentationDataAndSettings(accountManager: AccountManager<Te
|
||||
contactSynchronizationSettings: contactSynchronizationSettings
|
||||
)
|
||||
}
|
||||
|> deliverOn(Queue.mainQueue())
|
||||
|> deliverOn(Queue(name: "PresentationData-Load", qos: .userInteractive))
|
||||
|> map { internalData -> InitialPresentationDataAndSettings in
|
||||
let localizationSettings: LocalizationSettings?
|
||||
if let current = internalData.localizationSettings?.get(LocalizationSettings.self) {
|
||||
|
||||
@ -192,6 +192,7 @@ public final class ChatControllerInteraction {
|
||||
public var updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?
|
||||
public let presentationContext: ChatPresentationContext
|
||||
public var playNextOutgoingGift: Bool = false
|
||||
public var enableFullTranslucency: Bool = true
|
||||
|
||||
public init(
|
||||
openMessage: @escaping (Message, ChatControllerInteractionOpenMessageMode) -> Bool,
|
||||
|
||||
@ -1342,7 +1342,7 @@ private final class GroupEmbeddedView: UIScrollView, UIScrollViewDelegate, Pager
|
||||
let itemFrame = itemLayout.frame(at: index)
|
||||
itemLayer.frame = itemFrame
|
||||
|
||||
itemLayer.isVisibleForAnimations = true
|
||||
itemLayer.isVisibleForAnimations = context.sharedContext.energyUsageSettings.loopEmoji
|
||||
}
|
||||
}
|
||||
|
||||
@ -2160,7 +2160,7 @@ private final class EmptySearchResultsView: UIView {
|
||||
animationCache: context.animationCache,
|
||||
animationRenderer: context.animationRenderer,
|
||||
content: .animation(content: .file(file: file), size: CGSize(width: 32.0, height: 32.0), placeholderColor: titleColor, themeColor: nil, loopMode: .forever),
|
||||
isVisibleForAnimations: true,
|
||||
isVisibleForAnimations: context.sharedContext.energyUsageSettings.loopEmoji,
|
||||
action: nil
|
||||
)),
|
||||
environment: {},
|
||||
@ -3650,7 +3650,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
override init(frame: CGRect) {
|
||||
self.backgroundView = BlurredBackgroundView(color: nil)
|
||||
|
||||
if ProcessInfo.processInfo.processorCount > 2 {
|
||||
if ProcessInfo.processInfo.processorCount > 4 {
|
||||
self.shimmerHostView = PortalSourceView()
|
||||
self.standaloneShimmerEffect = StandaloneShimmerEffect()
|
||||
} else {
|
||||
@ -5795,7 +5795,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
placeholderView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
|
||||
}
|
||||
|
||||
itemLayer.isVisibleForAnimations = keyboardChildEnvironment.isContentInFocus
|
||||
itemLayer.isVisibleForAnimations = keyboardChildEnvironment.isContentInFocus && component.context.sharedContext.energyUsageSettings.loopEmoji
|
||||
}
|
||||
}
|
||||
if itemGroup.fillWithLoadingPlaceholders {
|
||||
|
||||
@ -167,7 +167,7 @@ final class EntityKeyboardAnimationTopPanelComponent: Component {
|
||||
itemLayer.layerTintColor = component.theme.list.itemAccentColor.cgColor
|
||||
}
|
||||
|
||||
itemLayer.isVisibleForAnimations = itemEnvironment.isContentInFocus
|
||||
itemLayer.isVisibleForAnimations = itemEnvironment.isContentInFocus && component.context.sharedContext.energyUsageSettings.loopEmoji
|
||||
}
|
||||
|
||||
if itemEnvironment.isExpanded {
|
||||
|
||||
@ -93,6 +93,8 @@ public final class TextNodeWithEntities {
|
||||
public let textNode: TextNode
|
||||
private var inlineStickerItemLayers: [InlineStickerItemLayer.Key: InlineStickerItemLayer] = [:]
|
||||
|
||||
private var enableLooping: Bool = true
|
||||
|
||||
public var visibilityRect: CGRect? {
|
||||
didSet {
|
||||
if !self.inlineStickerItemLayers.isEmpty && oldValue != self.visibilityRect {
|
||||
@ -107,7 +109,7 @@ public final class TextNodeWithEntities {
|
||||
} else {
|
||||
isItemVisible = false
|
||||
}
|
||||
itemLayer.isVisibleForAnimations = isItemVisible
|
||||
itemLayer.isVisibleForAnimations = self.enableLooping && isItemVisible
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -218,6 +220,8 @@ public final class TextNodeWithEntities {
|
||||
}
|
||||
|
||||
private func updateInlineStickers(context: AccountContext, cache: AnimationCache, renderer: MultiAnimationRenderer, textLayout: TextNodeLayout?, placeholderColor: UIColor, attemptSynchronousLoad: Bool) {
|
||||
self.enableLooping = context.sharedContext.energyUsageSettings.loopEmoji
|
||||
|
||||
var nextIndexById: [Int64: Int] = [:]
|
||||
var validIds: [InlineStickerItemLayer.Key] = []
|
||||
|
||||
@ -250,7 +254,7 @@ public final class TextNodeWithEntities {
|
||||
self.inlineStickerItemLayers[id] = itemLayer
|
||||
self.textNode.layer.addSublayer(itemLayer)
|
||||
|
||||
itemLayer.isVisibleForAnimations = self.isItemVisible(itemRect: itemFrame)
|
||||
itemLayer.isVisibleForAnimations = self.enableLooping && self.isItemVisible(itemRect: itemFrame)
|
||||
}
|
||||
|
||||
itemLayer.frame = itemFrame
|
||||
@ -284,6 +288,8 @@ public class ImmediateTextNodeWithEntities: TextNode {
|
||||
public var cutout: TextNodeCutout?
|
||||
public var displaySpoilers = false
|
||||
|
||||
private var enableLooping: Bool = true
|
||||
|
||||
public var arguments: TextNodeWithEntities.Arguments?
|
||||
|
||||
private var inlineStickerItemLayers: [InlineStickerItemLayer.Key: InlineStickerItemLayer] = [:]
|
||||
@ -293,7 +299,7 @@ public class ImmediateTextNodeWithEntities: TextNode {
|
||||
if !self.inlineStickerItemLayers.isEmpty && oldValue != self.visibility {
|
||||
for (_, itemLayer) in self.inlineStickerItemLayers {
|
||||
let isItemVisible: Bool = self.visibility
|
||||
itemLayer.isVisibleForAnimations = isItemVisible
|
||||
itemLayer.isVisibleForAnimations = self.enableLooping && isItemVisible
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -385,6 +391,8 @@ public class ImmediateTextNodeWithEntities: TextNode {
|
||||
}
|
||||
|
||||
private func updateInlineStickers(context: AccountContext, cache: AnimationCache, renderer: MultiAnimationRenderer, textLayout: TextNodeLayout?, placeholderColor: UIColor) {
|
||||
self.enableLooping = context.sharedContext.energyUsageSettings.loopEmoji
|
||||
|
||||
var nextIndexById: [Int64: Int] = [:]
|
||||
var validIds: [InlineStickerItemLayer.Key] = []
|
||||
|
||||
@ -415,7 +423,7 @@ public class ImmediateTextNodeWithEntities: TextNode {
|
||||
self.inlineStickerItemLayers[id] = itemLayer
|
||||
self.layer.addSublayer(itemLayer)
|
||||
|
||||
itemLayer.isVisibleForAnimations = self.visibility
|
||||
itemLayer.isVisibleForAnimations = self.enableLooping && self.visibility
|
||||
}
|
||||
|
||||
itemLayer.frame = itemFrame
|
||||
|
||||
@ -1646,6 +1646,9 @@ private func extractAccountManagerState(records: AccountRecordsView<TelegramAcco
|
||||
extendNow = true
|
||||
}
|
||||
}
|
||||
if !sharedApplicationContext.sharedContext.energyUsageSettings.extendBackgroundWork {
|
||||
extendNow = false
|
||||
}
|
||||
sharedApplicationContext.wakeupManager.allowBackgroundTimeExtension(timeout: 2.0, extendNow: extendNow)
|
||||
})
|
||||
|
||||
|
||||
@ -598,7 +598,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
self.automaticMediaDownloadSettings = context.sharedContext.currentAutomaticMediaDownloadSettings.with { $0 }
|
||||
self.automaticMediaDownloadSettings = context.sharedContext.currentAutomaticMediaDownloadSettings
|
||||
|
||||
self.stickerSettings = ChatInterfaceStickerSettings(loopAnimatedStickers: false)
|
||||
|
||||
@ -4281,6 +4281,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}, scrollToMessageId: { [weak self] index in
|
||||
self?.chatDisplayNode.historyNode.scrollToMessage(index: index)
|
||||
}, automaticMediaDownloadSettings: self.automaticMediaDownloadSettings, pollActionState: ChatInterfacePollActionState(), stickerSettings: self.stickerSettings, presentationContext: ChatPresentationContext(context: context, backgroundNode: self.chatBackgroundNode))
|
||||
controllerInteraction.enableFullTranslucency = context.sharedContext.energyUsageSettings.fullTranslucency
|
||||
|
||||
self.controllerInteraction = controllerInteraction
|
||||
|
||||
|
||||
@ -249,7 +249,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
loadingPlaceholderNode.setup(self.historyNode, updating: true)
|
||||
}
|
||||
} else {
|
||||
loadingPlaceholderNode = ChatLoadingPlaceholderNode(theme: self.chatPresentationInterfaceState.theme, chatWallpaper: self.chatPresentationInterfaceState.chatWallpaper, bubbleCorners: self.chatPresentationInterfaceState.bubbleCorners, backgroundNode: self.backgroundNode)
|
||||
loadingPlaceholderNode = ChatLoadingPlaceholderNode(context: self.context, theme: self.chatPresentationInterfaceState.theme, chatWallpaper: self.chatPresentationInterfaceState.chatWallpaper, bubbleCorners: self.chatPresentationInterfaceState.bubbleCorners, backgroundNode: self.backgroundNode)
|
||||
loadingPlaceholderNode.updatePresentationInterfaceState(self.chatPresentationInterfaceState)
|
||||
self.backgroundNode.supernode?.insertSubnode(loadingPlaceholderNode, aboveSubnode: self.backgroundNode)
|
||||
|
||||
@ -447,7 +447,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
onTransitionEventImpl?(transition)
|
||||
})
|
||||
|
||||
self.loadingNode = ChatLoadingNode(theme: self.chatPresentationInterfaceState.theme, chatWallpaper: self.chatPresentationInterfaceState.chatWallpaper, bubbleCorners: self.chatPresentationInterfaceState.bubbleCorners)
|
||||
self.loadingNode = ChatLoadingNode(context: context, theme: self.chatPresentationInterfaceState.theme, chatWallpaper: self.chatPresentationInterfaceState.chatWallpaper, bubbleCorners: self.chatPresentationInterfaceState.bubbleCorners)
|
||||
|
||||
self.inputPanelContainerNode = ChatInputPanelContainer()
|
||||
self.inputPanelOverlayNode = SparseNode()
|
||||
@ -491,7 +491,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
if (strongSelf.context.sharedContext.currentPresentationData.with({ $0 })).reduceMotion {
|
||||
return
|
||||
}
|
||||
if DeviceMetrics.performance.isGraphicallyCapable {
|
||||
if strongSelf.context.sharedContext.energyUsageSettings.fullTranslucency {
|
||||
strongSelf.backgroundNode.animateEvent(transition: transition, extendAnimation: false)
|
||||
}
|
||||
}
|
||||
@ -2216,7 +2216,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
if (self.context.sharedContext.currentPresentationData.with({ $0 })).reduceMotion {
|
||||
return
|
||||
}
|
||||
if DeviceMetrics.performance.isGraphicallyCapable {
|
||||
if self.context.sharedContext.energyUsageSettings.fullTranslucency {
|
||||
self.backgroundNode.animateEvent(transition: transition, extendAnimation: false)
|
||||
}
|
||||
}
|
||||
|
||||
@ -960,7 +960,7 @@ final class ChatEmptyNode: ASDisplayNode {
|
||||
self.currentTheme = interfaceState.theme
|
||||
self.currentStrings = interfaceState.strings
|
||||
|
||||
self.backgroundNode.updateColor(color: selectDateFillStaticColor(theme: interfaceState.theme, wallpaper: interfaceState.chatWallpaper), enableBlur: dateFillNeedsBlur(theme: interfaceState.theme, wallpaper: interfaceState.chatWallpaper), transition: .immediate)
|
||||
self.backgroundNode.updateColor(color: selectDateFillStaticColor(theme: interfaceState.theme, wallpaper: interfaceState.chatWallpaper), enableBlur: self.context.sharedContext.energyUsageSettings.fullTranslucency && dateFillNeedsBlur(theme: interfaceState.theme, wallpaper: interfaceState.chatWallpaper), transition: .immediate)
|
||||
}
|
||||
|
||||
var isScheduledMessages = false
|
||||
|
||||
@ -8,14 +8,15 @@ import ActivityIndicator
|
||||
import WallpaperBackgroundNode
|
||||
import ShimmerEffect
|
||||
import ChatPresentationInterfaceState
|
||||
import AccountContext
|
||||
|
||||
final class ChatLoadingNode: ASDisplayNode {
|
||||
private let backgroundNode: NavigationBackgroundNode
|
||||
private let activityIndicator: ActivityIndicator
|
||||
private let offset: CGPoint
|
||||
|
||||
init(theme: PresentationTheme, chatWallpaper: TelegramWallpaper, bubbleCorners: PresentationChatBubbleCorners) {
|
||||
self.backgroundNode = NavigationBackgroundNode(color: selectDateFillStaticColor(theme: theme, wallpaper: chatWallpaper), enableBlur: dateFillNeedsBlur(theme: theme, wallpaper: chatWallpaper))
|
||||
init(context: AccountContext, theme: PresentationTheme, chatWallpaper: TelegramWallpaper, bubbleCorners: PresentationChatBubbleCorners) {
|
||||
self.backgroundNode = NavigationBackgroundNode(color: selectDateFillStaticColor(theme: theme, wallpaper: chatWallpaper), enableBlur: context.sharedContext.energyUsageSettings.fullTranslucency && dateFillNeedsBlur(theme: theme, wallpaper: chatWallpaper))
|
||||
|
||||
let serviceColor = serviceMessageColorComponents(theme: theme, wallpaper: chatWallpaper)
|
||||
self.activityIndicator = ActivityIndicator(type: .custom(serviceColor.primaryText, 22.0, 2.0, false), speed: .regular)
|
||||
@ -134,6 +135,8 @@ final class ChatLoadingPlaceholderMessageContainer {
|
||||
final class ChatLoadingPlaceholderNode: ASDisplayNode {
|
||||
private weak var backgroundNode: WallpaperBackgroundNode?
|
||||
|
||||
private let context: AccountContext
|
||||
|
||||
private let maskNode: ASDisplayNode
|
||||
private let borderMaskNode: ASDisplayNode
|
||||
|
||||
@ -151,7 +154,8 @@ final class ChatLoadingPlaceholderNode: ASDisplayNode {
|
||||
|
||||
private var validLayout: (CGSize, UIEdgeInsets)?
|
||||
|
||||
init(theme: PresentationTheme, chatWallpaper: TelegramWallpaper, bubbleCorners: PresentationChatBubbleCorners, backgroundNode: WallpaperBackgroundNode) {
|
||||
init(context: AccountContext, theme: PresentationTheme, chatWallpaper: TelegramWallpaper, bubbleCorners: PresentationChatBubbleCorners, backgroundNode: WallpaperBackgroundNode) {
|
||||
self.context = context
|
||||
self.backgroundNode = backgroundNode
|
||||
|
||||
self.maskNode = ASDisplayNode()
|
||||
@ -185,13 +189,13 @@ final class ChatLoadingPlaceholderNode: ASDisplayNode {
|
||||
self.addSubnode(self.containerNode)
|
||||
self.containerNode.addSubnode(self.backgroundColorNode)
|
||||
|
||||
if DeviceMetrics.performance.isGraphicallyCapable {
|
||||
if context.sharedContext.energyUsageSettings.fullTranslucency {
|
||||
self.containerNode.addSubnode(self.effectNode)
|
||||
}
|
||||
|
||||
self.addSubnode(self.borderNode)
|
||||
|
||||
if DeviceMetrics.performance.isGraphicallyCapable {
|
||||
if context.sharedContext.energyUsageSettings.fullTranslucency {
|
||||
self.borderNode.addSubnode(self.borderEffectNode)
|
||||
}
|
||||
}
|
||||
@ -202,7 +206,7 @@ final class ChatLoadingPlaceholderNode: ASDisplayNode {
|
||||
self.containerNode.view.mask = self.maskNode.view
|
||||
self.borderNode.view.mask = self.borderMaskNode.view
|
||||
|
||||
if DeviceMetrics.performance.isGraphicallyCapable {
|
||||
if self.context.sharedContext.energyUsageSettings.fullTranslucency {
|
||||
self.backgroundNode?.updateIsLooping(true)
|
||||
}
|
||||
}
|
||||
|
||||
@ -383,7 +383,7 @@ final class ChatMediaInputStickerGridItemNode: GridItemNode {
|
||||
}
|
||||
|
||||
let theme = item.theme
|
||||
placeholderNode.update(backgroundColor: theme.chat.inputMediaPanel.stickersBackgroundColor.withAlphaComponent(1.0), foregroundColor: theme.chat.inputMediaPanel.stickersSectionTextColor.blitOver(theme.chat.inputMediaPanel.stickersBackgroundColor, alpha: 0.15), shimmeringColor: theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.3), data: item.stickerItem.file.immediateThumbnailData, size: placeholderFrame.size)
|
||||
placeholderNode.update(backgroundColor: theme.chat.inputMediaPanel.stickersBackgroundColor.withAlphaComponent(1.0), foregroundColor: theme.chat.inputMediaPanel.stickersSectionTextColor.blitOver(theme.chat.inputMediaPanel.stickersBackgroundColor, alpha: 0.15), shimmeringColor: theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.3), data: item.stickerItem.file.immediateThumbnailData, size: placeholderFrame.size, enableEffect: true)
|
||||
}
|
||||
|
||||
if let lockBackground = self.lockBackground, let lockTintView = self.lockTintView, let lockIconNode = self.lockIconNode {
|
||||
|
||||
@ -269,7 +269,7 @@ final class ChatMediaInputStickerPackItemNode: ListViewItemNode {
|
||||
immediateThumbnailData = data
|
||||
}
|
||||
|
||||
placeholderNode.update(backgroundColor: nil, foregroundColor: theme.chat.inputMediaPanel.stickersSectionTextColor.blitOver(theme.chat.inputPanel.panelBackgroundColor, alpha: 0.4), shimmeringColor: theme.chat.inputMediaPanel.panelHighlightedIconBackgroundColor.withMultipliedAlpha(0.2), data: immediateThumbnailData, size: boundingImageSize, imageSize: imageSize.cgSize)
|
||||
placeholderNode.update(backgroundColor: nil, foregroundColor: theme.chat.inputMediaPanel.stickersSectionTextColor.blitOver(theme.chat.inputPanel.panelBackgroundColor, alpha: 0.4), shimmeringColor: theme.chat.inputMediaPanel.panelHighlightedIconBackgroundColor.withMultipliedAlpha(0.2), data: immediateThumbnailData, size: boundingImageSize, enableEffect: true, imageSize: imageSize.cgSize)
|
||||
}
|
||||
|
||||
self.containerNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: expandedBoundingSize)
|
||||
|
||||
@ -181,7 +181,7 @@ private final class ChatMessageActionButtonNode: ASDisplayNode {
|
||||
|
||||
animation.animator.updateFrame(layer: node.backgroundBlurNode.layer, frame: CGRect(origin: CGPoint(), size: CGSize(width: max(0.0, width), height: 42.0)), completion: nil)
|
||||
node.backgroundBlurNode.update(size: node.backgroundBlurNode.bounds.size, cornerRadius: 0.0, animator: animation.animator)
|
||||
node.backgroundBlurNode.updateColor(color: selectDateFillStaticColor(theme: theme.theme, wallpaper: theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: theme.theme, wallpaper: theme.wallpaper), transition: .immediate)
|
||||
node.backgroundBlurNode.updateColor(color: selectDateFillStaticColor(theme: theme.theme, wallpaper: theme.wallpaper), enableBlur: context.sharedContext.energyUsageSettings.fullTranslucency && dateFillNeedsBlur(theme: theme.theme, wallpaper: theme.wallpaper), transition: .immediate)
|
||||
|
||||
if backgroundNode?.hasExtraBubbleBackground() == true {
|
||||
if node.backgroundContent == nil, let backgroundContent = backgroundNode?.makeBubbleBackground(for: .free) {
|
||||
|
||||
@ -125,7 +125,7 @@ class ChatMessageShareButton: HighlightableButtonNode {
|
||||
} else {
|
||||
updatedIconImage = PresentationResourcesChat.chatFreeShareButtonIcon(presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper)
|
||||
}
|
||||
self.backgroundNode.updateColor(color: selectDateFillStaticColor(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper), transition: .immediate)
|
||||
self.backgroundNode.updateColor(color: selectDateFillStaticColor(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper), enableBlur: controllerInteraction.enableFullTranslucency && dateFillNeedsBlur(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper), transition: .immediate)
|
||||
self.iconNode.image = updatedIconImage
|
||||
self.iconOffset = updatedIconOffset
|
||||
}
|
||||
@ -1444,7 +1444,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
||||
|
||||
let foregroundColor = bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.stickerPlaceholderColor, wallpaper: item.presentationData.theme.wallpaper)
|
||||
let shimmeringColor = bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.stickerPlaceholderShimmerColor, wallpaper: item.presentationData.theme.wallpaper)
|
||||
strongSelf.placeholderNode.update(backgroundColor: nil, foregroundColor: foregroundColor, shimmeringColor: shimmeringColor, data: immediateThumbnailData, size: animationNodeFrame.size, imageSize: file.dimensions?.cgSize ?? CGSize(width: 512.0, height: 512.0))
|
||||
strongSelf.placeholderNode.update(backgroundColor: nil, foregroundColor: foregroundColor, shimmeringColor: shimmeringColor, data: immediateThumbnailData, size: animationNodeFrame.size, enableEffect: item.context.sharedContext.energyUsageSettings.fullTranslucency, imageSize: file.dimensions?.cgSize ?? CGSize(width: 512.0, height: 512.0))
|
||||
strongSelf.placeholderNode.frame = animationNodeFrame
|
||||
}
|
||||
|
||||
@ -1488,9 +1488,9 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
||||
|
||||
if needsReplyBackground {
|
||||
if let replyBackgroundNode = strongSelf.replyBackgroundNode {
|
||||
replyBackgroundNode.updateColor(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), transition: .immediate)
|
||||
replyBackgroundNode.updateColor(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: item.controllerInteraction.enableFullTranslucency && dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), transition: .immediate)
|
||||
} else {
|
||||
let replyBackgroundNode = NavigationBackgroundNode(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper))
|
||||
let replyBackgroundNode = NavigationBackgroundNode(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: item.controllerInteraction.enableFullTranslucency && dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper))
|
||||
strongSelf.replyBackgroundNode = replyBackgroundNode
|
||||
strongSelf.contextSourceNode.contentNode.addSubnode(replyBackgroundNode)
|
||||
}
|
||||
@ -2442,7 +2442,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
||||
}
|
||||
|
||||
if let item = self.item, self.swipeToReplyNode == nil {
|
||||
let swipeToReplyNode = ChatMessageSwipeToReplyNode(fillColor: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), foregroundColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonForegroundColor, wallpaper: item.presentationData.theme.wallpaper), backgroundNode: item.controllerInteraction.presentationContext.backgroundNode, action: ChatMessageSwipeToReplyNode.Action(self.currentSwipeAction))
|
||||
let swipeToReplyNode = ChatMessageSwipeToReplyNode(fillColor: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: item.controllerInteraction.enableFullTranslucency && dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), foregroundColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonForegroundColor, wallpaper: item.presentationData.theme.wallpaper), backgroundNode: item.controllerInteraction.presentationContext.backgroundNode, action: ChatMessageSwipeToReplyNode.Action(self.currentSwipeAction))
|
||||
self.swipeToReplyNode = swipeToReplyNode
|
||||
self.insertSubnode(swipeToReplyNode, at: 0)
|
||||
}
|
||||
|
||||
@ -4240,7 +4240,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
||||
}
|
||||
|
||||
if let item = self.item, self.swipeToReplyNode == nil {
|
||||
let swipeToReplyNode = ChatMessageSwipeToReplyNode(fillColor: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), foregroundColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonForegroundColor, wallpaper: item.presentationData.theme.wallpaper), backgroundNode: item.controllerInteraction.presentationContext.backgroundNode, action: ChatMessageSwipeToReplyNode.Action(self.currentSwipeAction))
|
||||
let swipeToReplyNode = ChatMessageSwipeToReplyNode(fillColor: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: item.controllerInteraction.enableFullTranslucency && dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), foregroundColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonForegroundColor, wallpaper: item.presentationData.theme.wallpaper), backgroundNode: item.controllerInteraction.presentationContext.backgroundNode, action: ChatMessageSwipeToReplyNode.Action(self.currentSwipeAction))
|
||||
self.swipeToReplyNode = swipeToReplyNode
|
||||
self.insertSubnode(swipeToReplyNode, at: 0)
|
||||
}
|
||||
|
||||
@ -474,7 +474,7 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
let serviceColor = serviceMessageColorComponents(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper)
|
||||
dateColor = serviceColor.primaryText
|
||||
|
||||
blurredBackgroundColor = (selectDateFillStaticColor(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper), dateFillNeedsBlur(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper))
|
||||
blurredBackgroundColor = (selectDateFillStaticColor(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper), arguments.context.sharedContext.energyUsageSettings.fullTranslucency && dateFillNeedsBlur(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper))
|
||||
leftInset = 0.0
|
||||
loadedCheckFullImage = PresentationResourcesChat.chatFreeFullCheck(arguments.presentationData.theme.theme, size: checkSize, isDefaultWallpaper: isDefaultWallpaper)
|
||||
loadedCheckPartialImage = PresentationResourcesChat.chatFreePartialCheck(arguments.presentationData.theme.theme, size: checkSize, isDefaultWallpaper: isDefaultWallpaper)
|
||||
@ -492,7 +492,7 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
let serviceColor = serviceMessageColorComponents(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper)
|
||||
dateColor = serviceColor.primaryText
|
||||
outgoingStatus = status
|
||||
blurredBackgroundColor = (selectDateFillStaticColor(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper), dateFillNeedsBlur(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper))
|
||||
blurredBackgroundColor = (selectDateFillStaticColor(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper), arguments.context.sharedContext.energyUsageSettings.fullTranslucency && dateFillNeedsBlur(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper))
|
||||
leftInset = 0.0
|
||||
loadedCheckFullImage = PresentationResourcesChat.chatFreeFullCheck(arguments.presentationData.theme.theme, size: checkSize, isDefaultWallpaper: isDefaultWallpaper)
|
||||
loadedCheckPartialImage = PresentationResourcesChat.chatFreePartialCheck(arguments.presentationData.theme.theme, size: checkSize, isDefaultWallpaper: isDefaultWallpaper)
|
||||
|
||||
@ -200,7 +200,9 @@ final class ChatMessageDateHeaderNode: ListViewItemHeaderNode {
|
||||
|
||||
let graphics = PresentationResourcesChat.principalGraphics(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper, bubbleCorners: presentationData.chatBubbleCorners)
|
||||
|
||||
self.backgroundNode.updateColor(color: selectDateFillStaticColor(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper), transition: .immediate)
|
||||
let fullTranslucency: Bool = controllerInteraction?.enableFullTranslucency ?? true
|
||||
|
||||
self.backgroundNode.updateColor(color: selectDateFillStaticColor(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper), enableBlur: fullTranslucency && dateFillNeedsBlur(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper), transition: .immediate)
|
||||
self.stickBackgroundNode.image = graphics.dateFloatingBackground
|
||||
self.stickBackgroundNode.alpha = 0.0
|
||||
|
||||
@ -236,8 +238,10 @@ final class ChatMessageDateHeaderNode: ListViewItemHeaderNode {
|
||||
self.presentationData = presentationData
|
||||
|
||||
let graphics = PresentationResourcesChat.principalGraphics(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper, bubbleCorners: presentationData.chatBubbleCorners)
|
||||
|
||||
let fullTranslucency: Bool = self.controllerInteraction?.enableFullTranslucency ?? true
|
||||
|
||||
self.backgroundNode.updateColor(color: selectDateFillStaticColor(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper), transition: .immediate)
|
||||
self.backgroundNode.updateColor(color: selectDateFillStaticColor(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper), enableBlur: fullTranslucency && dateFillNeedsBlur(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper), transition: .immediate)
|
||||
self.stickBackgroundNode.image = graphics.dateFloatingBackground
|
||||
|
||||
let titleFont = Font.medium(min(18.0, floor(presentationData.fontSize.baseDisplaySize * 13.0 / 17.0)))
|
||||
@ -522,7 +526,7 @@ final class ChatMessageAvatarHeaderNode: ListViewItemHeaderNode {
|
||||
}
|
||||
self.avatarNode.setPeer(context: context, theme: theme, peer: EnginePeer(peer), authorOfMessage: authorOfMessage, overrideImage: overrideImage, emptyColor: emptyColor, synchronousLoad: synchronousLoad, displayDimensions: CGSize(width: 38.0, height: 38.0))
|
||||
|
||||
if peer.isPremium {
|
||||
if peer.isPremium && context.sharedContext.energyUsageSettings.playVideoAvatars {
|
||||
self.cachedDataDisposable.set((context.account.postbox.peerView(id: peer.id)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] peerView in
|
||||
guard let strongSelf = self else {
|
||||
|
||||
@ -236,7 +236,7 @@ class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
let mediaBackgroundFrame = imageFrame.insetBy(dx: -2.0, dy: -2.0)
|
||||
strongSelf.mediaBackgroundNode.frame = mediaBackgroundFrame
|
||||
|
||||
strongSelf.mediaBackgroundNode.updateColor(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), transition: .immediate)
|
||||
strongSelf.mediaBackgroundNode.updateColor(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: item.controllerInteraction.enableFullTranslucency && dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), transition: .immediate)
|
||||
strongSelf.mediaBackgroundNode.update(size: mediaBackgroundFrame.size, transition: .immediate)
|
||||
strongSelf.buttonNode.backgroundColor = item.presentationData.theme.theme.overallDarkAppearance ? UIColor(rgb: 0xffffff, alpha: 0.12) : UIColor(rgb: 0x000000, alpha: 0.12)
|
||||
|
||||
|
||||
@ -525,10 +525,10 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
|
||||
if let currentReplyBackgroundNode = currentReplyBackgroundNode {
|
||||
updatedReplyBackgroundNode = currentReplyBackgroundNode
|
||||
} else {
|
||||
updatedReplyBackgroundNode = NavigationBackgroundNode(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper))
|
||||
updatedReplyBackgroundNode = NavigationBackgroundNode(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: item.controllerInteraction.enableFullTranslucency && dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper))
|
||||
}
|
||||
|
||||
updatedReplyBackgroundNode?.updateColor(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), transition: .immediate)
|
||||
updatedReplyBackgroundNode?.updateColor(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: item.controllerInteraction.enableFullTranslucency && dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), transition: .immediate)
|
||||
}
|
||||
|
||||
var maxContentWidth = normalDisplaySize.width
|
||||
@ -1009,7 +1009,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
|
||||
translation.x = max(-80.0, min(0.0, translation.x))
|
||||
|
||||
if let item = self.item, self.swipeToReplyNode == nil {
|
||||
let swipeToReplyNode = ChatMessageSwipeToReplyNode(fillColor: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), foregroundColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonForegroundColor, wallpaper: item.presentationData.theme.wallpaper), backgroundNode: item.controllerInteraction.presentationContext.backgroundNode, action: ChatMessageSwipeToReplyNode.Action(self.currentSwipeAction))
|
||||
let swipeToReplyNode = ChatMessageSwipeToReplyNode(fillColor: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: item.controllerInteraction.enableFullTranslucency && dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), foregroundColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonForegroundColor, wallpaper: item.presentationData.theme.wallpaper), backgroundNode: item.controllerInteraction.presentationContext.backgroundNode, action: ChatMessageSwipeToReplyNode.Action(self.currentSwipeAction))
|
||||
self.swipeToReplyNode = swipeToReplyNode
|
||||
self.insertSubnode(swipeToReplyNode, at: 0)
|
||||
}
|
||||
|
||||
@ -561,10 +561,10 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
|
||||
if let currentReplyBackgroundNode = currentReplyBackgroundNode {
|
||||
updatedReplyBackgroundNode = currentReplyBackgroundNode
|
||||
} else {
|
||||
updatedReplyBackgroundNode = NavigationBackgroundNode(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper))
|
||||
updatedReplyBackgroundNode = NavigationBackgroundNode(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: item.controllerInteraction.enableFullTranslucency && dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper))
|
||||
}
|
||||
|
||||
updatedReplyBackgroundNode?.updateColor(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), transition: .immediate)
|
||||
updatedReplyBackgroundNode?.updateColor(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: item.controllerInteraction.enableFullTranslucency && dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), transition: .immediate)
|
||||
}
|
||||
|
||||
return (result, { [weak self] layoutData, animation in
|
||||
@ -625,7 +625,7 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
|
||||
case .free:
|
||||
let serviceColor = serviceMessageColorComponents(theme: theme.theme, wallpaper: theme.wallpaper)
|
||||
durationTextColor = serviceColor.primaryText
|
||||
durationBlurColor = (selectDateFillStaticColor(theme: theme.theme, wallpaper: theme.wallpaper), dateFillNeedsBlur(theme: theme.theme, wallpaper: theme.wallpaper))
|
||||
durationBlurColor = (selectDateFillStaticColor(theme: theme.theme, wallpaper: theme.wallpaper), item.controllerInteraction.enableFullTranslucency && dateFillNeedsBlur(theme: theme.theme, wallpaper: theme.wallpaper))
|
||||
case .bubble:
|
||||
durationBlurColor = nil
|
||||
if incoming {
|
||||
|
||||
@ -254,7 +254,7 @@ class ChatMessageProfilePhotoSuggestionContentNode: ChatMessageBubbleContentNode
|
||||
let mediaBackgroundFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((backgroundSize.width - width) / 2.0), y: 0.0), size: backgroundSize)
|
||||
strongSelf.mediaBackgroundNode.frame = mediaBackgroundFrame
|
||||
|
||||
strongSelf.mediaBackgroundNode.updateColor(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), transition: .immediate)
|
||||
strongSelf.mediaBackgroundNode.updateColor(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: item.controllerInteraction.enableFullTranslucency && dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), transition: .immediate)
|
||||
strongSelf.mediaBackgroundNode.update(size: mediaBackgroundFrame.size, transition: .immediate)
|
||||
strongSelf.buttonNode.backgroundColor = item.presentationData.theme.theme.overallDarkAppearance ? UIColor(rgb: 0xffffff, alpha: 0.12) : UIColor(rgb: 0x000000, alpha: 0.12)
|
||||
|
||||
|
||||
@ -894,7 +894,7 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
||||
let shimmeringColor = bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.stickerPlaceholderShimmerColor, wallpaper: item.presentationData.theme.wallpaper)
|
||||
|
||||
let placeholderFrame = updatedImageFrame.insetBy(dx: innerImageInset, dy: innerImageInset)
|
||||
strongSelf.placeholderNode.update(backgroundColor: nil, foregroundColor: foregroundColor, shimmeringColor: shimmeringColor, data: immediateThumbnailData, size: placeholderFrame.size)
|
||||
strongSelf.placeholderNode.update(backgroundColor: nil, foregroundColor: foregroundColor, shimmeringColor: shimmeringColor, data: immediateThumbnailData, size: placeholderFrame.size, enableEffect: item.context.sharedContext.energyUsageSettings.fullTranslucency)
|
||||
strongSelf.placeholderNode.frame = placeholderFrame
|
||||
}
|
||||
|
||||
@ -927,9 +927,9 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
||||
|
||||
if needsReplyBackground {
|
||||
if let replyBackgroundNode = strongSelf.replyBackgroundNode {
|
||||
replyBackgroundNode.updateColor(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), transition: .immediate)
|
||||
replyBackgroundNode.updateColor(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: item.controllerInteraction.enableFullTranslucency && dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), transition: .immediate)
|
||||
} else {
|
||||
let replyBackgroundNode = NavigationBackgroundNode(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper))
|
||||
let replyBackgroundNode = NavigationBackgroundNode(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: item.controllerInteraction.enableFullTranslucency && dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper))
|
||||
strongSelf.replyBackgroundNode = replyBackgroundNode
|
||||
strongSelf.contextSourceNode.contentNode.addSubnode(replyBackgroundNode)
|
||||
}
|
||||
@ -1412,7 +1412,7 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
||||
}
|
||||
|
||||
if let item = self.item, self.swipeToReplyNode == nil {
|
||||
let swipeToReplyNode = ChatMessageSwipeToReplyNode(fillColor: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), foregroundColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonForegroundColor, wallpaper: item.presentationData.theme.wallpaper), backgroundNode: item.controllerInteraction.presentationContext.backgroundNode, action: ChatMessageSwipeToReplyNode.Action(self.currentSwipeAction))
|
||||
let swipeToReplyNode = ChatMessageSwipeToReplyNode(fillColor: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: item.controllerInteraction.enableFullTranslucency && dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), foregroundColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonForegroundColor, wallpaper: item.presentationData.theme.wallpaper), backgroundNode: item.controllerInteraction.presentationContext.backgroundNode, action: ChatMessageSwipeToReplyNode.Action(self.currentSwipeAction))
|
||||
self.swipeToReplyNode = swipeToReplyNode
|
||||
self.insertSubnode(swipeToReplyNode, at: 0)
|
||||
}
|
||||
|
||||
@ -447,7 +447,7 @@ class ChatMessageThreadInfoNode: ASDisplayNode {
|
||||
|
||||
backgroundNode.frame = backgroundFrame
|
||||
backgroundNode.update(size: backgroundNode.bounds.size, cornerRadius: 0.0, transition: .immediate)
|
||||
backgroundNode.updateColor(color: selectDateFillStaticColor(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper), transition: .immediate)
|
||||
backgroundNode.updateColor(color: selectDateFillStaticColor(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper), enableBlur: arguments.controllerInteraction.enableFullTranslucency && dateFillNeedsBlur(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper), transition: .immediate)
|
||||
}
|
||||
} else {
|
||||
node.contentBackgroundNode.frame = CGRect(origin: CGPoint(x: -1.0, y: -3.0), size: image.size)
|
||||
|
||||
@ -516,7 +516,7 @@ private final class ThemeSettingsThemeItemIconNode : ListViewItemNode {
|
||||
strongSelf.stickerFetchedDisposable.set(fetchedMediaResource(mediaBox: item.context.account.postbox.mediaBox, userLocation: .other, userContentType: .sticker, reference: MediaResourceReference.media(media: .standalone(media: file), resource: file.resource)).start())
|
||||
|
||||
let thumbnailDimensions = PixelDimensions(width: 512, height: 512)
|
||||
strongSelf.placeholderNode.update(backgroundColor: nil, foregroundColor: UIColor(rgb: 0xffffff, alpha: 0.2), shimmeringColor: UIColor(rgb: 0xffffff, alpha: 0.3), data: file.immediateThumbnailData, size: emojiFrame.size, imageSize: thumbnailDimensions.cgSize)
|
||||
strongSelf.placeholderNode.update(backgroundColor: nil, foregroundColor: UIColor(rgb: 0xffffff, alpha: 0.2), shimmeringColor: UIColor(rgb: 0xffffff, alpha: 0.3), data: file.immediateThumbnailData, size: emojiFrame.size, enableEffect: item.context.sharedContext.energyUsageSettings.fullTranslucency, imageSize: thumbnailDimensions.cgSize)
|
||||
strongSelf.placeholderNode.frame = emojiFrame
|
||||
}
|
||||
|
||||
|
||||
@ -107,7 +107,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
|
||||
self.presentController = presentController
|
||||
self.getNavigationController = getNavigationController
|
||||
|
||||
self.automaticMediaDownloadSettings = context.sharedContext.currentAutomaticMediaDownloadSettings.with { $0 }
|
||||
self.automaticMediaDownloadSettings = context.sharedContext.currentAutomaticMediaDownloadSettings
|
||||
|
||||
self.backgroundNode = createWallpaperBackgroundNode(context: context, forChatDisplay: true)
|
||||
self.backgroundNode.isUserInteractionEnabled = false
|
||||
@ -125,7 +125,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
|
||||
return presentationData.strings.VoiceOver_ScrollStatus(row, count).string
|
||||
}
|
||||
|
||||
self.loadingNode = ChatLoadingNode(theme: self.presentationData.theme, chatWallpaper: self.presentationData.chatWallpaper, bubbleCorners: self.presentationData.chatBubbleCorners)
|
||||
self.loadingNode = ChatLoadingNode(context: context, theme: self.presentationData.theme, chatWallpaper: self.presentationData.chatWallpaper, bubbleCorners: self.presentationData.chatBubbleCorners)
|
||||
self.emptyNode = ChatRecentActionsEmptyNode(theme: self.presentationData.theme, chatWallpaper: self.presentationData.chatWallpaper, chatBubbleCorners: self.presentationData.chatBubbleCorners)
|
||||
self.emptyNode.alpha = 0.0
|
||||
|
||||
|
||||
@ -496,7 +496,7 @@ private final class ThemeSettingsThemeItemIconNode : ListViewItemNode {
|
||||
strongSelf.stickerFetchedDisposable.set(fetchedMediaResource(mediaBox: item.context.account.postbox.mediaBox, userLocation: .other, userContentType: .sticker, reference: MediaResourceReference.media(media: .standalone(media: file), resource: file.resource)).start())
|
||||
|
||||
let thumbnailDimensions = PixelDimensions(width: 512, height: 512)
|
||||
strongSelf.placeholderNode.update(backgroundColor: nil, foregroundColor: UIColor(rgb: 0xffffff, alpha: 0.2), shimmeringColor: UIColor(rgb: 0xffffff, alpha: 0.3), data: file.immediateThumbnailData, size: emojiFrame.size, imageSize: thumbnailDimensions.cgSize)
|
||||
strongSelf.placeholderNode.update(backgroundColor: nil, foregroundColor: UIColor(rgb: 0xffffff, alpha: 0.2), shimmeringColor: UIColor(rgb: 0xffffff, alpha: 0.3), data: file.immediateThumbnailData, size: emojiFrame.size, enableEffect: item.context.sharedContext.energyUsageSettings.fullTranslucency, imageSize: thumbnailDimensions.cgSize)
|
||||
strongSelf.placeholderNode.frame = emojiFrame
|
||||
}
|
||||
|
||||
|
||||
@ -499,7 +499,7 @@ final class HorizontalListContextResultsChatInputPanelItemNode: ListViewItemNode
|
||||
placeholderNode.bounds = CGRect(origin: CGPoint(), size: CGSize(width: croppedImageDimensions.width, height: croppedImageDimensions.height))
|
||||
placeholderNode.position = CGPoint(x: height / 2.0, y: (nodeLayout.contentSize.height - sideInset) / 2.0 + sideInset)
|
||||
|
||||
placeholderNode.update(backgroundColor: item.theme.list.plainBackgroundColor, foregroundColor: item.theme.list.mediaPlaceholderColor.mixedWith(item.theme.list.plainBackgroundColor, alpha: 0.4), shimmeringColor: item.theme.list.mediaPlaceholderColor.withAlphaComponent(0.3), data: immediateThumbnailData, size: CGSize(width: croppedImageDimensions.width, height: croppedImageDimensions.height))
|
||||
placeholderNode.update(backgroundColor: item.theme.list.plainBackgroundColor, foregroundColor: item.theme.list.mediaPlaceholderColor.mixedWith(item.theme.list.plainBackgroundColor, alpha: 0.4), shimmeringColor: item.theme.list.mediaPlaceholderColor.withAlphaComponent(0.3), data: immediateThumbnailData, size: CGSize(width: croppedImageDimensions.width, height: croppedImageDimensions.height), enableEffect: item.context.sharedContext.energyUsageSettings.fullTranslucency)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@ -11,9 +11,10 @@ import AnimatedStickerNode
|
||||
import TelegramAnimatedStickerNode
|
||||
import ShimmerEffect
|
||||
import TelegramPresentationData
|
||||
import AccountContext
|
||||
|
||||
final class HorizontalStickerGridItem: GridItem {
|
||||
let account: Account
|
||||
let context: AccountContext
|
||||
let file: TelegramMediaFile
|
||||
let theme: PresentationTheme
|
||||
let isPreviewed: (HorizontalStickerGridItem) -> Bool
|
||||
@ -21,8 +22,8 @@ final class HorizontalStickerGridItem: GridItem {
|
||||
|
||||
let section: GridSection? = nil
|
||||
|
||||
init(account: Account, file: TelegramMediaFile, theme: PresentationTheme, isPreviewed: @escaping (HorizontalStickerGridItem) -> Bool, sendSticker: @escaping (FileMediaReference, UIView, CGRect) -> Void) {
|
||||
self.account = account
|
||||
init(context: AccountContext, file: TelegramMediaFile, theme: PresentationTheme, isPreviewed: @escaping (HorizontalStickerGridItem) -> Bool, sendSticker: @escaping (FileMediaReference, UIView, CGRect) -> Void) {
|
||||
self.context = context
|
||||
self.file = file
|
||||
self.theme = theme
|
||||
self.isPreviewed = isPreviewed
|
||||
@ -31,7 +32,7 @@ final class HorizontalStickerGridItem: GridItem {
|
||||
|
||||
func node(layout: GridNodeLayout, synchronousLoad: Bool) -> GridItemNode {
|
||||
let node = HorizontalStickerGridItemNode()
|
||||
node.setup(account: self.account, item: self)
|
||||
node.setup(context: self.context, item: self)
|
||||
node.sendSticker = self.sendSticker
|
||||
return node
|
||||
}
|
||||
@ -41,13 +42,13 @@ final class HorizontalStickerGridItem: GridItem {
|
||||
assertionFailure()
|
||||
return
|
||||
}
|
||||
node.setup(account: self.account, item: self)
|
||||
node.setup(context: self.context, item: self)
|
||||
node.sendSticker = self.sendSticker
|
||||
}
|
||||
}
|
||||
|
||||
final class HorizontalStickerGridItemNode: GridItemNode {
|
||||
private var currentState: (Account, HorizontalStickerGridItem, CGSize)?
|
||||
private var currentState: (AccountContext, HorizontalStickerGridItem, CGSize)?
|
||||
let imageNode: TransformImageNode
|
||||
private(set) var animationNode: AnimatedStickerNode?
|
||||
private(set) var placeholderNode: StickerShimmerEffectNode?
|
||||
@ -137,8 +138,8 @@ final class HorizontalStickerGridItemNode: GridItemNode {
|
||||
self.imageNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.imageNodeTap(_:))))
|
||||
}
|
||||
|
||||
func setup(account: Account, item: HorizontalStickerGridItem) {
|
||||
if self.currentState == nil || self.currentState!.0 !== account || self.currentState!.1.file.id != item.file.id {
|
||||
func setup(context: AccountContext, item: HorizontalStickerGridItem) {
|
||||
if self.currentState == nil || self.currentState!.0 !== context || self.currentState!.1.file.id != item.file.id {
|
||||
if let dimensions = item.file.dimensions {
|
||||
if item.file.isAnimatedSticker || item.file.isVideoSticker {
|
||||
let animationNode: AnimatedStickerNode
|
||||
@ -161,9 +162,9 @@ final class HorizontalStickerGridItemNode: GridItemNode {
|
||||
let fittedDimensions = dimensions.cgSize.aspectFitted(CGSize(width: 160.0, height: 160.0))
|
||||
|
||||
if item.file.isVideoSticker {
|
||||
self.imageNode.setSignal(chatMessageSticker(postbox: account.postbox, userLocation: .other, file: item.file, small: true, synchronousLoad: false))
|
||||
self.imageNode.setSignal(chatMessageSticker(postbox: context.account.postbox, userLocation: .other, file: item.file, small: true, synchronousLoad: false))
|
||||
} else {
|
||||
self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: account.postbox, userLocation: .other, file: item.file, small: true, size: fittedDimensions, synchronousLoad: false))
|
||||
self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: context.account.postbox, userLocation: .other, file: item.file, small: true, size: fittedDimensions, synchronousLoad: false))
|
||||
}
|
||||
animationNode.started = { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
@ -181,19 +182,19 @@ final class HorizontalStickerGridItemNode: GridItemNode {
|
||||
strongSelf.removePlaceholder(animated: false)
|
||||
}
|
||||
}
|
||||
animationNode.setup(source: AnimatedStickerResourceSource(account: account, resource: item.file.resource, isVideo: item.file.isVideoSticker), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), playbackMode: .loop, mode: .cached)
|
||||
animationNode.setup(source: AnimatedStickerResourceSource(account: context.account, resource: item.file.resource, isVideo: item.file.isVideoSticker), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), playbackMode: .loop, mode: .cached)
|
||||
|
||||
self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: account, userLocation: .other, fileReference: stickerPackFileReference(item.file), resource: item.file.resource).start())
|
||||
self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: context.account, userLocation: .other, fileReference: stickerPackFileReference(item.file), resource: item.file.resource).start())
|
||||
} else {
|
||||
self.imageNode.alpha = 1.0
|
||||
self.imageNode.setSignal(chatMessageSticker(account: account, userLocation: .other, file: item.file, small: true))
|
||||
self.imageNode.setSignal(chatMessageSticker(account: context.account, userLocation: .other, file: item.file, small: true))
|
||||
|
||||
if let currentAnimationNode = self.animationNode {
|
||||
self.animationNode = nil
|
||||
currentAnimationNode.removeFromSupernode()
|
||||
}
|
||||
|
||||
self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: account, userLocation: .other, fileReference: stickerPackFileReference(item.file), resource: chatMessageStickerResource(file: item.file, small: true)).start())
|
||||
self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: context.account, userLocation: .other, fileReference: stickerPackFileReference(item.file), resource: chatMessageStickerResource(file: item.file, small: true)).start())
|
||||
}
|
||||
|
||||
if item.file.isPremiumSticker {
|
||||
@ -237,7 +238,7 @@ final class HorizontalStickerGridItemNode: GridItemNode {
|
||||
lockIconNode.removeFromSupernode()
|
||||
}
|
||||
|
||||
self.currentState = (account, item, dimensions.cgSize)
|
||||
self.currentState = (context, item, dimensions.cgSize)
|
||||
self.setNeedsLayout()
|
||||
}
|
||||
}
|
||||
@ -254,8 +255,8 @@ final class HorizontalStickerGridItemNode: GridItemNode {
|
||||
if let placeholderNode = self.placeholderNode {
|
||||
placeholderNode.frame = bounds
|
||||
|
||||
if let theme = self.currentState?.1.theme, let file = self.currentState?.1.file {
|
||||
placeholderNode.update(backgroundColor: theme.list.plainBackgroundColor, foregroundColor: theme.list.mediaPlaceholderColor.mixedWith(theme.list.plainBackgroundColor, alpha: 0.4), shimmeringColor: theme.list.mediaPlaceholderColor.withAlphaComponent(0.3), data: file.immediateThumbnailData, size: bounds.size)
|
||||
if let context = self.currentState?.0, let theme = self.currentState?.1.theme, let file = self.currentState?.1.file {
|
||||
placeholderNode.update(backgroundColor: theme.list.plainBackgroundColor, foregroundColor: theme.list.mediaPlaceholderColor.mixedWith(theme.list.plainBackgroundColor, alpha: 0.4), shimmeringColor: theme.list.mediaPlaceholderColor.withAlphaComponent(0.3), data: file.immediateThumbnailData, size: bounds.size, enableEffect: context.sharedContext.energyUsageSettings.fullTranslucency)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -70,8 +70,8 @@ private struct StickerEntry: Identifiable, Comparable {
|
||||
return lhs.index < rhs.index
|
||||
}
|
||||
|
||||
func item(account: Account, stickersInteraction: HorizontalStickersChatContextPanelInteraction, interfaceInteraction: ChatPanelInterfaceInteraction, theme: PresentationTheme) -> GridItem {
|
||||
return HorizontalStickerGridItem(account: account, file: self.file, theme: theme, isPreviewed: { item in
|
||||
func item(context: AccountContext, stickersInteraction: HorizontalStickersChatContextPanelInteraction, interfaceInteraction: ChatPanelInterfaceInteraction, theme: PresentationTheme) -> GridItem {
|
||||
return HorizontalStickerGridItem(context: context, file: self.file, theme: theme, isPreviewed: { item in
|
||||
return false//stickersInteraction.previewedStickerItem == item
|
||||
}, sendSticker: { file, node, rect in
|
||||
let _ = interfaceInteraction.sendSticker(file, true, node, rect, nil, [])
|
||||
@ -88,15 +88,15 @@ private struct StickerEntryTransition {
|
||||
let scrollToItem: GridNodeScrollToItem?
|
||||
}
|
||||
|
||||
private func preparedGridEntryTransition(account: Account, from fromEntries: [StickerEntry], to toEntries: [StickerEntry], stickersInteraction: HorizontalStickersChatContextPanelInteraction, interfaceInteraction: ChatPanelInterfaceInteraction, theme: PresentationTheme) -> StickerEntryTransition {
|
||||
private func preparedGridEntryTransition(context: AccountContext, from fromEntries: [StickerEntry], to toEntries: [StickerEntry], stickersInteraction: HorizontalStickersChatContextPanelInteraction, interfaceInteraction: ChatPanelInterfaceInteraction, theme: PresentationTheme) -> StickerEntryTransition {
|
||||
let stationaryItems: GridNodeStationaryItems = .none
|
||||
let scrollToItem: GridNodeScrollToItem? = nil
|
||||
|
||||
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
|
||||
|
||||
let deletions = deleteIndices
|
||||
let insertions = indicesAndItems.map { GridNodeInsertItem(index: $0.0, item: $0.1.item(account: account, stickersInteraction: stickersInteraction, interfaceInteraction: interfaceInteraction, theme: theme), previousIndex: $0.2) }
|
||||
let updates = updateIndices.map { GridNodeUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, stickersInteraction: stickersInteraction, interfaceInteraction: interfaceInteraction, theme: theme)) }
|
||||
let insertions = indicesAndItems.map { GridNodeInsertItem(index: $0.0, item: $0.1.item(context: context, stickersInteraction: stickersInteraction, interfaceInteraction: interfaceInteraction, theme: theme), previousIndex: $0.2) }
|
||||
let updates = updateIndices.map { GridNodeUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, stickersInteraction: stickersInteraction, interfaceInteraction: interfaceInteraction, theme: theme)) }
|
||||
|
||||
return StickerEntryTransition(deletions: deletions, insertions: insertions, updates: updates, updateFirstIndexInSectionOffset: nil, stationaryItems: stationaryItems, scrollToItem: scrollToItem)
|
||||
}
|
||||
@ -290,7 +290,7 @@ final class HorizontalStickersChatContextPanelNode: ChatInputContextPanelNode {
|
||||
self.updateLayout(size: validLayout.0, leftInset: validLayout.1, rightInset: validLayout.2, bottomInset: validLayout.3, transition: .immediate, interfaceState: validLayout.4)
|
||||
}
|
||||
|
||||
let transition = preparedGridEntryTransition(account: self.context.account, from: previousEntries, to: entries, stickersInteraction: self.stickersInteraction, interfaceInteraction: self.interfaceInteraction!, theme: self.theme)
|
||||
let transition = preparedGridEntryTransition(context: self.context, from: previousEntries, to: entries, stickersInteraction: self.stickersInteraction, interfaceInteraction: self.interfaceInteraction!, theme: self.theme)
|
||||
self.enqueueTransition(transition)
|
||||
}
|
||||
|
||||
|
||||
@ -31,7 +31,7 @@ final class InChatPrefetchManager {
|
||||
|
||||
init(context: AccountContext) {
|
||||
self.context = context
|
||||
self.settings = context.sharedContext.currentAutomaticMediaDownloadSettings.with { $0 }
|
||||
self.settings = context.sharedContext.currentAutomaticMediaDownloadSettings
|
||||
}
|
||||
|
||||
func updateAutoDownloadSettings(_ settings: MediaAutoDownloadSettings) {
|
||||
|
||||
@ -431,7 +431,7 @@ private final class InlineReactionSearchStickersNode: ASDisplayNode, UIScrollVie
|
||||
itemNode = current
|
||||
} else {
|
||||
let item = HorizontalStickerGridItem(
|
||||
account: self.context.account,
|
||||
context: self.context,
|
||||
file: item.file,
|
||||
theme: self.theme,
|
||||
isPreviewed: { [weak self] item in
|
||||
|
||||
@ -131,7 +131,7 @@ private final class LargeEmojiActionSheetItemNode: ActionSheetItemNode {
|
||||
}
|
||||
|
||||
if let immediateThumbnailData = file.immediateThumbnailData {
|
||||
self.placeholderNode.update(backgroundColor: nil, foregroundColor: theme.secondaryTextColor.blitOver(theme.itemBackgroundColor, alpha: 0.55), shimmeringColor: theme.itemBackgroundColor.withAlphaComponent(0.4), data: immediateThumbnailData, size: CGSize(width: 96.0, height: 96.0), imageSize: dimensions.cgSize)
|
||||
self.placeholderNode.update(backgroundColor: nil, foregroundColor: theme.secondaryTextColor.blitOver(theme.itemBackgroundColor, alpha: 0.55), shimmeringColor: theme.itemBackgroundColor.withAlphaComponent(0.4), data: immediateThumbnailData, size: CGSize(width: 96.0, height: 96.0), enableEffect: context.sharedContext.energyUsageSettings.fullTranslucency, imageSize: dimensions.cgSize)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -146,12 +146,16 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
public let currentInAppNotificationSettings: Atomic<InAppNotificationSettings>
|
||||
private var inAppNotificationSettingsDisposable: Disposable?
|
||||
|
||||
public let currentAutomaticMediaDownloadSettings: Atomic<MediaAutoDownloadSettings>
|
||||
public var currentAutomaticMediaDownloadSettings: MediaAutoDownloadSettings
|
||||
private let _automaticMediaDownloadSettings = Promise<MediaAutoDownloadSettings>()
|
||||
public var automaticMediaDownloadSettings: Signal<MediaAutoDownloadSettings, NoError> {
|
||||
return self._automaticMediaDownloadSettings.get()
|
||||
}
|
||||
|
||||
public var energyUsageSettings: EnergyUsageSettings {
|
||||
return self.currentAutomaticMediaDownloadSettings.energyUsageSettings
|
||||
}
|
||||
|
||||
public let currentAutodownloadSettings: Atomic<AutodownloadSettings>
|
||||
private let _autodownloadSettings = Promise<AutodownloadSettings>()
|
||||
private var currentAutodownloadSettingsDisposable = MetaDisposable()
|
||||
@ -230,7 +234,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
}
|
||||
|
||||
self._currentPresentationData = Atomic(value: initialPresentationDataAndSettings.presentationData)
|
||||
self.currentAutomaticMediaDownloadSettings = Atomic(value: initialPresentationDataAndSettings.automaticMediaDownloadSettings)
|
||||
self.currentAutomaticMediaDownloadSettings = initialPresentationDataAndSettings.automaticMediaDownloadSettings
|
||||
self.currentAutodownloadSettings = Atomic(value: initialPresentationDataAndSettings.autodownloadSettings)
|
||||
self.currentMediaInputSettings = Atomic(value: initialPresentationDataAndSettings.mediaInputSettings)
|
||||
self.currentInAppNotificationSettings = Atomic(value: initialPresentationDataAndSettings.inAppNotificationSettings)
|
||||
@ -363,7 +367,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
|
||||
self.automaticMediaDownloadSettingsDisposable.set(self._automaticMediaDownloadSettings.get().start(next: { [weak self] next in
|
||||
if let strongSelf = self {
|
||||
let _ = strongSelf.currentAutomaticMediaDownloadSettings.swap(next)
|
||||
strongSelf.currentAutomaticMediaDownloadSettings = next
|
||||
}
|
||||
}))
|
||||
|
||||
|
||||
@ -328,7 +328,7 @@ private final class FeaturedPackItemNode: ListViewItemNode {
|
||||
immediateThumbnailData = data
|
||||
}
|
||||
|
||||
placeholderNode.update(backgroundColor: theme.chat.inputMediaPanel.stickersBackgroundColor.withAlphaComponent(1.0), foregroundColor: theme.chat.inputMediaPanel.stickersSectionTextColor.blitOver(theme.chat.inputMediaPanel.stickersBackgroundColor, alpha: 0.15), shimmeringColor: theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.3), data: immediateThumbnailData, size: boundingImageSize, imageSize: imageSize.cgSize)
|
||||
placeholderNode.update(backgroundColor: theme.chat.inputMediaPanel.stickersBackgroundColor.withAlphaComponent(1.0), foregroundColor: theme.chat.inputMediaPanel.stickersSectionTextColor.blitOver(theme.chat.inputMediaPanel.stickersBackgroundColor, alpha: 0.15), shimmeringColor: theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.3), data: immediateThumbnailData, size: boundingImageSize, enableEffect: true, imageSize: imageSize.cgSize)
|
||||
}
|
||||
|
||||
self.containerNode.frame = CGRect(origin: CGPoint(), size: boundingSize)
|
||||
|
||||
@ -258,6 +258,73 @@ public struct MediaAutoSaveSettings: Codable, Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
public struct EnergyUsageSettings: Codable, Equatable {
|
||||
private enum CodingKeys: CodingKey {
|
||||
case loopEmoji
|
||||
case playVideoAvatars
|
||||
case fullTranslucency
|
||||
case extendBackgroundWork
|
||||
case synchronizeInBackground
|
||||
case autodownloadInBackground
|
||||
}
|
||||
|
||||
public static var `default`: EnergyUsageSettings {
|
||||
return EnergyUsageSettings(
|
||||
loopEmoji: true,
|
||||
playVideoAvatars: true,
|
||||
fullTranslucency: true,
|
||||
extendBackgroundWork: true,
|
||||
synchronizeInBackground: true,
|
||||
autodownloadInBackground: true
|
||||
)
|
||||
}
|
||||
|
||||
public var loopEmoji: Bool
|
||||
public var playVideoAvatars: Bool
|
||||
public var fullTranslucency: Bool
|
||||
public var extendBackgroundWork: Bool
|
||||
public var synchronizeInBackground: Bool
|
||||
public var autodownloadInBackground: Bool
|
||||
|
||||
public init(
|
||||
loopEmoji: Bool,
|
||||
playVideoAvatars: Bool,
|
||||
fullTranslucency: Bool,
|
||||
extendBackgroundWork: Bool,
|
||||
synchronizeInBackground: Bool,
|
||||
autodownloadInBackground: Bool
|
||||
) {
|
||||
self.loopEmoji = loopEmoji
|
||||
self.playVideoAvatars = playVideoAvatars
|
||||
self.fullTranslucency = fullTranslucency
|
||||
self.extendBackgroundWork = extendBackgroundWork
|
||||
self.synchronizeInBackground = synchronizeInBackground
|
||||
self.autodownloadInBackground = autodownloadInBackground
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
self.loopEmoji = try container.decodeIfPresent(Bool.self, forKey: .loopEmoji) ?? EnergyUsageSettings.default.loopEmoji
|
||||
self.playVideoAvatars = try container.decodeIfPresent(Bool.self, forKey: .playVideoAvatars) ?? EnergyUsageSettings.default.playVideoAvatars
|
||||
self.fullTranslucency = try container.decodeIfPresent(Bool.self, forKey: .fullTranslucency) ?? EnergyUsageSettings.default.fullTranslucency
|
||||
self.extendBackgroundWork = try container.decodeIfPresent(Bool.self, forKey: .extendBackgroundWork) ?? EnergyUsageSettings.default.extendBackgroundWork
|
||||
self.synchronizeInBackground = try container.decodeIfPresent(Bool.self, forKey: .synchronizeInBackground) ?? EnergyUsageSettings.default.synchronizeInBackground
|
||||
self.autodownloadInBackground = try container.decodeIfPresent(Bool.self, forKey: .autodownloadInBackground) ?? EnergyUsageSettings.default.autodownloadInBackground
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
try container.encode(self.loopEmoji, forKey: .loopEmoji)
|
||||
try container.encode(self.playVideoAvatars, forKey: .playVideoAvatars)
|
||||
try container.encode(self.fullTranslucency, forKey: .fullTranslucency)
|
||||
try container.encode(self.extendBackgroundWork, forKey: .extendBackgroundWork)
|
||||
try container.encode(self.synchronizeInBackground, forKey: .synchronizeInBackground)
|
||||
try container.encode(self.autodownloadInBackground, forKey: .autodownloadInBackground)
|
||||
}
|
||||
}
|
||||
|
||||
public struct MediaAutoDownloadSettings: Codable, Equatable {
|
||||
public var presets: MediaAutoDownloadPresets
|
||||
public var cellular: MediaAutoDownloadConnection
|
||||
@ -267,27 +334,30 @@ public struct MediaAutoDownloadSettings: Codable, Equatable {
|
||||
public var autoplayVideos: Bool
|
||||
public var downloadInBackground: Bool
|
||||
|
||||
public var energyUsageSettings: EnergyUsageSettings
|
||||
|
||||
public static var defaultSettings: MediaAutoDownloadSettings {
|
||||
let mb: Int64 = 1024 * 1024
|
||||
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),
|
||||
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),
|
||||
video: MediaAutoDownloadCategory(contacts: true, otherPrivate: true, groups: true, channels: true, sizeLimit: Int64(2.5 * CGFloat(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),
|
||||
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)))
|
||||
return MediaAutoDownloadSettings(presets: presets, cellular: MediaAutoDownloadConnection(enabled: true, preset: .medium, custom: nil), wifi: MediaAutoDownloadConnection(enabled: true, preset: .high, custom: nil), autoplayGifs: true, autoplayVideos: true, downloadInBackground: true)
|
||||
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)),
|
||||
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: Int64(2.5 * CGFloat(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),
|
||||
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)))
|
||||
return MediaAutoDownloadSettings(presets: presets, cellular: MediaAutoDownloadConnection(enabled: true, preset: .medium, custom: nil), wifi: MediaAutoDownloadConnection(enabled: true, preset: .high, custom: nil), autoplayGifs: true, autoplayVideos: true, downloadInBackground: true, energyUsageSettings: EnergyUsageSettings.default)
|
||||
}
|
||||
|
||||
public init(presets: MediaAutoDownloadPresets, cellular: MediaAutoDownloadConnection, wifi: MediaAutoDownloadConnection, autoplayGifs: Bool, autoplayVideos: Bool, downloadInBackground: Bool) {
|
||||
public init(presets: MediaAutoDownloadPresets, cellular: MediaAutoDownloadConnection, wifi: MediaAutoDownloadConnection, autoplayGifs: Bool, autoplayVideos: Bool, downloadInBackground: Bool, energyUsageSettings: EnergyUsageSettings) {
|
||||
self.presets = presets
|
||||
self.cellular = cellular
|
||||
self.wifi = wifi
|
||||
self.autoplayGifs = autoplayGifs
|
||||
self.autoplayVideos = autoplayGifs
|
||||
self.downloadInBackground = downloadInBackground
|
||||
self.energyUsageSettings = energyUsageSettings
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
@ -303,6 +373,8 @@ public struct MediaAutoDownloadSettings: Codable, Equatable {
|
||||
self.autoplayGifs = try container.decode(Int32.self, forKey: "autoplayGifs") != 0
|
||||
self.autoplayVideos = try container.decode(Int32.self, forKey: "autoplayVideos") != 0
|
||||
self.downloadInBackground = try container.decode(Int32.self, forKey: "downloadInBackground") != 0
|
||||
|
||||
self.energyUsageSettings = (try container.decodeIfPresent(EnergyUsageSettings.self, forKey: "energyUsageSettings")) ?? EnergyUsageSettings.default
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
@ -313,6 +385,7 @@ public struct MediaAutoDownloadSettings: Codable, Equatable {
|
||||
try container.encode((self.autoplayGifs ? 1 : 0) as Int32, forKey: "autoplayGifs")
|
||||
try container.encode((self.autoplayVideos ? 1 : 0) as Int32, forKey: "autoplayVideos")
|
||||
try container.encode((self.downloadInBackground ? 1 : 0) as Int32, forKey: "downloadInBackground")
|
||||
try container.encode(self.energyUsageSettings, forKey: "energyUsageSettings")
|
||||
}
|
||||
|
||||
public func connectionSettings(for networkType: MediaAutoDownloadNetworkType) -> MediaAutoDownloadConnection {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"app": "9.4",
|
||||
"app": "9.4.2",
|
||||
"bazel": "5.3.1",
|
||||
"xcode": "14.2"
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user