Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios

This commit is contained in:
Ilya Laktyushin 2023-02-15 16:31:59 +04:00
commit f2a327cad7
78 changed files with 1090 additions and 586 deletions

View File

@ -24,20 +24,19 @@ jobs:
- name: Create canonical source directory - name: Create canonical source directory
run: | run: |
set -x set -x
sudo mkdir /Users/telegram sudo mkdir -p /Users/Shared
sudo chown -R $(whoami) /Users/telegram cp -R $GITHUB_WORKSPACE /Users/Shared/
cp -R $GITHUB_WORKSPACE /Users/telegram/ mv /Users/Shared/$(basename $GITHUB_WORKSPACE) /Users/Shared/telegram-ios
mv /Users/telegram/$(basename $GITHUB_WORKSPACE) /Users/telegram/telegram-ios
- name: Build the App - name: Build the App
run: | run: |
set -x set -x
# source code paths are included in the final binary, so we need to make them stable across builds # 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 # use canonical bazel root
BAZEL_USER_ROOT="/private/var/tmp/_bazel_telegram" BAZEL_USER_ROOT="/private/var/tmp/_bazel_containerhost"
cd $SOURCE_DIR cd $SOURCE_DIR
@ -50,37 +49,14 @@ jobs:
echo "BUILD_NUMBER=$(echo $BUILD_NUMBER)" >> $GITHUB_ENV echo "BUILD_NUMBER=$(echo $BUILD_NUMBER)" >> $GITHUB_ENV
echo "APP_VERSION=$(echo $APP_VERSION)" >> $GITHUB_ENV echo "APP_VERSION=$(echo $APP_VERSION)" >> $GITHUB_ENV
# prepare temporary keychain python3 build-system/Make/ImportCertificates.py --path build-system/fake-codesigning/certs
export MY_KEYCHAIN="temp.keychain" python3 -u build-system/Make/Make.py \
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 \
--bazelUserRoot="$BAZEL_USER_ROOT" \ --bazelUserRoot="$BAZEL_USER_ROOT" \
build \ build \
--disableParallelSwiftmoduleGeneration \ --configurationPath="build-system/appstore-configuration.json" \
--configurationPath="$HOME/telegram-configuration" \ --codesigningInformationPath=build-system/fake-codesigning \
--buildNumber=$BUILD_NUMBER \ --configuration=release_arm64 \
--configuration=release_universal --buildNumber="$BUILD_NUMBER"
# collect ipa # collect ipa
OUTPUT_PATH="build/artifacts" OUTPUT_PATH="build/artifacts"
@ -117,7 +93,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with: with:
upload_url: ${{ steps.create_release.outputs.upload_url }} 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_name: Telegram.ipa
asset_content_type: application/zip asset_content_type: application/zip
@ -128,6 +104,6 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with: with:
upload_url: ${{ steps.create_release.outputs.upload_url }} 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_name: Telegram.DSYMs.zip
asset_content_type: application/zip asset_content_type: application/zip

View File

@ -718,7 +718,12 @@ private final class NotificationServiceHandler {
let _ = (combineLatest(queue: self.queue, let _ = (combineLatest(queue: self.queue,
self.accountManager.accountRecords(), 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) |> take(1)
|> deliverOn(self.queue)).start(next: { [weak self] records, sharedData in |> 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 let loggingSettings = sharedData.entries[SharedDataKeys.loggingSettings]?.get(LoggingSettings.self) ?? LoggingSettings.defaultSettings
Logger.shared.logToFile = loggingSettings.logToFile Logger.shared.logToFile = loggingSettings.logToFile
Logger.shared.logToConsole = loggingSettings.logToConsole 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) { if let keyId = notificationPayloadKeyId(data: payloadData) {
outer: for listRecord in records.records { outer: for listRecord in records.records {
@ -1406,34 +1419,38 @@ private final class NotificationServiceHandler {
let pollSignal: Signal<Never, NoError> let pollSignal: Signal<Never, NoError>
stateManager.network.shouldKeepConnection.set(.single(true)) if !shouldSynchronizeState {
if peerId.namespace == Namespaces.Peer.CloudChannel { pollSignal = .complete()
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 { } else {
Logger.shared.log("NotificationService \(episode)", "Will perform non-specific getDifference") stateManager.network.shouldKeepConnection.set(.single(true))
enum ControlError { if peerId.namespace == Namespaces.Peer.CloudChannel {
case restart Logger.shared.log("NotificationService \(episode)", "Will poll channel \(peerId)")
}
let signal = stateManager.standalonePollDifference() pollSignal = standalonePollChannelOnce(
|> castError(ControlError.self) accountPeerId: stateManager.accountPeerId,
|> mapToSignal { result -> Signal<Never, ControlError> in postbox: stateManager.postbox,
if result { network: stateManager.network,
return .complete() peerId: peerId,
} else { stateManager: stateManager
return .fail(.restart) )
} 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> let pollWithUpdatedContent: Signal<NotificationContent, NoError>

View File

@ -744,13 +744,15 @@ public protocol SharedAccountContext: AnyObject {
var currentPresentationData: Atomic<PresentationData> { get } var currentPresentationData: Atomic<PresentationData> { get }
var presentationData: Signal<PresentationData, NoError> { get } var presentationData: Signal<PresentationData, NoError> { get }
var currentAutomaticMediaDownloadSettings: Atomic<MediaAutoDownloadSettings> { get } var currentAutomaticMediaDownloadSettings: MediaAutoDownloadSettings { get }
var automaticMediaDownloadSettings: Signal<MediaAutoDownloadSettings, NoError> { get } var automaticMediaDownloadSettings: Signal<MediaAutoDownloadSettings, NoError> { get }
var currentAutodownloadSettings: Atomic<AutodownloadSettings> { get } var currentAutodownloadSettings: Atomic<AutodownloadSettings> { get }
var immediateExperimentalUISettings: ExperimentalUISettings { get } var immediateExperimentalUISettings: ExperimentalUISettings { get }
var currentInAppNotificationSettings: Atomic<InAppNotificationSettings> { get } var currentInAppNotificationSettings: Atomic<InAppNotificationSettings> { get }
var currentMediaInputSettings: Atomic<MediaInputSettings> { get } var currentMediaInputSettings: Atomic<MediaInputSettings> { get }
var energyUsageSettings: EnergyUsageSettings { get }
var applicationBindings: TelegramApplicationBindings { get } var applicationBindings: TelegramApplicationBindings { get }
var authorizationPushConfiguration: Signal<AuthorizationCodePushNotificationConfiguration?, NoError> { get } var authorizationPushConfiguration: Signal<AuthorizationCodePushNotificationConfiguration?, NoError> { get }

View File

@ -31,8 +31,8 @@ private struct ArchivedStickersNoticeEntry: Comparable, Identifiable {
return lhs.index < rhs.index return lhs.index < rhs.index
} }
func item(account: Account, presentationData: PresentationData) -> ListViewItem { func item(context: AccountContext, 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: { 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 }, setPackIdWithRevealedOptions: { current, previous in
}, addPack: { }, addPack: {
}, removePack: { }, removePack: {
@ -47,12 +47,12 @@ private struct ArchivedStickersNoticeTransition {
let updates: [ListViewUpdateItem] 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 (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) } 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 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(account: account, 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) return ArchivedStickersNoticeTransition(deletions: deletions, insertions: insertions, updates: updates)
} }
@ -79,7 +79,7 @@ private final class ArchivedStickersNoticeAlertContentNode: AlertContentNode {
return self.isUserInteractionEnabled 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.presentationData = presentationData
self.archivedStickerPacks = archivedStickerPacks self.archivedStickerPacks = archivedStickerPacks
@ -139,7 +139,7 @@ private final class ArchivedStickersNoticeAlertContentNode: AlertContentNode {
index += 1 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) self.enqueueTransition(transition)
} }
@ -304,7 +304,7 @@ public func archivedStickerPacksNoticeController(context: AccountContext, archiv
let disposable = MetaDisposable() 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?() dismissImpl?()
})]) })])

View File

@ -1754,12 +1754,19 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
Queue.mainQueue().after(1.0, { Queue.mainQueue().after(1.0, {
let _ = ( let _ = (
self.context.engine.data.get(TelegramEngine.EngineData.Item.Notices.Notice(key: ApplicationSpecificNotice.forcedPasswordSetupKey())) self.context.engine.data.get(
|> map { entry -> Int32? in TelegramEngine.EngineData.Item.Peer.Peer(id: self.context.account.peerId),
return entry?.get(ApplicationSpecificCounterNotice.self)?.value 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 |> deliverOnMainQueue
).start(next: { [weak self] value in ).start(next: { [weak self] phoneNumber, value in
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
@ -1772,7 +1779,8 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
title: strongSelf.presentationData.strings.ForcedPasswordSetup_Intro_Title, title: strongSelf.presentationData.strings.ForcedPasswordSetup_Intro_Title,
text: strongSelf.presentationData.strings.ForcedPasswordSetup_Intro_Text, text: strongSelf.presentationData.strings.ForcedPasswordSetup_Intro_Text,
actionText: strongSelf.presentationData.strings.ForcedPasswordSetup_Intro_Action, 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 controller.dismissConfirmation = { [weak controller] f in
guard let strongSelf = self, let controller = controller else { guard let strongSelf = self, let controller = controller else {

View File

@ -13,6 +13,7 @@ import SearchUI
import ContextUI import ContextUI
import AnimationCache import AnimationCache
import MultiAnimationRenderer import MultiAnimationRenderer
import TelegramUIPreferences
public enum ChatListContainerNodeFilter: Equatable { public enum ChatListContainerNodeFilter: Equatable {
case all case all
@ -648,13 +649,26 @@ public final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDele
return (state, filterId) 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 { if self.controlsHistoryPreload, case .chatList(groupId: .root) = self.location {
self.context.account.viewTracker.chatListPreloadItems.set(combineLatest(queue: .mainQueue(), self.context.account.viewTracker.chatListPreloadItems.set(combineLatest(queue: .mainQueue(),
context.sharedContext.hasOngoingCall.get(), context.sharedContext.hasOngoingCall.get(),
itemNode.listNode.preloadItems.get() itemNode.listNode.preloadItems.get(),
enablePreload
) )
|> map { hasOngoingCall, preloadItems -> Set<ChatHistoryPreloadItem> in |> map { hasOngoingCall, preloadItems, enablePreload -> Set<ChatHistoryPreloadItem> in
if hasOngoingCall { if hasOngoingCall || !enablePreload {
return Set() return Set()
} else { } else {
return Set(preloadItems) return Set(preloadItems)

View File

@ -675,7 +675,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
animationCache: context.animationCache, animationCache: context.animationCache,
animationRenderer: context.animationRenderer, animationRenderer: context.animationRenderer,
content: titleTopicIconContent, content: titleTopicIconContent,
isVisibleForAnimations: currentNode?.visibilityStatus ?? false, isVisibleForAnimations: (currentNode?.visibilityStatus ?? false) && context.sharedContext.energyUsageSettings.loopEmoji,
action: nil action: nil
) )
@ -1318,7 +1318,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
if isKnown { if isKnown {
let photo = personalPhoto ?? profilePhoto 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 let videoNode: AvatarVideoNode
if let current = strongSelf.avatarVideoNode { if let current = strongSelf.avatarVideoNode {
videoNode = current videoNode = current
@ -2788,7 +2788,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
animationCache: item.interaction.animationCache, animationCache: item.interaction.animationCache,
animationRenderer: item.interaction.animationRenderer, animationRenderer: item.interaction.animationRenderer,
content: avatarIconContent, content: avatarIconContent,
isVisibleForAnimations: strongSelf.visibilityStatus, isVisibleForAnimations: strongSelf.visibilityStatus && item.context.sharedContext.energyUsageSettings.loopEmoji,
action: nil action: nil
) )
strongSelf.avatarIconComponent = avatarIconComponent strongSelf.avatarIconComponent = avatarIconComponent
@ -3285,7 +3285,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
animationCache: item.interaction.animationCache, animationCache: item.interaction.animationCache,
animationRenderer: item.interaction.animationRenderer, animationRenderer: item.interaction.animationRenderer,
content: currentCredibilityIconContent, content: currentCredibilityIconContent,
isVisibleForAnimations: strongSelf.visibilityStatus, isVisibleForAnimations: strongSelf.visibilityStatus && item.context.sharedContext.energyUsageSettings.loopEmoji,
action: nil action: nil
) )
strongSelf.credibilityIconComponent = credibilityIconComponent strongSelf.credibilityIconComponent = credibilityIconComponent

View File

@ -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.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() { func reset() {

View File

@ -73,6 +73,7 @@ private enum DebugControllerEntry: ItemListNodeEntry {
case crashOnSlowQueries(PresentationTheme, Bool) case crashOnSlowQueries(PresentationTheme, Bool)
case clearTips(PresentationTheme) case clearTips(PresentationTheme)
case resetTranslationStates(PresentationTheme) case resetTranslationStates(PresentationTheme)
case resetNotifications
case crash(PresentationTheme) case crash(PresentationTheme)
case resetData(PresentationTheme) case resetData(PresentationTheme)
case resetDatabase(PresentationTheme) case resetDatabase(PresentationTheme)
@ -116,7 +117,7 @@ private enum DebugControllerEntry: ItemListNodeEntry {
return DebugControllerSection.logging.rawValue return DebugControllerSection.logging.rawValue
case .enableRaiseToSpeak, .keepChatNavigationStack, .skipReadHistory, .crashOnSlowQueries: case .enableRaiseToSpeak, .keepChatNavigationStack, .skipReadHistory, .crashOnSlowQueries:
return DebugControllerSection.experiments.rawValue 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 return DebugControllerSection.experiments.rawValue
case .preferredVideoCodec: case .preferredVideoCodec:
return DebugControllerSection.videoExperiments.rawValue return DebugControllerSection.videoExperiments.rawValue
@ -167,58 +168,60 @@ private enum DebugControllerEntry: ItemListNodeEntry {
return 17 return 17
case .resetTranslationStates: case .resetTranslationStates:
return 18 return 18
case .crash: case .resetNotifications:
return 19 return 19
case .resetData: case .crash:
return 20 return 20
case .resetDatabase: case .resetData:
return 21 return 21
case .resetDatabaseAndCache: case .resetDatabase:
return 22 return 22
case .resetHoles: case .resetDatabaseAndCache:
return 23 return 23
case .reindexUnread: case .resetHoles:
return 24 return 24
case .resetCacheIndex: case .reindexUnread:
return 25 return 25
case .reindexCache: case .resetCacheIndex:
return 26 return 26
case .resetBiometricsData: case .reindexCache:
return 27 return 27
case .resetWebViewCache: case .resetBiometricsData:
return 28 return 28
case .optimizeDatabase: case .resetWebViewCache:
return 29 return 29
case .photoPreview: case .optimizeDatabase:
return 30 return 30
case .knockoutWallpaper: case .photoPreview:
return 31 return 31
case .experimentalCompatibility: case .knockoutWallpaper:
return 32 return 32
case .enableDebugDataDisplay: case .experimentalCompatibility:
return 33 return 33
case .acceleratedStickers: case .enableDebugDataDisplay:
return 34 return 34
case .experimentalBackground: case .acceleratedStickers:
return 35 return 35
case .inlineForums: case .experimentalBackground:
return 36 return 36
case .localTranscription: case .inlineForums:
return 37 return 37
case .enableReactionOverrides: case .localTranscription:
return 38 return 38
case .restorePurchases: case .enableReactionOverrides:
return 39 return 39
case .playerEmbedding: case .restorePurchases:
return 40 return 40
case .playlistPlayback: case .playerEmbedding:
return 41 return 41
case .enableQuickReactionSwitch: case .playlistPlayback:
return 42 return 42
case .voiceConference: case .enableQuickReactionSwitch:
return 43 return 43
case .voiceConference:
return 44
case let .preferredVideoCodec(index, _, _, _): case let .preferredVideoCodec(index, _, _, _):
return 44 + index return 45 + index
case .disableVideoAspectScaling: case .disableVideoAspectScaling:
return 100 return 100
case .enableVoipTcp: case .enableVoipTcp:
@ -952,6 +955,15 @@ private enum DebugControllerEntry: ItemListNodeEntry {
]).start() ]).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: case .crash:
return ItemListActionItem(presentationData: presentationData, title: "Crash", kind: .generic, alignment: .natural, sectionId: self.section, style: .blocks, action: { return ItemListActionItem(presentationData: presentationData, title: "Crash", kind: .generic, alignment: .natural, sectionId: self.section, style: .blocks, action: {
preconditionFailure() preconditionFailure()
@ -1340,6 +1352,7 @@ private func debugControllerEntries(sharedContext: SharedAccountContext, present
if isMainApp { if isMainApp {
entries.append(.clearTips(presentationData.theme)) entries.append(.clearTips(presentationData.theme))
entries.append(.resetTranslationStates(presentationData.theme)) entries.append(.resetTranslationStates(presentationData.theme))
entries.append(.resetNotifications)
} }
entries.append(.crash(presentationData.theme)) entries.append(.crash(presentationData.theme))
entries.append(.resetData(presentationData.theme)) entries.append(.resetData(presentationData.theme))

View File

@ -14,10 +14,6 @@ public enum DeviceMetrics: CaseIterable, Equatable {
var cpuCount: UInt32 = 0 var cpuCount: UInt32 = 0
sysctlbyname("hw.ncpu", &cpuCount, &length, nil, 0) sysctlbyname("hw.ncpu", &cpuCount, &length, nil, 0)
#if DEBUG
cpuCount = 2
#endif
self.isGraphicallyCapable = cpuCount >= 6 self.isGraphicallyCapable = cpuCount >= 6
} }
} }

View File

@ -107,7 +107,7 @@ final class TrendingTopItemNode: ASDisplayNode {
} }
if let placeholderNode = self.placeholderNode, let file = self.file { 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)
} }
} }

View File

@ -76,7 +76,7 @@ final class InstantPageImageNode: ASDisplayNode, InstantPageNode {
let imageReference = ImageMediaReference.webPage(webPage: WebpageReference(webPage), media: image) let imageReference = ImageMediaReference.webPage(webPage: WebpageReference(webPage), media: image)
self.imageNode.setSignal(chatMessagePhoto(postbox: context.account.postbox, userLocation: sourceLocation.userLocation, photoReference: imageReference)) 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()) 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 { } else if let file = media.media as? TelegramMediaFile {
let fileReference = FileMediaReference.webPage(webPage: WebpageReference(webPage), media: file) let fileReference = FileMediaReference.webPage(webPage: WebpageReference(webPage), media: file)
if file.mimeType.hasPrefix("image/") { 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() _ = freeMediaFileInteractiveFetched(account: context.account, userLocation: sourceLocation.userLocation, fileReference: fileReference).start()
} }
self.imageNode.setSignal(instantPageImageFile(account: context.account, userLocation: sourceLocation.userLocation, fileReference: fileReference, fetched: true)) self.imageNode.setSignal(instantPageImageFile(account: context.account, userLocation: sourceLocation.userLocation, fileReference: fileReference, fetched: true))

View File

@ -12,6 +12,7 @@ import StickerResources
import AnimatedStickerNode import AnimatedStickerNode
import TelegramAnimatedStickerNode import TelegramAnimatedStickerNode
import ShimmerEffect import ShimmerEffect
import AccountContext
public struct ItemListStickerPackItemEditing: Equatable { public struct ItemListStickerPackItemEditing: Equatable {
public var editable: Bool public var editable: Bool
@ -38,7 +39,7 @@ public enum ItemListStickerPackItemControl: Equatable {
public final class ItemListStickerPackItem: ListViewItem, ItemListItem { public final class ItemListStickerPackItem: ListViewItem, ItemListItem {
let presentationData: ItemListPresentationData let presentationData: ItemListPresentationData
let account: Account let context: AccountContext
let packInfo: StickerPackCollectionInfo let packInfo: StickerPackCollectionInfo
let itemCount: String let itemCount: String
let topItem: StickerPackItem? let topItem: StickerPackItem?
@ -54,9 +55,9 @@ public final class ItemListStickerPackItem: ListViewItem, ItemListItem {
let removePack: () -> Void let removePack: () -> Void
let toggleSelected: () -> 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.presentationData = presentationData
self.account = account self.context = context
self.packInfo = packInfo self.packInfo = packInfo
self.itemCount = itemCount self.itemCount = itemCount
self.topItem = topItem self.topItem = topItem
@ -506,18 +507,18 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode {
if fileUpdated { if fileUpdated {
imageApply = makeImageLayout(TransformImageArguments(corners: ImageCorners(), imageSize: stillImageSize, boundingSize: stillImageSize, intrinsicInsets: UIEdgeInsets())) 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, _): case let .animated(resource, dimensions, _):
imageSize = dimensions.cgSize.aspectFitted(imageBoundingSize) imageSize = dimensions.cgSize.aspectFitted(imageBoundingSize)
if fileUpdated { if fileUpdated {
imageApply = makeImageLayout(TransformImageArguments(corners: ImageCorners(), imageSize: imageBoundingSize, boundingSize: imageBoundingSize, intrinsicInsets: UIEdgeInsets())) 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 { 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 { } else {
updatedImageSignal = .single({ _ in return nil }) updatedImageSignal = .single({ _ in return nil })
@ -768,7 +769,7 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode {
strongSelf.animationNode = animationNode strongSelf.animationNode = animationNode
strongSelf.addSubnode(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.visibility = strongSelf.visibility != .none && item.playAnimatedStickers
animationNode.isHidden = !item.playAnimatedStickers animationNode.isHidden = !item.playAnimatedStickers
@ -794,7 +795,7 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode {
placeholderNode.frame = imageFrame 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 { if let updatedImageSignal = updatedImageSignal {

View File

@ -35,7 +35,7 @@ public enum TwoFactorDataInputMode {
case authorized case authorized
} }
case password(doneText: String) case password(phoneNumber: String?, doneText: String)
case passwordRecoveryEmail(emailPattern: String, mode: PasswordRecoveryEmailMode, doneText: String) case passwordRecoveryEmail(emailPattern: String, mode: PasswordRecoveryEmailMode, doneText: String)
case passwordRecovery(recovery: Recovery, doneText: String) case passwordRecovery(recovery: Recovery, doneText: String)
case emailAddress(password: String, hint: String, 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) { public override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated) super.viewWillAppear(animated)
if case .rememberPassword = self.mode { switch self.mode {
case .rememberPassword, .password:
(self.displayNode as? TwoFactorDataInputScreenNode)?.focus() (self.displayNode as? TwoFactorDataInputScreenNode)?.focus()
default:
break
} }
} }
@ -110,7 +113,7 @@ public final class TwoFactorDataInputScreen: ViewController {
return return
} }
switch strongSelf.mode { switch strongSelf.mode {
case let .password(doneText): case let .password(_, doneText):
let values = (strongSelf.displayNode as! TwoFactorDataInputScreenNode).inputText let values = (strongSelf.displayNode as! TwoFactorDataInputScreenNode).inputText
if values.count != 2 { if values.count != 2 {
return return
@ -924,7 +927,7 @@ public final class TwoFactorDataInputScreen: ViewController {
} }
private enum TwoFactorDataInputTextNodeType { private enum TwoFactorDataInputTextNodeType {
case password(confirmation: Bool) case password(phoneNumber: String?, confirmation: Bool)
case email case email
case code case code
case hint case hint
@ -984,6 +987,7 @@ private final class TwoFactorDataInputTextNode: ASDisplayNode, UITextFieldDelega
private let toggleTextHidden: (TwoFactorDataInputTextNode) -> Void private let toggleTextHidden: (TwoFactorDataInputTextNode) -> Void
private let backgroundNode: ASImageNode private let backgroundNode: ASImageNode
private var shadowInputNode: TextFieldNode?
private let inputNode: TextFieldNode private let inputNode: TextFieldNode
private let hideButtonNode: HighlightableButtonNode private let hideButtonNode: HighlightableButtonNode
private let clearButtonNode: HighlightableButtonNode private let clearButtonNode: HighlightableButtonNode
@ -1068,7 +1072,7 @@ private final class TwoFactorDataInputTextNode: ASDisplayNode, UITextFieldDelega
self.hideButtonNode = HighlightableButtonNode() self.hideButtonNode = HighlightableButtonNode()
switch mode { switch mode {
case let .password(confirmation): case let .password(phoneNumber, confirmation):
self.inputNode.textField.keyboardType = .default self.inputNode.textField.keyboardType = .default
self.inputNode.textField.isSecureTextEntry = true self.inputNode.textField.isSecureTextEntry = true
if confirmation { if confirmation {
@ -1076,29 +1080,68 @@ private final class TwoFactorDataInputTextNode: ASDisplayNode, UITextFieldDelega
} else { } else {
self.inputNode.textField.returnKeyType = .next 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 self.hideButtonNode.isHidden = confirmation
case .email: case .email:
self.inputNode.textField.keyboardType = .emailAddress self.inputNode.textField.keyboardType = .emailAddress
self.inputNode.textField.returnKeyType = .done self.inputNode.textField.returnKeyType = .done
self.hideButtonNode.isHidden = true 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: case .code:
self.inputNode.textField.keyboardType = .numberPad self.inputNode.textField.keyboardType = .numberPad
self.inputNode.textField.returnKeyType = .done self.inputNode.textField.returnKeyType = .done
self.hideButtonNode.isHidden = true 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: case .hint:
self.inputNode.textField.keyboardType = .asciiCapable self.inputNode.textField.keyboardType = .asciiCapable
self.inputNode.textField.returnKeyType = .done self.inputNode.textField.returnKeyType = .done
self.hideButtonNode.isHidden = true 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.inputNode.textField.keyboardAppearance = theme.rootController.keyboardColor.keyboardAppearance
self.hideButtonNode.setImage(generateTextHiddenImage(color: theme.list.freePlainInputField.controlColor, on: false), for: []) self.hideButtonNode.setImage(generateTextHiddenImage(color: theme.list.freePlainInputField.controlColor, on: false), for: [])
@ -1110,6 +1153,10 @@ private final class TwoFactorDataInputTextNode: ASDisplayNode, UITextFieldDelega
super.init() super.init()
self.addSubnode(self.backgroundNode) self.addSubnode(self.backgroundNode)
if let shadowInputNode = self.shadowInputNode {
shadowInputNode.alpha = 0.001
self.addSubnode(shadowInputNode)
}
self.addSubnode(self.inputNode) self.addSubnode(self.inputNode)
self.addSubnode(self.hideButtonNode) self.addSubnode(self.hideButtonNode)
@ -1179,6 +1226,10 @@ private final class TwoFactorDataInputTextNode: ASDisplayNode, UITextFieldDelega
let leftInset: CGFloat = 16.0 let leftInset: CGFloat = 16.0
let rightInset: CGFloat = 38.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.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.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))) 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)? var toggleTextHidden: ((TwoFactorDataInputTextNode) -> Void)?
switch mode { switch mode {
case .password: case let .password(phoneNumber, _):
title = presentationData.strings.TwoFactorSetup_Password_Title title = presentationData.strings.TwoFactorSetup_Password_Title
text = NSAttributedString(string: "", font: Font.regular(16.0), textColor: presentationData.theme.list.itemPrimaryTextColor) text = NSAttributedString(string: "", font: Font.regular(16.0), textColor: presentationData.theme.list.itemPrimaryTextColor)
buttonText = presentationData.strings.TwoFactorSetup_Password_Action buttonText = presentationData.strings.TwoFactorSetup_Password_Action
@ -1307,7 +1358,7 @@ private final class TwoFactorDataInputScreenNode: ViewControllerTracingNode, UIS
changeEmailActionText = "" changeEmailActionText = ""
resendCodeActionText = "" resendCodeActionText = ""
inputNodes = [ 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) focusUpdated?(node, focused)
}, next: { node in }, next: { node in
next?(node) next?(node)
@ -1316,7 +1367,7 @@ private final class TwoFactorDataInputScreenNode: ViewControllerTracingNode, UIS
}, toggleTextHidden: { node in }, toggleTextHidden: { node in
toggleTextHidden?(node) 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) focusUpdated?(node, focused)
}, next: { node in }, next: { node in
next?(node) next?(node)
@ -1334,7 +1385,7 @@ private final class TwoFactorDataInputScreenNode: ViewControllerTracingNode, UIS
changeEmailActionText = "" changeEmailActionText = ""
resendCodeActionText = "" resendCodeActionText = ""
inputNodes = [ 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) focusUpdated?(node, focused)
}, next: { node in }, next: { node in
next?(node) next?(node)
@ -1343,7 +1394,7 @@ private final class TwoFactorDataInputScreenNode: ViewControllerTracingNode, UIS
}, toggleTextHidden: { node in }, toggleTextHidden: { node in
toggleTextHidden?(node) 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) focusUpdated?(node, focused)
}, next: { node in }, next: { node in
next?(node) next?(node)
@ -1453,7 +1504,7 @@ private final class TwoFactorDataInputScreenNode: ViewControllerTracingNode, UIS
changeEmailActionText = "" changeEmailActionText = ""
resendCodeActionText = "" resendCodeActionText = ""
inputNodes = [ 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) focusUpdated?(node, focused)
}, next: { node in }, next: { node in
next?(node) next?(node)

View File

@ -18,17 +18,20 @@ public enum TwoFactorAuthSplashMode {
public var text: String public var text: String
public var actionText: String public var actionText: String
public var doneText: String public var doneText: String
public var phoneNumber: String?
public init( public init(
title: String, title: String,
text: String, text: String,
actionText: String, actionText: String,
doneText: String doneText: String,
phoneNumber: String?
) { ) {
self.title = title self.title = title
self.text = text self.text = text
self.actionText = actionText self.actionText = actionText
self.doneText = doneText self.doneText = doneText
self.phoneNumber = phoneNumber
} }
} }
@ -100,7 +103,7 @@ public final class TwoFactorAuthSplashScreen: ViewController {
} }
switch strongSelf.mode { switch strongSelf.mode {
case let .intro(intro): 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)) }, presentation: strongSelf.navigationPresentation))
case .done, .remember: case .done, .remember:
guard let navigationController = strongSelf.navigationController as? NavigationController else { guard let navigationController = strongSelf.navigationController as? NavigationController else {

View File

@ -13,15 +13,15 @@ import StickerPackPreviewUI
import ItemListStickerPackItem import ItemListStickerPackItem
private final class GroupStickerPackSetupControllerArguments { private final class GroupStickerPackSetupControllerArguments {
let account: Account let context: AccountContext
let selectStickerPack: (StickerPackCollectionInfo) -> Void let selectStickerPack: (StickerPackCollectionInfo) -> Void
let openStickerPack: (StickerPackCollectionInfo) -> Void let openStickerPack: (StickerPackCollectionInfo) -> Void
let updateSearchText: (String) -> Void let updateSearchText: (String) -> Void
let openStickersBot: () -> Void let openStickersBot: () -> Void
init(account: Account, selectStickerPack: @escaping (StickerPackCollectionInfo) -> Void, openStickerPack: @escaping (StickerPackCollectionInfo) -> Void, updateSearchText: @escaping (String) -> Void, openStickersBot: @escaping () -> Void) { init(context: AccountContext, selectStickerPack: @escaping (StickerPackCollectionInfo) -> Void, openStickerPack: @escaping (StickerPackCollectionInfo) -> Void, updateSearchText: @escaping (String) -> Void, openStickersBot: @escaping () -> Void) {
self.account = account self.context = context
self.selectStickerPack = selectStickerPack self.selectStickerPack = selectStickerPack
self.openStickerPack = openStickerPack self.openStickerPack = openStickerPack
self.updateSearchText = updateSearchText self.updateSearchText = updateSearchText
@ -218,7 +218,7 @@ private enum GroupStickerPackEntry: ItemListNodeEntry {
case let .packsTitle(_, text): case let .packsTitle(_, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .pack(_, _, _, info, topItem, count, playAnimatedStickers, selected): 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 { if selected {
arguments.openStickerPack(info) arguments.openStickerPack(info)
} else { } else {
@ -230,7 +230,7 @@ private enum GroupStickerPackEntry: ItemListNodeEntry {
}, toggleSelected: { }, toggleSelected: {
}) })
case let .currentPack(_, theme, strings, content): 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 { if case let .found(packInfo, _, _) = content {
arguments.openStickerPack(packInfo) arguments.openStickerPack(packInfo)
} }
@ -385,7 +385,7 @@ public func groupStickerPackSetupController(context: AccountContext, updatedPres
var presentStickerPackController: ((StickerPackCollectionInfo) -> Void)? 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) searchText.set(info.shortName)
}, openStickerPack: { info in }, openStickerPack: { info in
presentStickerPackController?(info) presentStickerPackController?(info)

View File

@ -268,7 +268,7 @@ private class StickerNode: ASDisplayNode {
if self.placeholderNode.supernode != nil { if self.placeholderNode.supernode != nil {
let placeholderFrame = CGRect(origin: CGPoint(x: -10.0, y: 0.0), size: imageSize) let placeholderFrame = CGRect(origin: CGPoint(x: -10.0, y: 0.0), size: imageSize)
let thumbnailDimensions = PixelDimensions(width: 512, height: 512) 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 self.placeholderNode.frame = placeholderFrame
} }
} }

View File

@ -735,9 +735,9 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
} }
} }
#if DEBUG if !self.context.sharedContext.energyUsageSettings.loopEmoji {
loopIdle = true loopIdle = false
#endif }
var validIndices = Set<Int>() var validIndices = Set<Int>()
var nextX: CGFloat = sideInset var nextX: CGFloat = sideInset

View File

@ -33,12 +33,13 @@ private final class DataAndStorageControllerArguments {
let toggleRaiseToListen: (Bool) -> Void let toggleRaiseToListen: (Bool) -> Void
let toggleAutoplayGifs: (Bool) -> Void let toggleAutoplayGifs: (Bool) -> Void
let toggleAutoplayVideos: (Bool) -> Void let toggleAutoplayVideos: (Bool) -> Void
let openEnergySavingSettings: () -> Void
let toggleDownloadInBackground: (Bool) -> Void let toggleDownloadInBackground: (Bool) -> Void
let openBrowserSelection: () -> Void let openBrowserSelection: () -> Void
let openIntents: () -> Void let openIntents: () -> Void
let toggleEnableSensitiveContent: (Bool) -> 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.openStorageUsage = openStorageUsage
self.openNetworkUsage = openNetworkUsage self.openNetworkUsage = openNetworkUsage
self.openProxy = openProxy self.openProxy = openProxy
@ -51,6 +52,7 @@ private final class DataAndStorageControllerArguments {
self.toggleRaiseToListen = toggleRaiseToListen self.toggleRaiseToListen = toggleRaiseToListen
self.toggleAutoplayGifs = toggleAutoplayGifs self.toggleAutoplayGifs = toggleAutoplayGifs
self.toggleAutoplayVideos = toggleAutoplayVideos self.toggleAutoplayVideos = toggleAutoplayVideos
self.openEnergySavingSettings = openEnergySavingSettings
self.toggleDownloadInBackground = toggleDownloadInBackground self.toggleDownloadInBackground = toggleDownloadInBackground
self.openBrowserSelection = openBrowserSelection self.openBrowserSelection = openBrowserSelection
self.openIntents = openIntents self.openIntents = openIntents
@ -64,6 +66,7 @@ private enum DataAndStorageSection: Int32 {
case autoSave case autoSave
case backgroundDownload case backgroundDownload
case autoPlay case autoPlay
case energySaving
case voiceCalls case voiceCalls
case other case other
case connection case connection
@ -107,6 +110,9 @@ private enum DataAndStorageEntry: ItemListNodeEntry {
case autoplayHeader(PresentationTheme, String) case autoplayHeader(PresentationTheme, String)
case autoplayGifs(PresentationTheme, String, Bool) case autoplayGifs(PresentationTheme, String, Bool)
case autoplayVideos(PresentationTheme, String, Bool) case autoplayVideos(PresentationTheme, String, Bool)
case energySaving
case useLessVoiceData(PresentationTheme, String, Bool) case useLessVoiceData(PresentationTheme, String, Bool)
case useLessVoiceDataInfo(PresentationTheme, String) case useLessVoiceDataInfo(PresentationTheme, String)
case otherHeader(PresentationTheme, String) case otherHeader(PresentationTheme, String)
@ -135,6 +141,8 @@ private enum DataAndStorageEntry: ItemListNodeEntry {
return DataAndStorageSection.voiceCalls.rawValue return DataAndStorageSection.voiceCalls.rawValue
case .autoplayHeader, .autoplayGifs, .autoplayVideos: case .autoplayHeader, .autoplayGifs, .autoplayVideos:
return DataAndStorageSection.autoPlay.rawValue return DataAndStorageSection.autoPlay.rawValue
case .energySaving:
return DataAndStorageSection.energySaving.rawValue
case .otherHeader, .shareSheet, .saveEditedPhotos, .openLinksIn, .pauseMusicOnRecording, .raiseToListen, .raiseToListenInfo: case .otherHeader, .shareSheet, .saveEditedPhotos, .openLinksIn, .pauseMusicOnRecording, .raiseToListen, .raiseToListenInfo:
return DataAndStorageSection.other.rawValue return DataAndStorageSection.other.rawValue
case .connectionHeader, .connectionProxy: case .connectionHeader, .connectionProxy:
@ -178,10 +186,12 @@ private enum DataAndStorageEntry: ItemListNodeEntry {
return 26 return 26
case .autoplayVideos: case .autoplayVideos:
return 27 return 27
case .otherHeader: case .energySaving:
return 28 return 28
case .shareSheet: case .otherHeader:
return 29 return 29
case .shareSheet:
return 30
case .saveEditedPhotos: case .saveEditedPhotos:
return 31 return 31
case .openLinksIn: case .openLinksIn:
@ -275,6 +285,12 @@ private enum DataAndStorageEntry: ItemListNodeEntry {
} else { } else {
return false return false
} }
case .energySaving:
if case .energySaving = rhs {
return true
} else {
return false
}
case let .useLessVoiceData(lhsTheme, lhsText, lhsValue): case let .useLessVoiceData(lhsTheme, lhsText, lhsValue):
if case let .useLessVoiceData(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue { if case let .useLessVoiceData(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
return true 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 return ItemListSwitchItem(presentationData: presentationData, title: text, value: value, sectionId: self.section, style: .blocks, updated: { value in
arguments.toggleAutoplayVideos(value) arguments.toggleAutoplayVideos(value)
}, tag: DataAndStorageEntryTag.autoplayVideos) }, 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): case let .useLessVoiceData(_, text, value):
return ItemListSwitchItem(presentationData: presentationData, title: text, value: value, sectionId: self.section, style: .blocks, updated: { value in return ItemListSwitchItem(presentationData: presentationData, title: text, value: value, sectionId: self.section, style: .blocks, updated: { value in
arguments.toggleVoiceUseLessData(value) 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(.autoplayGifs(presentationData.theme, presentationData.strings.ChatSettings_AutoPlayGifs, data.automaticMediaDownloadSettings.autoplayGifs))
entries.append(.autoplayVideos(presentationData.theme, presentationData.strings.ChatSettings_AutoPlayVideos, data.automaticMediaDownloadSettings.autoplayVideos)) entries.append(.autoplayVideos(presentationData.theme, presentationData.strings.ChatSettings_AutoPlayVideos, data.automaticMediaDownloadSettings.autoplayVideos))
entries.append(.energySaving)
entries.append(.otherHeader(presentationData.theme, presentationData.strings.ChatSettings_Other)) entries.append(.otherHeader(presentationData.theme, presentationData.strings.ChatSettings_Other))
if #available(iOSApplicationExtension 13.2, iOS 13.2, *) { if #available(iOSApplicationExtension 13.2, iOS 13.2, *) {
entries.append(.shareSheet(presentationData.theme, presentationData.strings.ChatSettings_IntentsSettings)) entries.append(.shareSheet(presentationData.theme, presentationData.strings.ChatSettings_IntentsSettings))
@ -922,6 +945,8 @@ public func dataAndStorageController(context: AccountContext, focusOnItemTag: Da
settings.autoplayVideos = value settings.autoplayVideos = value
return settings return settings
}).start() }).start()
}, openEnergySavingSettings: {
pushControllerImpl?(energySavingSettingsScreen(context: context))
}, toggleDownloadInBackground: { value in }, toggleDownloadInBackground: { value in
let _ = updateMediaDownloadSettingsInteractively(accountManager: context.sharedContext.accountManager, { settings in let _ = updateMediaDownloadSettingsInteractively(accountManager: context.sharedContext.accountManager, { settings in
var settings = settings var settings = settings

View File

@ -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
}

View File

@ -248,7 +248,8 @@ public func deleteAccountOptionsController(context: AccountContext, navigationCo
title: presentationData.strings.TwoFactorSetup_Intro_Title, title: presentationData.strings.TwoFactorSetup_Intro_Title,
text: presentationData.strings.TwoFactorSetup_Intro_Text, text: presentationData.strings.TwoFactorSetup_Intro_Text,
actionText: presentationData.strings.TwoFactorSetup_Intro_Action, actionText: presentationData.strings.TwoFactorSetup_Intro_Action,
doneText: presentationData.strings.TwoFactorSetup_Done_Action doneText: presentationData.strings.TwoFactorSetup_Done_Action,
phoneNumber: nil
))) )))
replaceTopControllerImpl?(controller, false) replaceTopControllerImpl?(controller, false)

View File

@ -944,28 +944,37 @@ public func privacyAndSecurityController(
} }
}) })
}, openTwoStepVerification: { data in }, openTwoStepVerification: { data in
if let data = data { let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId))
switch data { |> deliverOnMainQueue).start(next: { peer in
case .set: if let data = data {
break switch data {
case let .notSet(pendingEmail): case .set:
if pendingEmail == nil { break
let presentationData = context.sharedContext.currentPresentationData.with { $0 } case let .notSet(pendingEmail):
let controller = TwoFactorAuthSplashScreen(sharedContext: context.sharedContext, engine: .authorized(context.engine), mode: .intro(.init( if pendingEmail == nil {
title: presentationData.strings.TwoFactorSetup_Intro_Title, var phoneNumber: String?
text: presentationData.strings.TwoFactorSetup_Intro_Text, if case let .user(user) = peer {
actionText: presentationData.strings.TwoFactorSetup_Intro_Action, phoneNumber = user.phone
doneText: presentationData.strings.TwoFactorSetup_Done_Action }
)))
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) pushControllerImpl?(controller, true)
return return
}
} }
} }
}
let controller = twoStepVerificationUnlockSettingsController(context: context, mode: .access(intro: false, data: data.flatMap({ Signal<TwoStepVerificationUnlockSettingsControllerData, NoError>.single(.access(configuration: $0)) }))) let controller = twoStepVerificationUnlockSettingsController(context: context, mode: .access(intro: false, data: data.flatMap({ Signal<TwoStepVerificationUnlockSettingsControllerData, NoError>.single(.access(configuration: $0)) })))
pushControllerImpl?(controller, true) pushControllerImpl?(controller, true)
})
}, openActiveSessions: { }, openActiveSessions: {
pushControllerImpl?(recentSessionsController(context: context, activeSessionsContext: activeSessionsContext, webSessionsContext: webSessionsContext, websitesOnly: true), true) pushControllerImpl?(recentSessionsController(context: context, activeSessionsContext: activeSessionsContext, webSessionsContext: webSessionsContext, websitesOnly: true), true)
}, toggleArchiveAndMuteNonContacts: { archiveValue in }, toggleArchiveAndMuteNonContacts: { archiveValue in

View File

@ -21,7 +21,8 @@ public func makeSetupTwoFactorAuthController(context: AccountContext) -> ViewCon
title: presentationData.strings.TwoFactorSetup_Intro_Title, title: presentationData.strings.TwoFactorSetup_Intro_Title,
text: presentationData.strings.TwoFactorSetup_Intro_Text, text: presentationData.strings.TwoFactorSetup_Intro_Text,
actionText: presentationData.strings.TwoFactorSetup_Intro_Action, actionText: presentationData.strings.TwoFactorSetup_Intro_Action,
doneText: presentationData.strings.TwoFactorSetup_Done_Action doneText: presentationData.strings.TwoFactorSetup_Done_Action,
phoneNumber: nil
))) )))
return controller return controller
} }

View File

@ -21,15 +21,15 @@ public enum ArchivedStickerPacksControllerMode {
} }
private final class ArchivedStickerPacksControllerArguments { private final class ArchivedStickerPacksControllerArguments {
let account: Account let context: AccountContext
let openStickerPack: (StickerPackCollectionInfo) -> Void let openStickerPack: (StickerPackCollectionInfo) -> Void
let setPackIdWithRevealedOptions: (ItemCollectionId?, ItemCollectionId?) -> Void let setPackIdWithRevealedOptions: (ItemCollectionId?, ItemCollectionId?) -> Void
let addPack: (StickerPackCollectionInfo) -> Void let addPack: (StickerPackCollectionInfo) -> Void
let removePack: (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) { init(context: AccountContext, openStickerPack: @escaping (StickerPackCollectionInfo) -> Void, setPackIdWithRevealedOptions: @escaping (ItemCollectionId?, ItemCollectionId?) -> Void, addPack: @escaping (StickerPackCollectionInfo) -> Void, removePack: @escaping (StickerPackCollectionInfo) -> Void) {
self.account = account self.context = context
self.openStickerPack = openStickerPack self.openStickerPack = openStickerPack
self.setPackIdWithRevealedOptions = setPackIdWithRevealedOptions self.setPackIdWithRevealedOptions = setPackIdWithRevealedOptions
self.addPack = addPack self.addPack = addPack
@ -135,7 +135,7 @@ private enum ArchivedStickerPacksEntry: ItemListNodeEntry {
case let .info(_, text): case let .info(_, text):
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section) return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section)
case let .pack(_, _, _, info, topItem, count, animatedStickers, enabled, editing): 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) arguments.openStickerPack(info)
}, setPackIdWithRevealedOptions: { current, previous in }, setPackIdWithRevealedOptions: { current, previous in
arguments.setPackIdWithRevealedOptions(current, previous) arguments.setPackIdWithRevealedOptions(current, previous)
@ -264,7 +264,7 @@ public func archivedStickerPacksController(context: AccountContext, mode: Archiv
var presentStickerPackController: ((StickerPackCollectionInfo) -> Void)? var presentStickerPackController: ((StickerPackCollectionInfo) -> Void)?
let arguments = ArchivedStickerPacksControllerArguments(account: context.account, openStickerPack: { info in let arguments = ArchivedStickerPacksControllerArguments(context: context, openStickerPack: { info in
presentStickerPackController?(info) presentStickerPackController?(info)
}, setPackIdWithRevealedOptions: { packId, fromPackId in }, setPackIdWithRevealedOptions: { packId, fromPackId in
updateState { state in updateState { state in

View File

@ -13,13 +13,13 @@ import StickerPackPreviewUI
import ItemListStickerPackItem import ItemListStickerPackItem
private final class FeaturedStickerPacksControllerArguments { private final class FeaturedStickerPacksControllerArguments {
let account: Account let context: AccountContext
let openStickerPack: (StickerPackCollectionInfo) -> Void let openStickerPack: (StickerPackCollectionInfo) -> Void
let addPack: (StickerPackCollectionInfo) -> Void let addPack: (StickerPackCollectionInfo) -> Void
init(account: Account, openStickerPack: @escaping (StickerPackCollectionInfo) -> Void, addPack: @escaping (StickerPackCollectionInfo) -> Void) { init(context: AccountContext, openStickerPack: @escaping (StickerPackCollectionInfo) -> Void, addPack: @escaping (StickerPackCollectionInfo) -> Void) {
self.account = account self.context = context
self.openStickerPack = openStickerPack self.openStickerPack = openStickerPack
self.addPack = addPack self.addPack = addPack
} }
@ -102,7 +102,7 @@ private enum FeaturedStickerPacksEntry: ItemListNodeEntry {
let arguments = arguments as! FeaturedStickerPacksControllerArguments let arguments = arguments as! FeaturedStickerPacksControllerArguments
switch self { switch self {
case let .pack(_, _, _, info, unread, topItem, count, playAnimatedStickers, installed): 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) arguments.openStickerPack(info)
}, setPackIdWithRevealedOptions: { _, _ in }, setPackIdWithRevealedOptions: { _, _ in
}, addPack: { }, addPack: {
@ -168,7 +168,7 @@ public func featuredStickerPacksController(context: AccountContext) -> ViewContr
var presentStickerPackController: ((StickerPackCollectionInfo) -> Void)? var presentStickerPackController: ((StickerPackCollectionInfo) -> Void)?
let arguments = FeaturedStickerPacksControllerArguments(account: context.account, openStickerPack: { info in let arguments = FeaturedStickerPacksControllerArguments(context: context, openStickerPack: { info in
presentStickerPackController?(info) presentStickerPackController?(info)
}, addPack: { info in }, addPack: { info in
let _ = (context.engine.stickers.loadedStickerPack(reference: .id(id: info.id.id, accessHash: info.accessHash), forceActualized: false) let _ = (context.engine.stickers.loadedStickerPack(reference: .id(id: info.id.id, accessHash: info.accessHash), forceActualized: false)

View File

@ -451,7 +451,7 @@ private indirect enum InstalledStickerPacksEntry: ItemListNodeEntry {
case let .trendingPacksTitle(_, text): case let .trendingPacksTitle(_, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .trendingPack(_, _, _, info, topItem, count, animatedStickers, unread, installed): 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) arguments.openStickerPack(info)
}, setPackIdWithRevealedOptions: { _, _ in }, setPackIdWithRevealedOptions: { _, _ in
}, addPack: { }, addPack: {
@ -466,7 +466,7 @@ private indirect enum InstalledStickerPacksEntry: ItemListNodeEntry {
case let .packsTitle(_, text): case let .packsTitle(_, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .pack(_, _, _, info, topItem, count, animatedStickers, enabled, editing, selected): 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) arguments.openStickerPack(info)
}, setPackIdWithRevealedOptions: { current, previous in }, setPackIdWithRevealedOptions: { current, previous in
arguments.setPackIdWithRevealedOptions(current, previous) arguments.setPackIdWithRevealedOptions(current, previous)

View File

@ -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()) 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) 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 strongSelf.placeholderNode.frame = emojiFrame
} }

View File

@ -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()) 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) 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 self.placeholderNode.frame = emojiFrame
} }

View File

@ -90,6 +90,8 @@ public class StickerShimmerEffectNode: ASDisplayNode {
self.backdropNode = backdropNode self.backdropNode = backdropNode
self.insertSubnode(backdropNode, at: 0) self.insertSubnode(backdropNode, at: 0)
backdropNode.isHidden = self.effectNode.isHidden
self.effectNode.layer.compositingFilter = "screenBlendMode" self.effectNode.layer.compositingFilter = "screenBlendMode"
} }
@ -97,7 +99,7 @@ public class StickerShimmerEffectNode: ASDisplayNode {
self.effectNode.updateAbsoluteRect(rect, within: containerSize) 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 { if data == nil {
return return
} }
@ -112,13 +114,18 @@ public class StickerShimmerEffectNode: ASDisplayNode {
self.currentSize = size self.currentSize = size
self.backgroundNode.backgroundColor = foregroundColor 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 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 self.foregroundNode.image = nil
let maskView: UIImageView let maskView: UIImageView

View File

@ -13,6 +13,7 @@ import TextFormat
import AccountContext import AccountContext
import ContextUI import ContextUI
import StickerPeekUI import StickerPeekUI
import AccountContext
private struct StickerPackPreviewGridEntry: Comparable, Identifiable { private struct StickerPackPreviewGridEntry: Comparable, Identifiable {
let index: Int let index: Int
@ -26,8 +27,8 @@ private struct StickerPackPreviewGridEntry: Comparable, Identifiable {
return lhs.index < rhs.index return lhs.index < rhs.index
} }
func item(account: Account, interaction: StickerPackPreviewInteraction, theme: PresentationTheme) -> StickerPackPreviewGridItem { func item(context: AccountContext, interaction: StickerPackPreviewInteraction, theme: PresentationTheme) -> StickerPackPreviewGridItem {
return StickerPackPreviewGridItem(account: account, stickerItem: self.stickerItem, interaction: interaction, theme: theme, isPremium: false, isLocked: false, isEmpty: false) 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 insertions: [GridNodeInsertItem]
let updates: [GridNodeUpdateItem] 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) let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: previousList, rightList: list)
self.deletions = deleteIndices 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.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(account: account, interaction: interaction, theme: theme)) } 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) 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 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 self.currentItems = updatedItems
} }
} }

View File

@ -33,7 +33,7 @@ final class StickerPackPreviewInteraction {
} }
final class StickerPackPreviewGridItem: GridItem { final class StickerPackPreviewGridItem: GridItem {
let account: Account let context: AccountContext
let stickerItem: StickerPackItem? let stickerItem: StickerPackItem?
let interaction: StickerPackPreviewInteraction let interaction: StickerPackPreviewInteraction
let theme: PresentationTheme let theme: PresentationTheme
@ -43,8 +43,8 @@ final class StickerPackPreviewGridItem: GridItem {
let section: GridSection? = nil let section: GridSection? = nil
init(account: Account, stickerItem: StickerPackItem?, interaction: StickerPackPreviewInteraction, theme: PresentationTheme, isPremium: Bool, isLocked: Bool, isEmpty: Bool) { init(context: AccountContext, stickerItem: StickerPackItem?, interaction: StickerPackPreviewInteraction, theme: PresentationTheme, isPremium: Bool, isLocked: Bool, isEmpty: Bool) {
self.account = account self.context = context
self.stickerItem = stickerItem self.stickerItem = stickerItem
self.interaction = interaction self.interaction = interaction
self.theme = theme self.theme = theme
@ -55,7 +55,7 @@ final class StickerPackPreviewGridItem: GridItem {
func node(layout: GridNodeLayout, synchronousLoad: Bool) -> GridItemNode { func node(layout: GridNodeLayout, synchronousLoad: Bool) -> GridItemNode {
let node = StickerPackPreviewGridItemNode() 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 return node
} }
@ -64,14 +64,14 @@ final class StickerPackPreviewGridItem: GridItem {
assertionFailure() assertionFailure()
return 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) private let textFont = Font.regular(20.0)
final class StickerPackPreviewGridItemNode: GridItemNode { final class StickerPackPreviewGridItemNode: GridItemNode {
private var currentState: (Account, StickerPackItem?)? private var currentState: (AccountContext, StickerPackItem?)?
private var isLocked: Bool? private var isLocked: Bool?
private var isPremium: Bool? private var isPremium: Bool?
private var isEmpty: Bool? private var isEmpty: Bool?
@ -173,11 +173,11 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
} }
private var setupTimestamp: Double? 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.interaction = interaction
self.theme = theme 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 self.isLocked = isLocked
if isLocked { if isLocked {
@ -229,9 +229,9 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
if stickerItem.file.isAnimatedSticker || stickerItem.file.isVideoSticker { if stickerItem.file.isAnimatedSticker || stickerItem.file.isVideoSticker {
let dimensions = stickerItem.file.dimensions ?? PixelDimensions(width: 512, height: 512) let dimensions = stickerItem.file.dimensions ?? PixelDimensions(width: 512, height: 512)
if stickerItem.file.isVideoSticker { 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 { } 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 { if self.animationNode == nil {
@ -255,14 +255,14 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
} }
} }
let fittedDimensions = dimensions.cgSize.aspectFitted(CGSize(width: 160.0, height: 160.0)) 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.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 { 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 { } else {
if let animationNode = self.animationNode { if let animationNode = self.animationNode {
@ -270,8 +270,8 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
self.animationNode = nil self.animationNode = nil
animationNode.removeFromSupernode() animationNode.removeFromSupernode()
} }
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))
self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: account, userLocation: .other, fileReference: stickerPackFileReference(stickerItem.file), resource: chatMessageStickerResource(file: stickerItem.file, small: true)).start()) self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: context.account, userLocation: .other, fileReference: stickerPackFileReference(stickerItem.file), resource: chatMessageStickerResource(file: stickerItem.file, small: true)).start())
} }
} else { } else {
if isEmpty { if isEmpty {
@ -287,7 +287,7 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
self.animationNode?.alpha = isLocked ? 0.5 : 1.0 self.animationNode?.alpha = isLocked ? 0.5 : 1.0
self.imageNode.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.setNeedsLayout()
} }
self.isEmpty = isEmpty self.isEmpty = isEmpty
@ -322,8 +322,8 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
let placeholderFrame = imageFrame let placeholderFrame = imageFrame
self.placeholderNode.frame = imageFrame self.placeholderNode.frame = imageFrame
if let theme = self.theme, let (_, stickerItem) = self.currentState, let item = stickerItem { 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) 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 { if let lockBackground = self.lockBackground, let lockTintView = self.lockTintView, let lockIconNode = self.lockIconNode {

View File

@ -52,7 +52,7 @@ private enum StickerPackPreviewGridEntry: Comparable, Identifiable {
func item(context: AccountContext, interaction: StickerPackPreviewInteraction, theme: PresentationTheme, strings: PresentationStrings, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer) -> GridItem { func item(context: AccountContext, interaction: StickerPackPreviewInteraction, theme: PresentationTheme, strings: PresentationStrings, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer) -> GridItem {
switch self { switch self {
case let .sticker(_, _, stickerItem, isEmpty, isPremium, isLocked): 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): 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) return StickerPackEmojisItem(context: context, animationCache: animationCache, animationRenderer: animationRenderer, interaction: interaction, info: info, items: items, theme: theme, strings: strings, title: title, isInstalled: isInstalled, isEmpty: false)
} }

View File

@ -993,6 +993,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[1891070632] = { return Api.contacts.TopPeers.parse_topPeers($0) } dict[1891070632] = { return Api.contacts.TopPeers.parse_topPeers($0) }
dict[-1255369827] = { return Api.contacts.TopPeers.parse_topPeersDisabled($0) } dict[-1255369827] = { return Api.contacts.TopPeers.parse_topPeersDisabled($0) }
dict[-567906571] = { return Api.contacts.TopPeers.parse_topPeersNotModified($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[-860107216] = { return Api.help.AppUpdate.parse_appUpdate($0) }
dict[-1000708810] = { return Api.help.AppUpdate.parse_noAppUpdate($0) } dict[-1000708810] = { return Api.help.AppUpdate.parse_noAppUpdate($0) }
dict[-2016381538] = { return Api.help.CountriesList.parse_countriesList($0) } dict[-2016381538] = { return Api.help.CountriesList.parse_countriesList($0) }
@ -1775,6 +1777,8 @@ public extension Api {
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.contacts.TopPeers: case let _1 as Api.contacts.TopPeers:
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.help.AppConfig:
_1.serialize(buffer, boxed)
case let _1 as Api.help.AppUpdate: case let _1 as Api.help.AppUpdate:
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.help.CountriesList: case let _1 as Api.help.CountriesList:

View File

@ -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 { public extension Api.help {
enum AppUpdate: TypeConstructorDescription { enum AppUpdate: TypeConstructorDescription {
case appUpdate(flags: Int32, id: Int32, version: String, text: String, entities: [Api.MessageEntity], document: Api.Document?, url: String?, sticker: Api.Document?) 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
}
}
}

View File

@ -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 { public extension Api.messages {
enum ArchivedStickers: TypeConstructorDescription { enum ArchivedStickers: TypeConstructorDescription {
case archivedStickers(count: Int32, sets: [Api.StickerSetCovered]) 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
}
}
}
}

View File

@ -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 { public extension Api.messages {
enum InactiveChats: TypeConstructorDescription { enum InactiveChats: TypeConstructorDescription {
case inactiveChats(dates: [Int32], chats: [Api.Chat], users: [Api.User]) 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
}
}
}
}

View File

@ -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 { public extension Api.payments {
enum BankCardData: TypeConstructorDescription { enum BankCardData: TypeConstructorDescription {
case bankCardData(title: String, openUrls: [Api.BankCardOpenUrl]) case bankCardData(title: String, openUrls: [Api.BankCardOpenUrl])

View File

@ -3334,15 +3334,15 @@ public extension Api.functions.help {
} }
} }
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() let buffer = Buffer()
buffer.appendInt32(-1735311088) buffer.appendInt32(1642330196)
serializeInt32(hash, buffer: buffer, boxed: false)
return (FunctionDescription(name: "help.getAppConfig", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.JSONValue? in return (FunctionDescription(name: "help.getAppConfig", parameters: [("hash", String(describing: hash))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.help.AppConfig? in
let reader = BufferReader(buffer) let reader = BufferReader(buffer)
var result: Api.JSONValue? var result: Api.help.AppConfig?
if let signature = reader.readInt32() { 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 return result
}) })

View File

@ -1,6 +1,6 @@
import Postbox import Postbox
private func currentAppConfiguration(transaction: Transaction) -> AppConfiguration { func currentAppConfiguration(transaction: Transaction) -> AppConfiguration {
if let entry = transaction.getPreferencesEntry(key: PreferencesKeys.appConfiguration)?.get(AppConfiguration.self) { if let entry = transaction.getPreferencesEntry(key: PreferencesKeys.appConfiguration)?.get(AppConfiguration.self) {
return entry return entry
} else { } else {

View File

@ -5,22 +5,35 @@ import TelegramApi
import MtProtoKit import MtProtoKit
func updateAppConfigurationOnce(postbox: Postbox, network: Network) -> Signal<Void, NoError> { func updateAppConfigurationOnce(postbox: Postbox, network: Network) -> Signal<Void, NoError> {
return network.request(Api.functions.help.getAppConfig()) return postbox.transaction { transaction -> Int32 in
|> map(Optional.init) return currentAppConfiguration(transaction: transaction).hash
|> `catch` { _ -> Signal<Api.JSONValue?, NoError> in
return .single(nil)
} }
|> mapToSignal { result -> Signal<Void, NoError> in |> mapToSignal { hash -> Signal<Void, NoError> in
guard let result = result else { return network.request(Api.functions.help.getAppConfig(hash: hash))
return .complete() |> 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 |> `catch` { _ -> Signal<(data: Api.JSONValue, hash: Int32)?, NoError> in
if let data = JSON(apiJson: result) { return .single(nil)
updateAppConfiguration(transaction: transaction, { configuration -> AppConfiguration in }
var configuration = configuration |> mapToSignal { result -> Signal<Void, NoError> in
configuration.data = data guard let result = result else {
return configuration 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
})
}
} }
} }
} }

View File

@ -15,15 +15,21 @@ func addSynchronizeRecentlyUsedMediaOperation(transaction: Transaction, category
} }
let peerId = PeerId(0) let peerId = PeerId(0)
var topOperation: (SynchronizeRecentlyUsedMediaOperation, Int32)? var removeOperations: [(SynchronizeRecentlyUsedMediaOperation, Int32)] = []
transaction.operationLogEnumerateEntries(peerId: peerId, tag: tag, { entry in transaction.operationLogEnumerateEntries(peerId: peerId, tag: tag, { entry in
if let operation = entry.contents as? SynchronizeRecentlyUsedMediaOperation { 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) let _ = transaction.operationLogRemoveEntry(peerId: peerId, tag: tag, tagLocalIndex: topLocalIndex)
} }

View File

@ -3,24 +3,28 @@ import Postbox
public struct AppConfiguration: Codable, Equatable { public struct AppConfiguration: Codable, Equatable {
public var data: JSON? public var data: JSON?
public var hash: Int32
public static var defaultValue: AppConfiguration { 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.data = data
self.hash = hash
} }
public init(from decoder: Decoder) throws { public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: StringCodingKey.self) let container = try decoder.container(keyedBy: StringCodingKey.self)
self.data = try container.decodeIfPresent(JSON.self, forKey: "data") 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 { public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: StringCodingKey.self) var container = encoder.container(keyedBy: StringCodingKey.self)
try container.encodeIfPresent(self.data, forKey: "data") try container.encodeIfPresent(self.data, forKey: "data")
try container.encode(self.hash, forKey: "storedHash")
} }
} }

View File

@ -289,7 +289,7 @@ public func currentPresentationDataAndSettings(accountManager: AccountManager<Te
contactSynchronizationSettings: contactSynchronizationSettings contactSynchronizationSettings: contactSynchronizationSettings
) )
} }
|> deliverOn(Queue.mainQueue()) |> deliverOn(Queue(name: "PresentationData-Load", qos: .userInteractive))
|> map { internalData -> InitialPresentationDataAndSettings in |> map { internalData -> InitialPresentationDataAndSettings in
let localizationSettings: LocalizationSettings? let localizationSettings: LocalizationSettings?
if let current = internalData.localizationSettings?.get(LocalizationSettings.self) { if let current = internalData.localizationSettings?.get(LocalizationSettings.self) {

View File

@ -192,6 +192,7 @@ public final class ChatControllerInteraction {
public var updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? public var updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?
public let presentationContext: ChatPresentationContext public let presentationContext: ChatPresentationContext
public var playNextOutgoingGift: Bool = false public var playNextOutgoingGift: Bool = false
public var enableFullTranslucency: Bool = true
public init( public init(
openMessage: @escaping (Message, ChatControllerInteractionOpenMessageMode) -> Bool, openMessage: @escaping (Message, ChatControllerInteractionOpenMessageMode) -> Bool,

View File

@ -1342,7 +1342,7 @@ private final class GroupEmbeddedView: UIScrollView, UIScrollViewDelegate, Pager
let itemFrame = itemLayout.frame(at: index) let itemFrame = itemLayout.frame(at: index)
itemLayer.frame = itemFrame itemLayer.frame = itemFrame
itemLayer.isVisibleForAnimations = true itemLayer.isVisibleForAnimations = context.sharedContext.energyUsageSettings.loopEmoji
} }
} }
@ -2160,7 +2160,7 @@ private final class EmptySearchResultsView: UIView {
animationCache: context.animationCache, animationCache: context.animationCache,
animationRenderer: context.animationRenderer, animationRenderer: context.animationRenderer,
content: .animation(content: .file(file: file), size: CGSize(width: 32.0, height: 32.0), placeholderColor: titleColor, themeColor: nil, loopMode: .forever), 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 action: nil
)), )),
environment: {}, environment: {},
@ -3650,7 +3650,7 @@ public final class EmojiPagerContentComponent: Component {
override init(frame: CGRect) { override init(frame: CGRect) {
self.backgroundView = BlurredBackgroundView(color: nil) self.backgroundView = BlurredBackgroundView(color: nil)
if ProcessInfo.processInfo.processorCount > 2 { if ProcessInfo.processInfo.processorCount > 4 {
self.shimmerHostView = PortalSourceView() self.shimmerHostView = PortalSourceView()
self.standaloneShimmerEffect = StandaloneShimmerEffect() self.standaloneShimmerEffect = StandaloneShimmerEffect()
} else { } else {
@ -5795,7 +5795,7 @@ public final class EmojiPagerContentComponent: Component {
placeholderView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1) 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 { if itemGroup.fillWithLoadingPlaceholders {

View File

@ -167,7 +167,7 @@ final class EntityKeyboardAnimationTopPanelComponent: Component {
itemLayer.layerTintColor = component.theme.list.itemAccentColor.cgColor itemLayer.layerTintColor = component.theme.list.itemAccentColor.cgColor
} }
itemLayer.isVisibleForAnimations = itemEnvironment.isContentInFocus itemLayer.isVisibleForAnimations = itemEnvironment.isContentInFocus && component.context.sharedContext.energyUsageSettings.loopEmoji
} }
if itemEnvironment.isExpanded { if itemEnvironment.isExpanded {

View File

@ -93,6 +93,8 @@ public final class TextNodeWithEntities {
public let textNode: TextNode public let textNode: TextNode
private var inlineStickerItemLayers: [InlineStickerItemLayer.Key: InlineStickerItemLayer] = [:] private var inlineStickerItemLayers: [InlineStickerItemLayer.Key: InlineStickerItemLayer] = [:]
private var enableLooping: Bool = true
public var visibilityRect: CGRect? { public var visibilityRect: CGRect? {
didSet { didSet {
if !self.inlineStickerItemLayers.isEmpty && oldValue != self.visibilityRect { if !self.inlineStickerItemLayers.isEmpty && oldValue != self.visibilityRect {
@ -107,7 +109,7 @@ public final class TextNodeWithEntities {
} else { } else {
isItemVisible = false 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) { 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 nextIndexById: [Int64: Int] = [:]
var validIds: [InlineStickerItemLayer.Key] = [] var validIds: [InlineStickerItemLayer.Key] = []
@ -250,7 +254,7 @@ public final class TextNodeWithEntities {
self.inlineStickerItemLayers[id] = itemLayer self.inlineStickerItemLayers[id] = itemLayer
self.textNode.layer.addSublayer(itemLayer) self.textNode.layer.addSublayer(itemLayer)
itemLayer.isVisibleForAnimations = self.isItemVisible(itemRect: itemFrame) itemLayer.isVisibleForAnimations = self.enableLooping && self.isItemVisible(itemRect: itemFrame)
} }
itemLayer.frame = itemFrame itemLayer.frame = itemFrame
@ -284,6 +288,8 @@ public class ImmediateTextNodeWithEntities: TextNode {
public var cutout: TextNodeCutout? public var cutout: TextNodeCutout?
public var displaySpoilers = false public var displaySpoilers = false
private var enableLooping: Bool = true
public var arguments: TextNodeWithEntities.Arguments? public var arguments: TextNodeWithEntities.Arguments?
private var inlineStickerItemLayers: [InlineStickerItemLayer.Key: InlineStickerItemLayer] = [:] private var inlineStickerItemLayers: [InlineStickerItemLayer.Key: InlineStickerItemLayer] = [:]
@ -293,7 +299,7 @@ public class ImmediateTextNodeWithEntities: TextNode {
if !self.inlineStickerItemLayers.isEmpty && oldValue != self.visibility { if !self.inlineStickerItemLayers.isEmpty && oldValue != self.visibility {
for (_, itemLayer) in self.inlineStickerItemLayers { for (_, itemLayer) in self.inlineStickerItemLayers {
let isItemVisible: Bool = self.visibility 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) { private func updateInlineStickers(context: AccountContext, cache: AnimationCache, renderer: MultiAnimationRenderer, textLayout: TextNodeLayout?, placeholderColor: UIColor) {
self.enableLooping = context.sharedContext.energyUsageSettings.loopEmoji
var nextIndexById: [Int64: Int] = [:] var nextIndexById: [Int64: Int] = [:]
var validIds: [InlineStickerItemLayer.Key] = [] var validIds: [InlineStickerItemLayer.Key] = []
@ -415,7 +423,7 @@ public class ImmediateTextNodeWithEntities: TextNode {
self.inlineStickerItemLayers[id] = itemLayer self.inlineStickerItemLayers[id] = itemLayer
self.layer.addSublayer(itemLayer) self.layer.addSublayer(itemLayer)
itemLayer.isVisibleForAnimations = self.visibility itemLayer.isVisibleForAnimations = self.enableLooping && self.visibility
} }
itemLayer.frame = itemFrame itemLayer.frame = itemFrame

View File

@ -1646,6 +1646,9 @@ private func extractAccountManagerState(records: AccountRecordsView<TelegramAcco
extendNow = true extendNow = true
} }
} }
if !sharedApplicationContext.sharedContext.energyUsageSettings.extendBackgroundWork {
extendNow = false
}
sharedApplicationContext.wakeupManager.allowBackgroundTimeExtension(timeout: 2.0, extendNow: extendNow) sharedApplicationContext.wakeupManager.allowBackgroundTimeExtension(timeout: 2.0, extendNow: extendNow)
}) })

View File

@ -598,7 +598,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} }
self.presentationData = context.sharedContext.currentPresentationData.with { $0 } self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.automaticMediaDownloadSettings = context.sharedContext.currentAutomaticMediaDownloadSettings.with { $0 } self.automaticMediaDownloadSettings = context.sharedContext.currentAutomaticMediaDownloadSettings
self.stickerSettings = ChatInterfaceStickerSettings(loopAnimatedStickers: false) self.stickerSettings = ChatInterfaceStickerSettings(loopAnimatedStickers: false)
@ -4281,6 +4281,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}, scrollToMessageId: { [weak self] index in }, scrollToMessageId: { [weak self] index in
self?.chatDisplayNode.historyNode.scrollToMessage(index: index) self?.chatDisplayNode.historyNode.scrollToMessage(index: index)
}, automaticMediaDownloadSettings: self.automaticMediaDownloadSettings, pollActionState: ChatInterfacePollActionState(), stickerSettings: self.stickerSettings, presentationContext: ChatPresentationContext(context: context, backgroundNode: self.chatBackgroundNode)) }, automaticMediaDownloadSettings: self.automaticMediaDownloadSettings, pollActionState: ChatInterfacePollActionState(), stickerSettings: self.stickerSettings, presentationContext: ChatPresentationContext(context: context, backgroundNode: self.chatBackgroundNode))
controllerInteraction.enableFullTranslucency = context.sharedContext.energyUsageSettings.fullTranslucency
self.controllerInteraction = controllerInteraction self.controllerInteraction = controllerInteraction

View File

@ -249,7 +249,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
loadingPlaceholderNode.setup(self.historyNode, updating: true) loadingPlaceholderNode.setup(self.historyNode, updating: true)
} }
} else { } 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) loadingPlaceholderNode.updatePresentationInterfaceState(self.chatPresentationInterfaceState)
self.backgroundNode.supernode?.insertSubnode(loadingPlaceholderNode, aboveSubnode: self.backgroundNode) self.backgroundNode.supernode?.insertSubnode(loadingPlaceholderNode, aboveSubnode: self.backgroundNode)
@ -447,7 +447,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
onTransitionEventImpl?(transition) 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.inputPanelContainerNode = ChatInputPanelContainer()
self.inputPanelOverlayNode = SparseNode() self.inputPanelOverlayNode = SparseNode()
@ -491,7 +491,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
if (strongSelf.context.sharedContext.currentPresentationData.with({ $0 })).reduceMotion { if (strongSelf.context.sharedContext.currentPresentationData.with({ $0 })).reduceMotion {
return return
} }
if DeviceMetrics.performance.isGraphicallyCapable { if strongSelf.context.sharedContext.energyUsageSettings.fullTranslucency {
strongSelf.backgroundNode.animateEvent(transition: transition, extendAnimation: false) strongSelf.backgroundNode.animateEvent(transition: transition, extendAnimation: false)
} }
} }
@ -2216,7 +2216,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
if (self.context.sharedContext.currentPresentationData.with({ $0 })).reduceMotion { if (self.context.sharedContext.currentPresentationData.with({ $0 })).reduceMotion {
return return
} }
if DeviceMetrics.performance.isGraphicallyCapable { if self.context.sharedContext.energyUsageSettings.fullTranslucency {
self.backgroundNode.animateEvent(transition: transition, extendAnimation: false) self.backgroundNode.animateEvent(transition: transition, extendAnimation: false)
} }
} }

View File

@ -960,7 +960,7 @@ final class ChatEmptyNode: ASDisplayNode {
self.currentTheme = interfaceState.theme self.currentTheme = interfaceState.theme
self.currentStrings = interfaceState.strings 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 var isScheduledMessages = false

View File

@ -8,14 +8,15 @@ import ActivityIndicator
import WallpaperBackgroundNode import WallpaperBackgroundNode
import ShimmerEffect import ShimmerEffect
import ChatPresentationInterfaceState import ChatPresentationInterfaceState
import AccountContext
final class ChatLoadingNode: ASDisplayNode { final class ChatLoadingNode: ASDisplayNode {
private let backgroundNode: NavigationBackgroundNode private let backgroundNode: NavigationBackgroundNode
private let activityIndicator: ActivityIndicator private let activityIndicator: ActivityIndicator
private let offset: CGPoint private let offset: CGPoint
init(theme: PresentationTheme, chatWallpaper: TelegramWallpaper, bubbleCorners: PresentationChatBubbleCorners) { init(context: AccountContext, theme: PresentationTheme, chatWallpaper: TelegramWallpaper, bubbleCorners: PresentationChatBubbleCorners) {
self.backgroundNode = NavigationBackgroundNode(color: selectDateFillStaticColor(theme: theme, wallpaper: chatWallpaper), enableBlur: dateFillNeedsBlur(theme: theme, wallpaper: chatWallpaper)) 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) let serviceColor = serviceMessageColorComponents(theme: theme, wallpaper: chatWallpaper)
self.activityIndicator = ActivityIndicator(type: .custom(serviceColor.primaryText, 22.0, 2.0, false), speed: .regular) 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 { final class ChatLoadingPlaceholderNode: ASDisplayNode {
private weak var backgroundNode: WallpaperBackgroundNode? private weak var backgroundNode: WallpaperBackgroundNode?
private let context: AccountContext
private let maskNode: ASDisplayNode private let maskNode: ASDisplayNode
private let borderMaskNode: ASDisplayNode private let borderMaskNode: ASDisplayNode
@ -151,7 +154,8 @@ final class ChatLoadingPlaceholderNode: ASDisplayNode {
private var validLayout: (CGSize, UIEdgeInsets)? 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.backgroundNode = backgroundNode
self.maskNode = ASDisplayNode() self.maskNode = ASDisplayNode()
@ -185,13 +189,13 @@ final class ChatLoadingPlaceholderNode: ASDisplayNode {
self.addSubnode(self.containerNode) self.addSubnode(self.containerNode)
self.containerNode.addSubnode(self.backgroundColorNode) self.containerNode.addSubnode(self.backgroundColorNode)
if DeviceMetrics.performance.isGraphicallyCapable { if context.sharedContext.energyUsageSettings.fullTranslucency {
self.containerNode.addSubnode(self.effectNode) self.containerNode.addSubnode(self.effectNode)
} }
self.addSubnode(self.borderNode) self.addSubnode(self.borderNode)
if DeviceMetrics.performance.isGraphicallyCapable { if context.sharedContext.energyUsageSettings.fullTranslucency {
self.borderNode.addSubnode(self.borderEffectNode) self.borderNode.addSubnode(self.borderEffectNode)
} }
} }
@ -202,7 +206,7 @@ final class ChatLoadingPlaceholderNode: ASDisplayNode {
self.containerNode.view.mask = self.maskNode.view self.containerNode.view.mask = self.maskNode.view
self.borderNode.view.mask = self.borderMaskNode.view self.borderNode.view.mask = self.borderMaskNode.view
if DeviceMetrics.performance.isGraphicallyCapable { if self.context.sharedContext.energyUsageSettings.fullTranslucency {
self.backgroundNode?.updateIsLooping(true) self.backgroundNode?.updateIsLooping(true)
} }
} }

View File

@ -383,7 +383,7 @@ final class ChatMediaInputStickerGridItemNode: GridItemNode {
} }
let theme = item.theme 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 { if let lockBackground = self.lockBackground, let lockTintView = self.lockTintView, let lockIconNode = self.lockIconNode {

View File

@ -269,7 +269,7 @@ final class ChatMediaInputStickerPackItemNode: ListViewItemNode {
immediateThumbnailData = data 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) self.containerNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: expandedBoundingSize)

View File

@ -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) 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.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 backgroundNode?.hasExtraBubbleBackground() == true {
if node.backgroundContent == nil, let backgroundContent = backgroundNode?.makeBubbleBackground(for: .free) { if node.backgroundContent == nil, let backgroundContent = backgroundNode?.makeBubbleBackground(for: .free) {

View File

@ -125,7 +125,7 @@ class ChatMessageShareButton: HighlightableButtonNode {
} else { } else {
updatedIconImage = PresentationResourcesChat.chatFreeShareButtonIcon(presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper) 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.iconNode.image = updatedIconImage
self.iconOffset = updatedIconOffset 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 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) 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 strongSelf.placeholderNode.frame = animationNodeFrame
} }
@ -1488,9 +1488,9 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
if needsReplyBackground { if needsReplyBackground {
if let replyBackgroundNode = strongSelf.replyBackgroundNode { 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 { } 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.replyBackgroundNode = replyBackgroundNode
strongSelf.contextSourceNode.contentNode.addSubnode(replyBackgroundNode) strongSelf.contextSourceNode.contentNode.addSubnode(replyBackgroundNode)
} }
@ -2442,7 +2442,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
} }
if let item = self.item, self.swipeToReplyNode == nil { 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.swipeToReplyNode = swipeToReplyNode
self.insertSubnode(swipeToReplyNode, at: 0) self.insertSubnode(swipeToReplyNode, at: 0)
} }

View File

@ -4240,7 +4240,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
} }
if let item = self.item, self.swipeToReplyNode == nil { 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.swipeToReplyNode = swipeToReplyNode
self.insertSubnode(swipeToReplyNode, at: 0) self.insertSubnode(swipeToReplyNode, at: 0)
} }

View File

@ -474,7 +474,7 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
let serviceColor = serviceMessageColorComponents(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper) let serviceColor = serviceMessageColorComponents(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper)
dateColor = serviceColor.primaryText 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 leftInset = 0.0
loadedCheckFullImage = PresentationResourcesChat.chatFreeFullCheck(arguments.presentationData.theme.theme, size: checkSize, isDefaultWallpaper: isDefaultWallpaper) loadedCheckFullImage = PresentationResourcesChat.chatFreeFullCheck(arguments.presentationData.theme.theme, size: checkSize, isDefaultWallpaper: isDefaultWallpaper)
loadedCheckPartialImage = PresentationResourcesChat.chatFreePartialCheck(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) let serviceColor = serviceMessageColorComponents(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper)
dateColor = serviceColor.primaryText dateColor = serviceColor.primaryText
outgoingStatus = status 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 leftInset = 0.0
loadedCheckFullImage = PresentationResourcesChat.chatFreeFullCheck(arguments.presentationData.theme.theme, size: checkSize, isDefaultWallpaper: isDefaultWallpaper) loadedCheckFullImage = PresentationResourcesChat.chatFreeFullCheck(arguments.presentationData.theme.theme, size: checkSize, isDefaultWallpaper: isDefaultWallpaper)
loadedCheckPartialImage = PresentationResourcesChat.chatFreePartialCheck(arguments.presentationData.theme.theme, size: checkSize, isDefaultWallpaper: isDefaultWallpaper) loadedCheckPartialImage = PresentationResourcesChat.chatFreePartialCheck(arguments.presentationData.theme.theme, size: checkSize, isDefaultWallpaper: isDefaultWallpaper)

View File

@ -200,7 +200,9 @@ final class ChatMessageDateHeaderNode: ListViewItemHeaderNode {
let graphics = PresentationResourcesChat.principalGraphics(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper, bubbleCorners: presentationData.chatBubbleCorners) 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.image = graphics.dateFloatingBackground
self.stickBackgroundNode.alpha = 0.0 self.stickBackgroundNode.alpha = 0.0
@ -236,8 +238,10 @@ final class ChatMessageDateHeaderNode: ListViewItemHeaderNode {
self.presentationData = presentationData self.presentationData = presentationData
let graphics = PresentationResourcesChat.principalGraphics(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper, bubbleCorners: presentationData.chatBubbleCorners) 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 self.stickBackgroundNode.image = graphics.dateFloatingBackground
let titleFont = Font.medium(min(18.0, floor(presentationData.fontSize.baseDisplaySize * 13.0 / 17.0))) 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)) 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) self.cachedDataDisposable.set((context.account.postbox.peerView(id: peer.id)
|> deliverOnMainQueue).start(next: { [weak self] peerView in |> deliverOnMainQueue).start(next: { [weak self] peerView in
guard let strongSelf = self else { guard let strongSelf = self else {

View File

@ -236,7 +236,7 @@ class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
let mediaBackgroundFrame = imageFrame.insetBy(dx: -2.0, dy: -2.0) let mediaBackgroundFrame = imageFrame.insetBy(dx: -2.0, dy: -2.0)
strongSelf.mediaBackgroundNode.frame = mediaBackgroundFrame 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.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) strongSelf.buttonNode.backgroundColor = item.presentationData.theme.theme.overallDarkAppearance ? UIColor(rgb: 0xffffff, alpha: 0.12) : UIColor(rgb: 0x000000, alpha: 0.12)

View File

@ -525,10 +525,10 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
if let currentReplyBackgroundNode = currentReplyBackgroundNode { if let currentReplyBackgroundNode = currentReplyBackgroundNode {
updatedReplyBackgroundNode = currentReplyBackgroundNode updatedReplyBackgroundNode = currentReplyBackgroundNode
} else { } 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 var maxContentWidth = normalDisplaySize.width
@ -1009,7 +1009,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
translation.x = max(-80.0, min(0.0, translation.x)) translation.x = max(-80.0, min(0.0, translation.x))
if let item = self.item, self.swipeToReplyNode == nil { 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.swipeToReplyNode = swipeToReplyNode
self.insertSubnode(swipeToReplyNode, at: 0) self.insertSubnode(swipeToReplyNode, at: 0)
} }

View File

@ -561,10 +561,10 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
if let currentReplyBackgroundNode = currentReplyBackgroundNode { if let currentReplyBackgroundNode = currentReplyBackgroundNode {
updatedReplyBackgroundNode = currentReplyBackgroundNode updatedReplyBackgroundNode = currentReplyBackgroundNode
} else { } 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 return (result, { [weak self] layoutData, animation in
@ -625,7 +625,7 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
case .free: case .free:
let serviceColor = serviceMessageColorComponents(theme: theme.theme, wallpaper: theme.wallpaper) let serviceColor = serviceMessageColorComponents(theme: theme.theme, wallpaper: theme.wallpaper)
durationTextColor = serviceColor.primaryText 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: case .bubble:
durationBlurColor = nil durationBlurColor = nil
if incoming { if incoming {

View File

@ -254,7 +254,7 @@ class ChatMessageProfilePhotoSuggestionContentNode: ChatMessageBubbleContentNode
let mediaBackgroundFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((backgroundSize.width - width) / 2.0), y: 0.0), size: backgroundSize) let mediaBackgroundFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((backgroundSize.width - width) / 2.0), y: 0.0), size: backgroundSize)
strongSelf.mediaBackgroundNode.frame = mediaBackgroundFrame 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.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) strongSelf.buttonNode.backgroundColor = item.presentationData.theme.theme.overallDarkAppearance ? UIColor(rgb: 0xffffff, alpha: 0.12) : UIColor(rgb: 0x000000, alpha: 0.12)

View File

@ -894,7 +894,7 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
let shimmeringColor = bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.stickerPlaceholderShimmerColor, wallpaper: item.presentationData.theme.wallpaper) let shimmeringColor = bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.stickerPlaceholderShimmerColor, wallpaper: item.presentationData.theme.wallpaper)
let placeholderFrame = updatedImageFrame.insetBy(dx: innerImageInset, dy: innerImageInset) 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 strongSelf.placeholderNode.frame = placeholderFrame
} }
@ -927,9 +927,9 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
if needsReplyBackground { if needsReplyBackground {
if let replyBackgroundNode = strongSelf.replyBackgroundNode { 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 { } 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.replyBackgroundNode = replyBackgroundNode
strongSelf.contextSourceNode.contentNode.addSubnode(replyBackgroundNode) strongSelf.contextSourceNode.contentNode.addSubnode(replyBackgroundNode)
} }
@ -1412,7 +1412,7 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
} }
if let item = self.item, self.swipeToReplyNode == nil { 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.swipeToReplyNode = swipeToReplyNode
self.insertSubnode(swipeToReplyNode, at: 0) self.insertSubnode(swipeToReplyNode, at: 0)
} }

View File

@ -447,7 +447,7 @@ class ChatMessageThreadInfoNode: ASDisplayNode {
backgroundNode.frame = backgroundFrame backgroundNode.frame = backgroundFrame
backgroundNode.update(size: backgroundNode.bounds.size, cornerRadius: 0.0, transition: .immediate) 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 { } else {
node.contentBackgroundNode.frame = CGRect(origin: CGPoint(x: -1.0, y: -3.0), size: image.size) node.contentBackgroundNode.frame = CGRect(origin: CGPoint(x: -1.0, y: -3.0), size: image.size)

View File

@ -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()) 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) 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 strongSelf.placeholderNode.frame = emojiFrame
} }

View File

@ -107,7 +107,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
self.presentController = presentController self.presentController = presentController
self.getNavigationController = getNavigationController self.getNavigationController = getNavigationController
self.automaticMediaDownloadSettings = context.sharedContext.currentAutomaticMediaDownloadSettings.with { $0 } self.automaticMediaDownloadSettings = context.sharedContext.currentAutomaticMediaDownloadSettings
self.backgroundNode = createWallpaperBackgroundNode(context: context, forChatDisplay: true) self.backgroundNode = createWallpaperBackgroundNode(context: context, forChatDisplay: true)
self.backgroundNode.isUserInteractionEnabled = false self.backgroundNode.isUserInteractionEnabled = false
@ -125,7 +125,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
return presentationData.strings.VoiceOver_ScrollStatus(row, count).string 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 = ChatRecentActionsEmptyNode(theme: self.presentationData.theme, chatWallpaper: self.presentationData.chatWallpaper, chatBubbleCorners: self.presentationData.chatBubbleCorners)
self.emptyNode.alpha = 0.0 self.emptyNode.alpha = 0.0

View File

@ -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()) 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) 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 strongSelf.placeholderNode.frame = emojiFrame
} }

View File

@ -499,7 +499,7 @@ final class HorizontalListContextResultsChatInputPanelItemNode: ListViewItemNode
placeholderNode.bounds = CGRect(origin: CGPoint(), size: CGSize(width: croppedImageDimensions.width, height: croppedImageDimensions.height)) 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.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)
} }
} }
}) })

View File

@ -11,9 +11,10 @@ import AnimatedStickerNode
import TelegramAnimatedStickerNode import TelegramAnimatedStickerNode
import ShimmerEffect import ShimmerEffect
import TelegramPresentationData import TelegramPresentationData
import AccountContext
final class HorizontalStickerGridItem: GridItem { final class HorizontalStickerGridItem: GridItem {
let account: Account let context: AccountContext
let file: TelegramMediaFile let file: TelegramMediaFile
let theme: PresentationTheme let theme: PresentationTheme
let isPreviewed: (HorizontalStickerGridItem) -> Bool let isPreviewed: (HorizontalStickerGridItem) -> Bool
@ -21,8 +22,8 @@ final class HorizontalStickerGridItem: GridItem {
let section: GridSection? = nil let section: GridSection? = nil
init(account: Account, file: TelegramMediaFile, theme: PresentationTheme, isPreviewed: @escaping (HorizontalStickerGridItem) -> Bool, sendSticker: @escaping (FileMediaReference, UIView, CGRect) -> Void) { init(context: AccountContext, file: TelegramMediaFile, theme: PresentationTheme, isPreviewed: @escaping (HorizontalStickerGridItem) -> Bool, sendSticker: @escaping (FileMediaReference, UIView, CGRect) -> Void) {
self.account = account self.context = context
self.file = file self.file = file
self.theme = theme self.theme = theme
self.isPreviewed = isPreviewed self.isPreviewed = isPreviewed
@ -31,7 +32,7 @@ final class HorizontalStickerGridItem: GridItem {
func node(layout: GridNodeLayout, synchronousLoad: Bool) -> GridItemNode { func node(layout: GridNodeLayout, synchronousLoad: Bool) -> GridItemNode {
let node = HorizontalStickerGridItemNode() let node = HorizontalStickerGridItemNode()
node.setup(account: self.account, item: self) node.setup(context: self.context, item: self)
node.sendSticker = self.sendSticker node.sendSticker = self.sendSticker
return node return node
} }
@ -41,13 +42,13 @@ final class HorizontalStickerGridItem: GridItem {
assertionFailure() assertionFailure()
return return
} }
node.setup(account: self.account, item: self) node.setup(context: self.context, item: self)
node.sendSticker = self.sendSticker node.sendSticker = self.sendSticker
} }
} }
final class HorizontalStickerGridItemNode: GridItemNode { final class HorizontalStickerGridItemNode: GridItemNode {
private var currentState: (Account, HorizontalStickerGridItem, CGSize)? private var currentState: (AccountContext, HorizontalStickerGridItem, CGSize)?
let imageNode: TransformImageNode let imageNode: TransformImageNode
private(set) var animationNode: AnimatedStickerNode? private(set) var animationNode: AnimatedStickerNode?
private(set) var placeholderNode: StickerShimmerEffectNode? private(set) var placeholderNode: StickerShimmerEffectNode?
@ -137,8 +138,8 @@ final class HorizontalStickerGridItemNode: GridItemNode {
self.imageNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.imageNodeTap(_:)))) self.imageNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.imageNodeTap(_:))))
} }
func setup(account: Account, item: HorizontalStickerGridItem) { func setup(context: AccountContext, item: HorizontalStickerGridItem) {
if self.currentState == nil || self.currentState!.0 !== account || self.currentState!.1.file.id != item.file.id { if self.currentState == nil || self.currentState!.0 !== context || self.currentState!.1.file.id != item.file.id {
if let dimensions = item.file.dimensions { if let dimensions = item.file.dimensions {
if item.file.isAnimatedSticker || item.file.isVideoSticker { if item.file.isAnimatedSticker || item.file.isVideoSticker {
let animationNode: AnimatedStickerNode let animationNode: AnimatedStickerNode
@ -161,9 +162,9 @@ final class HorizontalStickerGridItemNode: GridItemNode {
let fittedDimensions = dimensions.cgSize.aspectFitted(CGSize(width: 160.0, height: 160.0)) let fittedDimensions = dimensions.cgSize.aspectFitted(CGSize(width: 160.0, height: 160.0))
if item.file.isVideoSticker { 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 { } 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 animationNode.started = { [weak self] in
guard let strongSelf = self else { guard let strongSelf = self else {
@ -181,19 +182,19 @@ final class HorizontalStickerGridItemNode: GridItemNode {
strongSelf.removePlaceholder(animated: false) 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 { } else {
self.imageNode.alpha = 1.0 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 { if let currentAnimationNode = self.animationNode {
self.animationNode = nil self.animationNode = nil
currentAnimationNode.removeFromSupernode() 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 { if item.file.isPremiumSticker {
@ -237,7 +238,7 @@ final class HorizontalStickerGridItemNode: GridItemNode {
lockIconNode.removeFromSupernode() lockIconNode.removeFromSupernode()
} }
self.currentState = (account, item, dimensions.cgSize) self.currentState = (context, item, dimensions.cgSize)
self.setNeedsLayout() self.setNeedsLayout()
} }
} }
@ -254,8 +255,8 @@ final class HorizontalStickerGridItemNode: GridItemNode {
if let placeholderNode = self.placeholderNode { if let placeholderNode = self.placeholderNode {
placeholderNode.frame = bounds placeholderNode.frame = bounds
if let theme = self.currentState?.1.theme, let file = self.currentState?.1.file { 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) 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)
} }
} }

View File

@ -70,8 +70,8 @@ private struct StickerEntry: Identifiable, Comparable {
return lhs.index < rhs.index return lhs.index < rhs.index
} }
func item(account: Account, stickersInteraction: HorizontalStickersChatContextPanelInteraction, interfaceInteraction: ChatPanelInterfaceInteraction, theme: PresentationTheme) -> GridItem { func item(context: AccountContext, stickersInteraction: HorizontalStickersChatContextPanelInteraction, interfaceInteraction: ChatPanelInterfaceInteraction, theme: PresentationTheme) -> GridItem {
return HorizontalStickerGridItem(account: account, file: self.file, theme: theme, isPreviewed: { item in return HorizontalStickerGridItem(context: context, file: self.file, theme: theme, isPreviewed: { item in
return false//stickersInteraction.previewedStickerItem == item return false//stickersInteraction.previewedStickerItem == item
}, sendSticker: { file, node, rect in }, sendSticker: { file, node, rect in
let _ = interfaceInteraction.sendSticker(file, true, node, rect, nil, []) let _ = interfaceInteraction.sendSticker(file, true, node, rect, nil, [])
@ -88,15 +88,15 @@ private struct StickerEntryTransition {
let scrollToItem: GridNodeScrollToItem? 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 stationaryItems: GridNodeStationaryItems = .none
let scrollToItem: GridNodeScrollToItem? = nil let scrollToItem: GridNodeScrollToItem? = nil
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries) let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
let deletions = deleteIndices 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 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(account: account, stickersInteraction: stickersInteraction, interfaceInteraction: interfaceInteraction, theme: theme)) } 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) 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) 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) self.enqueueTransition(transition)
} }

View File

@ -31,7 +31,7 @@ final class InChatPrefetchManager {
init(context: AccountContext) { init(context: AccountContext) {
self.context = context self.context = context
self.settings = context.sharedContext.currentAutomaticMediaDownloadSettings.with { $0 } self.settings = context.sharedContext.currentAutomaticMediaDownloadSettings
} }
func updateAutoDownloadSettings(_ settings: MediaAutoDownloadSettings) { func updateAutoDownloadSettings(_ settings: MediaAutoDownloadSettings) {

View File

@ -431,7 +431,7 @@ private final class InlineReactionSearchStickersNode: ASDisplayNode, UIScrollVie
itemNode = current itemNode = current
} else { } else {
let item = HorizontalStickerGridItem( let item = HorizontalStickerGridItem(
account: self.context.account, context: self.context,
file: item.file, file: item.file,
theme: self.theme, theme: self.theme,
isPreviewed: { [weak self] item in isPreviewed: { [weak self] item in

View File

@ -131,7 +131,7 @@ private final class LargeEmojiActionSheetItemNode: ActionSheetItemNode {
} }
if let immediateThumbnailData = file.immediateThumbnailData { 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)
} }
} }

View File

@ -146,12 +146,16 @@ public final class SharedAccountContextImpl: SharedAccountContext {
public let currentInAppNotificationSettings: Atomic<InAppNotificationSettings> public let currentInAppNotificationSettings: Atomic<InAppNotificationSettings>
private var inAppNotificationSettingsDisposable: Disposable? private var inAppNotificationSettingsDisposable: Disposable?
public let currentAutomaticMediaDownloadSettings: Atomic<MediaAutoDownloadSettings> public var currentAutomaticMediaDownloadSettings: MediaAutoDownloadSettings
private let _automaticMediaDownloadSettings = Promise<MediaAutoDownloadSettings>() private let _automaticMediaDownloadSettings = Promise<MediaAutoDownloadSettings>()
public var automaticMediaDownloadSettings: Signal<MediaAutoDownloadSettings, NoError> { public var automaticMediaDownloadSettings: Signal<MediaAutoDownloadSettings, NoError> {
return self._automaticMediaDownloadSettings.get() return self._automaticMediaDownloadSettings.get()
} }
public var energyUsageSettings: EnergyUsageSettings {
return self.currentAutomaticMediaDownloadSettings.energyUsageSettings
}
public let currentAutodownloadSettings: Atomic<AutodownloadSettings> public let currentAutodownloadSettings: Atomic<AutodownloadSettings>
private let _autodownloadSettings = Promise<AutodownloadSettings>() private let _autodownloadSettings = Promise<AutodownloadSettings>()
private var currentAutodownloadSettingsDisposable = MetaDisposable() private var currentAutodownloadSettingsDisposable = MetaDisposable()
@ -230,7 +234,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
} }
self._currentPresentationData = Atomic(value: initialPresentationDataAndSettings.presentationData) self._currentPresentationData = Atomic(value: initialPresentationDataAndSettings.presentationData)
self.currentAutomaticMediaDownloadSettings = Atomic(value: initialPresentationDataAndSettings.automaticMediaDownloadSettings) self.currentAutomaticMediaDownloadSettings = initialPresentationDataAndSettings.automaticMediaDownloadSettings
self.currentAutodownloadSettings = Atomic(value: initialPresentationDataAndSettings.autodownloadSettings) self.currentAutodownloadSettings = Atomic(value: initialPresentationDataAndSettings.autodownloadSettings)
self.currentMediaInputSettings = Atomic(value: initialPresentationDataAndSettings.mediaInputSettings) self.currentMediaInputSettings = Atomic(value: initialPresentationDataAndSettings.mediaInputSettings)
self.currentInAppNotificationSettings = Atomic(value: initialPresentationDataAndSettings.inAppNotificationSettings) 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 self.automaticMediaDownloadSettingsDisposable.set(self._automaticMediaDownloadSettings.get().start(next: { [weak self] next in
if let strongSelf = self { if let strongSelf = self {
let _ = strongSelf.currentAutomaticMediaDownloadSettings.swap(next) strongSelf.currentAutomaticMediaDownloadSettings = next
} }
})) }))

View File

@ -328,7 +328,7 @@ private final class FeaturedPackItemNode: ListViewItemNode {
immediateThumbnailData = data 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) self.containerNode.frame = CGRect(origin: CGPoint(), size: boundingSize)

View File

@ -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 struct MediaAutoDownloadSettings: Codable, Equatable {
public var presets: MediaAutoDownloadPresets public var presets: MediaAutoDownloadPresets
public var cellular: MediaAutoDownloadConnection public var cellular: MediaAutoDownloadConnection
@ -267,27 +334,30 @@ public struct MediaAutoDownloadSettings: Codable, Equatable {
public var autoplayVideos: Bool public var autoplayVideos: Bool
public var downloadInBackground: Bool public var downloadInBackground: Bool
public var energyUsageSettings: EnergyUsageSettings
public static var defaultSettings: MediaAutoDownloadSettings { public static var defaultSettings: MediaAutoDownloadSettings {
let mb: Int64 = 1024 * 1024 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), let presets = MediaAutoDownloadPresets(low: MediaAutoDownloadCategories(basePreset: .low, photo: MediaAutoDownloadCategory(contacts: true, otherPrivate: true, groups: true, channels: true, sizeLimit: 1 * mb, predownload: false),
video: MediaAutoDownloadCategory(contacts: false, otherPrivate: false, groups: false, channels: false, sizeLimit: 1 * mb, predownload: false), video: MediaAutoDownloadCategory(contacts: false, otherPrivate: false, groups: false, channels: false, sizeLimit: 1 * mb, predownload: false),
file: MediaAutoDownloadCategory(contacts: false, otherPrivate: false, groups: false, channels: false, sizeLimit: 1 * mb, predownload: false)), file: MediaAutoDownloadCategory(contacts: false, otherPrivate: false, groups: false, channels: false, sizeLimit: 1 * mb, predownload: false)),
medium: MediaAutoDownloadCategories(basePreset: .medium, photo: MediaAutoDownloadCategory(contacts: true, otherPrivate: true, groups: true, channels: true, sizeLimit: 1 * mb, predownload: false), medium: MediaAutoDownloadCategories(basePreset: .medium, photo: MediaAutoDownloadCategory(contacts: true, otherPrivate: true, groups: true, channels: true, sizeLimit: 1 * mb, predownload: false),
video: MediaAutoDownloadCategory(contacts: true, otherPrivate: true, groups: true, channels: true, sizeLimit: Int64(2.5 * CGFloat(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)), file: MediaAutoDownloadCategory(contacts: true, otherPrivate: true, groups: true, channels: true, sizeLimit: 1 * mb, predownload: false)),
high: MediaAutoDownloadCategories(basePreset: .high, photo: MediaAutoDownloadCategory(contacts: true, otherPrivate: true, groups: true, channels: true, sizeLimit: 1 * mb, predownload: false), high: MediaAutoDownloadCategories(basePreset: .high, photo: MediaAutoDownloadCategory(contacts: true, otherPrivate: true, groups: true, channels: true, sizeLimit: 1 * mb, predownload: false),
video: MediaAutoDownloadCategory(contacts: true, otherPrivate: true, groups: true, channels: true, sizeLimit: 10 * mb, predownload: true), video: MediaAutoDownloadCategory(contacts: true, otherPrivate: true, groups: true, channels: true, sizeLimit: 10 * mb, predownload: true),
file: MediaAutoDownloadCategory(contacts: true, otherPrivate: true, groups: true, channels: true, sizeLimit: 3 * mb, predownload: false))) file: MediaAutoDownloadCategory(contacts: true, otherPrivate: true, groups: true, channels: true, sizeLimit: 3 * mb, predownload: false)))
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) 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.presets = presets
self.cellular = cellular self.cellular = cellular
self.wifi = wifi self.wifi = wifi
self.autoplayGifs = autoplayGifs self.autoplayGifs = autoplayGifs
self.autoplayVideos = autoplayGifs self.autoplayVideos = autoplayGifs
self.downloadInBackground = downloadInBackground self.downloadInBackground = downloadInBackground
self.energyUsageSettings = energyUsageSettings
} }
public init(from decoder: Decoder) throws { 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.autoplayGifs = try container.decode(Int32.self, forKey: "autoplayGifs") != 0
self.autoplayVideos = try container.decode(Int32.self, forKey: "autoplayVideos") != 0 self.autoplayVideos = try container.decode(Int32.self, forKey: "autoplayVideos") != 0
self.downloadInBackground = try container.decode(Int32.self, forKey: "downloadInBackground") != 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 { 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.autoplayGifs ? 1 : 0) as Int32, forKey: "autoplayGifs")
try container.encode((self.autoplayVideos ? 1 : 0) as Int32, forKey: "autoplayVideos") 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.downloadInBackground ? 1 : 0) as Int32, forKey: "downloadInBackground")
try container.encode(self.energyUsageSettings, forKey: "energyUsageSettings")
} }
public func connectionSettings(for networkType: MediaAutoDownloadNetworkType) -> MediaAutoDownloadConnection { public func connectionSettings(for networkType: MediaAutoDownloadNetworkType) -> MediaAutoDownloadConnection {

View File

@ -1,5 +1,5 @@
{ {
"app": "9.4", "app": "9.4.2",
"bazel": "5.3.1", "bazel": "5.3.1",
"xcode": "14.2" "xcode": "14.2"
} }