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
run: |
set -x
sudo mkdir /Users/telegram
sudo chown -R $(whoami) /Users/telegram
cp -R $GITHUB_WORKSPACE /Users/telegram/
mv /Users/telegram/$(basename $GITHUB_WORKSPACE) /Users/telegram/telegram-ios
sudo mkdir -p /Users/Shared
cp -R $GITHUB_WORKSPACE /Users/Shared/
mv /Users/Shared/$(basename $GITHUB_WORKSPACE) /Users/Shared/telegram-ios
- name: Build the App
run: |
set -x
# source code paths are included in the final binary, so we need to make them stable across builds
SOURCE_DIR=/Users/telegram/telegram-ios
SOURCE_DIR=/Users/Shared/telegram-ios
# use canonical bazel root
BAZEL_USER_ROOT="/private/var/tmp/_bazel_telegram"
BAZEL_USER_ROOT="/private/var/tmp/_bazel_containerhost"
cd $SOURCE_DIR
@ -50,37 +49,14 @@ jobs:
echo "BUILD_NUMBER=$(echo $BUILD_NUMBER)" >> $GITHUB_ENV
echo "APP_VERSION=$(echo $APP_VERSION)" >> $GITHUB_ENV
# prepare temporary keychain
export MY_KEYCHAIN="temp.keychain"
export MY_KEYCHAIN_PASSWORD="secret"
security create-keychain -p "$MY_KEYCHAIN_PASSWORD" "$MY_KEYCHAIN"
security list-keychains -d user -s "$MY_KEYCHAIN" $(security list-keychains -d user | sed s/\"//g)
security set-keychain-settings "$MY_KEYCHAIN"
security unlock-keychain -p "$MY_KEYCHAIN_PASSWORD" "$MY_KEYCHAIN"
# install fake certificates
export CERTS_PATH="build-system/fake-codesigning/certs/distribution"
for f in "$CERTS_PATH"/*.p12; do
security import "$f" -k "$MY_KEYCHAIN" -P "" -T /usr/bin/codesign -T /usr/bin/security || true
done
for f in "$CERTS_PATH"/*.cer; do
security import "$f" -k "$MY_KEYCHAIN" -P "" -T /usr/bin/codesign -T /usr/bin/security || true
done
security set-key-partition-list -S apple-tool:,apple: -k "$MY_KEYCHAIN_PASSWORD" "$MY_KEYCHAIN"
# use the official release configuration
rm -rf $HOME/telegram-configuration
mkdir -p $HOME/telegram-configuration
cp -R build-system/example-configuration/* $HOME/telegram-configuration/
# build the app
python3 build-system/Make/Make.py \
python3 build-system/Make/ImportCertificates.py --path build-system/fake-codesigning/certs
python3 -u build-system/Make/Make.py \
--bazelUserRoot="$BAZEL_USER_ROOT" \
build \
--disableParallelSwiftmoduleGeneration \
--configurationPath="$HOME/telegram-configuration" \
--buildNumber=$BUILD_NUMBER \
--configuration=release_universal
--configurationPath="build-system/appstore-configuration.json" \
--codesigningInformationPath=build-system/fake-codesigning \
--configuration=release_arm64 \
--buildNumber="$BUILD_NUMBER"
# collect ipa
OUTPUT_PATH="build/artifacts"
@ -117,7 +93,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: /Users/telegram/telegram-ios/build/artifacts/Telegram.ipa
asset_path: /Users/Shared/telegram-ios/build/artifacts/Telegram.ipa
asset_name: Telegram.ipa
asset_content_type: application/zip
@ -128,6 +104,6 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: /Users/telegram/telegram-ios/build/artifacts/Telegram.DSYMs.zip
asset_path: /Users/Shared/telegram-ios/build/artifacts/Telegram.DSYMs.zip
asset_name: Telegram.DSYMs.zip
asset_content_type: application/zip

View File

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

View File

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

View File

@ -31,8 +31,8 @@ private struct ArchivedStickersNoticeEntry: Comparable, Identifiable {
return lhs.index < rhs.index
}
func item(account: Account, presentationData: PresentationData) -> ListViewItem {
return ItemListStickerPackItem(presentationData: ItemListPresentationData(presentationData), account: account, packInfo: info, itemCount: self.count, topItem: topItem, unread: false, control: .none, editing: ItemListStickerPackItemEditing(editable: false, editing: false, revealed: false, reorderable: false, selectable: false), enabled: true, playAnimatedStickers: true, sectionId: 0, action: {
func item(context: AccountContext, presentationData: PresentationData) -> ListViewItem {
return ItemListStickerPackItem(presentationData: ItemListPresentationData(presentationData), context: context, packInfo: info, itemCount: self.count, topItem: topItem, unread: false, control: .none, editing: ItemListStickerPackItemEditing(editable: false, editing: false, revealed: false, reorderable: false, selectable: false), enabled: true, playAnimatedStickers: true, sectionId: 0, action: {
}, setPackIdWithRevealedOptions: { current, previous in
}, addPack: {
}, removePack: {
@ -47,12 +47,12 @@ private struct ArchivedStickersNoticeTransition {
let updates: [ListViewUpdateItem]
}
private func preparedTransition(from fromEntries: [ArchivedStickersNoticeEntry], to toEntries: [ArchivedStickersNoticeEntry], account: Account, presentationData: PresentationData) -> ArchivedStickersNoticeTransition {
private func preparedTransition(from fromEntries: [ArchivedStickersNoticeEntry], to toEntries: [ArchivedStickersNoticeEntry], context: AccountContext, presentationData: PresentationData) -> ArchivedStickersNoticeTransition {
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, presentationData: presentationData), directionHint: nil) }
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, presentationData: presentationData), directionHint: nil) }
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData), directionHint: nil) }
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData), directionHint: nil) }
return ArchivedStickersNoticeTransition(deletions: deletions, insertions: insertions, updates: updates)
}
@ -79,7 +79,7 @@ private final class ArchivedStickersNoticeAlertContentNode: AlertContentNode {
return self.isUserInteractionEnabled
}
init(theme: AlertControllerTheme, account: Account, presentationData: PresentationData, archivedStickerPacks: [(StickerPackCollectionInfo, StickerPackItem?)], actions: [TextAlertAction]) {
init(theme: AlertControllerTheme, context: AccountContext, presentationData: PresentationData, archivedStickerPacks: [(StickerPackCollectionInfo, StickerPackItem?)], actions: [TextAlertAction]) {
self.presentationData = presentationData
self.archivedStickerPacks = archivedStickerPacks
@ -139,7 +139,7 @@ private final class ArchivedStickersNoticeAlertContentNode: AlertContentNode {
index += 1
}
let transition = preparedTransition(from: [], to: entries, account: account, presentationData: presentationData)
let transition = preparedTransition(from: [], to: entries, context: context, presentationData: presentationData)
self.enqueueTransition(transition)
}
@ -304,7 +304,7 @@ public func archivedStickerPacksNoticeController(context: AccountContext, archiv
let disposable = MetaDisposable()
let contentNode = ArchivedStickersNoticeAlertContentNode(theme: AlertControllerTheme(presentationData: presentationData), account: context.account, presentationData: presentationData, archivedStickerPacks: archivedStickerPacks, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {
let contentNode = ArchivedStickersNoticeAlertContentNode(theme: AlertControllerTheme(presentationData: presentationData), context: context, presentationData: presentationData, archivedStickerPacks: archivedStickerPacks, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {
dismissImpl?()
})])

View File

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

View File

@ -13,6 +13,7 @@ import SearchUI
import ContextUI
import AnimationCache
import MultiAnimationRenderer
import TelegramUIPreferences
public enum ChatListContainerNodeFilter: Equatable {
case all
@ -648,13 +649,26 @@ public final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDele
return (state, filterId)
})
let enablePreload = context.sharedContext.accountManager.sharedData(keys: Set([ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings]))
|> map { sharedData -> Bool in
var automaticMediaDownloadSettings: MediaAutoDownloadSettings
if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings]?.get(MediaAutoDownloadSettings.self) {
automaticMediaDownloadSettings = value
} else {
automaticMediaDownloadSettings = MediaAutoDownloadSettings.defaultSettings
}
return automaticMediaDownloadSettings.energyUsageSettings.autodownloadInBackground
}
|> distinctUntilChanged
if self.controlsHistoryPreload, case .chatList(groupId: .root) = self.location {
self.context.account.viewTracker.chatListPreloadItems.set(combineLatest(queue: .mainQueue(),
context.sharedContext.hasOngoingCall.get(),
itemNode.listNode.preloadItems.get()
itemNode.listNode.preloadItems.get(),
enablePreload
)
|> map { hasOngoingCall, preloadItems -> Set<ChatHistoryPreloadItem> in
if hasOngoingCall {
|> map { hasOngoingCall, preloadItems, enablePreload -> Set<ChatHistoryPreloadItem> in
if hasOngoingCall || !enablePreload {
return Set()
} else {
return Set(preloadItems)

View File

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

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.isVisibleForAnimations = animateIdle
animationLayer.isVisibleForAnimations = animateIdle && context.sharedContext.energyUsageSettings.loopEmoji
}
func reset() {

View File

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

View File

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

View File

@ -107,7 +107,7 @@ final class TrendingTopItemNode: ASDisplayNode {
}
if let placeholderNode = self.placeholderNode, let file = self.file {
placeholderNode.update(backgroundColor: backgroundColor, foregroundColor: foregroundColor, shimmeringColor: shimmeringColor, data: file.immediateThumbnailData, size: self.itemSize ?? CGSize(width: 75.0, height: 75.0))
placeholderNode.update(backgroundColor: backgroundColor, foregroundColor: foregroundColor, shimmeringColor: shimmeringColor, data: file.immediateThumbnailData, size: self.itemSize ?? CGSize(width: 75.0, height: 75.0), enableEffect: true)
}
}

View File

@ -76,7 +76,7 @@ final class InstantPageImageNode: ASDisplayNode, InstantPageNode {
let imageReference = ImageMediaReference.webPage(webPage: WebpageReference(webPage), media: image)
self.imageNode.setSignal(chatMessagePhoto(postbox: context.account.postbox, userLocation: sourceLocation.userLocation, photoReference: imageReference))
if !interactive || shouldDownloadMediaAutomatically(settings: context.sharedContext.currentAutomaticMediaDownloadSettings.with { $0 }, peerType: sourceLocation.peerType, networkType: MediaAutoDownloadNetworkType(context.account.immediateNetworkType), authorPeerId: nil, contactsPeerIds: Set(), media: image) {
if !interactive || shouldDownloadMediaAutomatically(settings: context.sharedContext.currentAutomaticMediaDownloadSettings, peerType: sourceLocation.peerType, networkType: MediaAutoDownloadNetworkType(context.account.immediateNetworkType), authorPeerId: nil, contactsPeerIds: Set(), media: image) {
self.fetchedDisposable.set(chatMessagePhotoInteractiveFetched(context: context, userLocation: sourceLocation.userLocation, photoReference: imageReference, displayAtSize: nil, storeToDownloadsPeerId: nil).start())
}
@ -108,7 +108,7 @@ final class InstantPageImageNode: ASDisplayNode, InstantPageNode {
} else if let file = media.media as? TelegramMediaFile {
let fileReference = FileMediaReference.webPage(webPage: WebpageReference(webPage), media: file)
if file.mimeType.hasPrefix("image/") {
if !interactive || shouldDownloadMediaAutomatically(settings: context.sharedContext.currentAutomaticMediaDownloadSettings.with { $0 }, peerType: sourceLocation.peerType, networkType: MediaAutoDownloadNetworkType(context.account.immediateNetworkType), authorPeerId: nil, contactsPeerIds: Set(), media: file) {
if !interactive || shouldDownloadMediaAutomatically(settings: context.sharedContext.currentAutomaticMediaDownloadSettings, peerType: sourceLocation.peerType, networkType: MediaAutoDownloadNetworkType(context.account.immediateNetworkType), authorPeerId: nil, contactsPeerIds: Set(), media: file) {
_ = freeMediaFileInteractiveFetched(account: context.account, userLocation: sourceLocation.userLocation, fileReference: fileReference).start()
}
self.imageNode.setSignal(instantPageImageFile(account: context.account, userLocation: sourceLocation.userLocation, fileReference: fileReference, fetched: true))

View File

@ -12,6 +12,7 @@ import StickerResources
import AnimatedStickerNode
import TelegramAnimatedStickerNode
import ShimmerEffect
import AccountContext
public struct ItemListStickerPackItemEditing: Equatable {
public var editable: Bool
@ -38,7 +39,7 @@ public enum ItemListStickerPackItemControl: Equatable {
public final class ItemListStickerPackItem: ListViewItem, ItemListItem {
let presentationData: ItemListPresentationData
let account: Account
let context: AccountContext
let packInfo: StickerPackCollectionInfo
let itemCount: String
let topItem: StickerPackItem?
@ -54,9 +55,9 @@ public final class ItemListStickerPackItem: ListViewItem, ItemListItem {
let removePack: () -> Void
let toggleSelected: () -> Void
public init(presentationData: ItemListPresentationData, account: Account, packInfo: StickerPackCollectionInfo, itemCount: String, topItem: StickerPackItem?, unread: Bool, control: ItemListStickerPackItemControl, editing: ItemListStickerPackItemEditing, enabled: Bool, playAnimatedStickers: Bool, sectionId: ItemListSectionId, action: (() -> Void)?, setPackIdWithRevealedOptions: @escaping (ItemCollectionId?, ItemCollectionId?) -> Void, addPack: @escaping () -> Void, removePack: @escaping () -> Void, toggleSelected: @escaping () -> Void) {
public init(presentationData: ItemListPresentationData, context: AccountContext, packInfo: StickerPackCollectionInfo, itemCount: String, topItem: StickerPackItem?, unread: Bool, control: ItemListStickerPackItemControl, editing: ItemListStickerPackItemEditing, enabled: Bool, playAnimatedStickers: Bool, sectionId: ItemListSectionId, action: (() -> Void)?, setPackIdWithRevealedOptions: @escaping (ItemCollectionId?, ItemCollectionId?) -> Void, addPack: @escaping () -> Void, removePack: @escaping () -> Void, toggleSelected: @escaping () -> Void) {
self.presentationData = presentationData
self.account = account
self.context = context
self.packInfo = packInfo
self.itemCount = itemCount
self.topItem = topItem
@ -506,18 +507,18 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode {
if fileUpdated {
imageApply = makeImageLayout(TransformImageArguments(corners: ImageCorners(), imageSize: stillImageSize, boundingSize: stillImageSize, intrinsicInsets: UIEdgeInsets()))
updatedImageSignal = chatMessageStickerPackThumbnail(postbox: item.account.postbox, resource: representation.resource, nilIfEmpty: true)
updatedImageSignal = chatMessageStickerPackThumbnail(postbox: item.context.account.postbox, resource: representation.resource, nilIfEmpty: true)
}
case let .animated(resource, dimensions, _):
imageSize = dimensions.cgSize.aspectFitted(imageBoundingSize)
if fileUpdated {
imageApply = makeImageLayout(TransformImageArguments(corners: ImageCorners(), imageSize: imageBoundingSize, boundingSize: imageBoundingSize, intrinsicInsets: UIEdgeInsets()))
updatedImageSignal = chatMessageStickerPackThumbnail(postbox: item.account.postbox, resource: resource, animated: true, nilIfEmpty: true)
updatedImageSignal = chatMessageStickerPackThumbnail(postbox: item.context.account.postbox, resource: resource, animated: true, nilIfEmpty: true)
}
}
if fileUpdated, let resourceReference = resourceReference {
updatedFetchSignal = fetchedMediaResource(mediaBox: item.account.postbox.mediaBox, userLocation: .other, userContentType: .sticker, reference: resourceReference)
updatedFetchSignal = fetchedMediaResource(mediaBox: item.context.account.postbox.mediaBox, userLocation: .other, userContentType: .sticker, reference: resourceReference)
}
} else {
updatedImageSignal = .single({ _ in return nil })
@ -768,7 +769,7 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode {
strongSelf.animationNode = animationNode
strongSelf.addSubnode(animationNode)
animationNode.setup(source: AnimatedStickerResourceSource(account: item.account, resource: resource, isVideo: isVideo), width: 80, height: 80, playbackMode: .loop, mode: .direct(cachePathPrefix: nil))
animationNode.setup(source: AnimatedStickerResourceSource(account: item.context.account, resource: resource, isVideo: isVideo), width: 80, height: 80, playbackMode: .loop, mode: .direct(cachePathPrefix: nil))
}
animationNode.visibility = strongSelf.visibility != .none && item.playAnimatedStickers
animationNode.isHidden = !item.playAnimatedStickers
@ -794,7 +795,7 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode {
placeholderNode.frame = imageFrame
placeholderNode.update(backgroundColor: nil, foregroundColor: item.presentationData.theme.list.disclosureArrowColor.blitOver(item.presentationData.theme.list.itemBlocksBackgroundColor, alpha: 0.55), shimmeringColor: item.presentationData.theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.4), data: immediateThumbnailData, size: imageFrame.size, imageSize: imageSize.cgSize)
placeholderNode.update(backgroundColor: nil, foregroundColor: item.presentationData.theme.list.disclosureArrowColor.blitOver(item.presentationData.theme.list.itemBlocksBackgroundColor, alpha: 0.55), shimmeringColor: item.presentationData.theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.4), data: immediateThumbnailData, size: imageFrame.size, enableEffect: item.context.sharedContext.energyUsageSettings.fullTranslucency, imageSize: imageSize.cgSize)
}
if let updatedImageSignal = updatedImageSignal {

View File

@ -35,7 +35,7 @@ public enum TwoFactorDataInputMode {
case authorized
}
case password(doneText: String)
case password(phoneNumber: String?, doneText: String)
case passwordRecoveryEmail(emailPattern: String, mode: PasswordRecoveryEmailMode, doneText: String)
case passwordRecovery(recovery: Recovery, doneText: String)
case emailAddress(password: String, hint: String, doneText: String)
@ -99,8 +99,11 @@ public final class TwoFactorDataInputScreen: ViewController {
public override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if case .rememberPassword = self.mode {
switch self.mode {
case .rememberPassword, .password:
(self.displayNode as? TwoFactorDataInputScreenNode)?.focus()
default:
break
}
}
@ -110,7 +113,7 @@ public final class TwoFactorDataInputScreen: ViewController {
return
}
switch strongSelf.mode {
case let .password(doneText):
case let .password(_, doneText):
let values = (strongSelf.displayNode as! TwoFactorDataInputScreenNode).inputText
if values.count != 2 {
return
@ -924,7 +927,7 @@ public final class TwoFactorDataInputScreen: ViewController {
}
private enum TwoFactorDataInputTextNodeType {
case password(confirmation: Bool)
case password(phoneNumber: String?, confirmation: Bool)
case email
case code
case hint
@ -984,6 +987,7 @@ private final class TwoFactorDataInputTextNode: ASDisplayNode, UITextFieldDelega
private let toggleTextHidden: (TwoFactorDataInputTextNode) -> Void
private let backgroundNode: ASImageNode
private var shadowInputNode: TextFieldNode?
private let inputNode: TextFieldNode
private let hideButtonNode: HighlightableButtonNode
private let clearButtonNode: HighlightableButtonNode
@ -1068,7 +1072,7 @@ private final class TwoFactorDataInputTextNode: ASDisplayNode, UITextFieldDelega
self.hideButtonNode = HighlightableButtonNode()
switch mode {
case let .password(confirmation):
case let .password(phoneNumber, confirmation):
self.inputNode.textField.keyboardType = .default
self.inputNode.textField.isSecureTextEntry = true
if confirmation {
@ -1076,29 +1080,68 @@ private final class TwoFactorDataInputTextNode: ASDisplayNode, UITextFieldDelega
} else {
self.inputNode.textField.returnKeyType = .next
}
if #available(iOS 12.0, *) {
if !confirmation, let phoneNumber {
let shadowInputNode = TextFieldNode()
shadowInputNode.textField.font = Font.regular(17.0)
shadowInputNode.textField.textColor = theme.list.freePlainInputField.primaryColor
shadowInputNode.textField.attributedPlaceholder = NSAttributedString(string: placeholder, font: Font.regular(17.0), textColor: theme.list.freePlainInputField.placeholderColor)
self.shadowInputNode = shadowInputNode
shadowInputNode.textField.textContentType = .username
shadowInputNode.textField.text = phoneNumber
}
self.inputNode.textField.textContentType = .newPassword
self.inputNode.textField.passwordRules = UITextInputPasswordRules(descriptor: "minlength: 8;")
}
self.hideButtonNode.isHidden = confirmation
case .email:
self.inputNode.textField.keyboardType = .emailAddress
self.inputNode.textField.returnKeyType = .done
self.hideButtonNode.isHidden = true
if #available(iOS 12.0, *) {
self.inputNode.textField.textContentType = .emailAddress
}
self.inputNode.textField.autocorrectionType = .no
self.inputNode.textField.autocapitalizationType = .none
self.inputNode.textField.spellCheckingType = .no
if #available(iOS 11.0, *) {
self.inputNode.textField.smartQuotesType = .no
self.inputNode.textField.smartDashesType = .no
self.inputNode.textField.smartInsertDeleteType = .no
}
case .code:
self.inputNode.textField.keyboardType = .numberPad
self.inputNode.textField.returnKeyType = .done
self.hideButtonNode.isHidden = true
self.inputNode.textField.autocorrectionType = .no
self.inputNode.textField.autocapitalizationType = .none
self.inputNode.textField.spellCheckingType = .no
if #available(iOS 11.0, *) {
self.inputNode.textField.smartQuotesType = .no
self.inputNode.textField.smartDashesType = .no
self.inputNode.textField.smartInsertDeleteType = .no
}
case .hint:
self.inputNode.textField.keyboardType = .asciiCapable
self.inputNode.textField.returnKeyType = .done
self.hideButtonNode.isHidden = true
self.inputNode.textField.autocorrectionType = .no
self.inputNode.textField.autocapitalizationType = .none
self.inputNode.textField.spellCheckingType = .no
if #available(iOS 11.0, *) {
self.inputNode.textField.smartQuotesType = .no
self.inputNode.textField.smartDashesType = .no
self.inputNode.textField.smartInsertDeleteType = .no
}
}
self.inputNode.textField.autocorrectionType = .no
self.inputNode.textField.autocapitalizationType = .none
self.inputNode.textField.spellCheckingType = .no
if #available(iOS 11.0, *) {
self.inputNode.textField.smartQuotesType = .no
self.inputNode.textField.smartDashesType = .no
self.inputNode.textField.smartInsertDeleteType = .no
}
self.inputNode.textField.keyboardAppearance = theme.rootController.keyboardColor.keyboardAppearance
self.hideButtonNode.setImage(generateTextHiddenImage(color: theme.list.freePlainInputField.controlColor, on: false), for: [])
@ -1110,6 +1153,10 @@ private final class TwoFactorDataInputTextNode: ASDisplayNode, UITextFieldDelega
super.init()
self.addSubnode(self.backgroundNode)
if let shadowInputNode = self.shadowInputNode {
shadowInputNode.alpha = 0.001
self.addSubnode(shadowInputNode)
}
self.addSubnode(self.inputNode)
self.addSubnode(self.hideButtonNode)
@ -1179,6 +1226,10 @@ private final class TwoFactorDataInputTextNode: ASDisplayNode, UITextFieldDelega
let leftInset: CGFloat = 16.0
let rightInset: CGFloat = 38.0
if let shadowInputNode = self.shadowInputNode {
transition.updateFrame(node: shadowInputNode, frame: CGRect(origin: CGPoint(x: leftInset, y: 0.0), size: CGSize(width: size.width - leftInset - rightInset, height: size.height)))
}
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: size))
transition.updateFrame(node: self.inputNode, frame: CGRect(origin: CGPoint(x: leftInset, y: 0.0), size: CGSize(width: size.width - leftInset - rightInset, height: size.height)))
transition.updateFrame(node: self.hideButtonNode, frame: CGRect(origin: CGPoint(x: size.width - rightInset - 4.0, y: 0.0), size: CGSize(width: rightInset + 4.0, height: size.height)))
@ -1299,7 +1350,7 @@ private final class TwoFactorDataInputScreenNode: ViewControllerTracingNode, UIS
var toggleTextHidden: ((TwoFactorDataInputTextNode) -> Void)?
switch mode {
case .password:
case let .password(phoneNumber, _):
title = presentationData.strings.TwoFactorSetup_Password_Title
text = NSAttributedString(string: "", font: Font.regular(16.0), textColor: presentationData.theme.list.itemPrimaryTextColor)
buttonText = presentationData.strings.TwoFactorSetup_Password_Action
@ -1307,7 +1358,7 @@ private final class TwoFactorDataInputScreenNode: ViewControllerTracingNode, UIS
changeEmailActionText = ""
resendCodeActionText = ""
inputNodes = [
TwoFactorDataInputTextNode(theme: presentationData.theme, mode: .password(confirmation: false), placeholder: presentationData.strings.TwoFactorSetup_Password_PlaceholderPassword, focusUpdated: { node, focused in
TwoFactorDataInputTextNode(theme: presentationData.theme, mode: .password(phoneNumber: phoneNumber, confirmation: false), placeholder: presentationData.strings.TwoFactorSetup_Password_PlaceholderPassword, focusUpdated: { node, focused in
focusUpdated?(node, focused)
}, next: { node in
next?(node)
@ -1316,7 +1367,7 @@ private final class TwoFactorDataInputScreenNode: ViewControllerTracingNode, UIS
}, toggleTextHidden: { node in
toggleTextHidden?(node)
}),
TwoFactorDataInputTextNode(theme: presentationData.theme, mode: .password(confirmation: true), placeholder: presentationData.strings.TwoFactorSetup_Password_PlaceholderConfirmPassword, focusUpdated: { node, focused in
TwoFactorDataInputTextNode(theme: presentationData.theme, mode: .password(phoneNumber: phoneNumber, confirmation: true), placeholder: presentationData.strings.TwoFactorSetup_Password_PlaceholderConfirmPassword, focusUpdated: { node, focused in
focusUpdated?(node, focused)
}, next: { node in
next?(node)
@ -1334,7 +1385,7 @@ private final class TwoFactorDataInputScreenNode: ViewControllerTracingNode, UIS
changeEmailActionText = ""
resendCodeActionText = ""
inputNodes = [
TwoFactorDataInputTextNode(theme: presentationData.theme, mode: .password(confirmation: false), placeholder: presentationData.strings.TwoFactorSetup_PasswordRecovery_PlaceholderPassword, focusUpdated: { node, focused in
TwoFactorDataInputTextNode(theme: presentationData.theme, mode: .password(phoneNumber: nil, confirmation: false), placeholder: presentationData.strings.TwoFactorSetup_PasswordRecovery_PlaceholderPassword, focusUpdated: { node, focused in
focusUpdated?(node, focused)
}, next: { node in
next?(node)
@ -1343,7 +1394,7 @@ private final class TwoFactorDataInputScreenNode: ViewControllerTracingNode, UIS
}, toggleTextHidden: { node in
toggleTextHidden?(node)
}),
TwoFactorDataInputTextNode(theme: presentationData.theme, mode: .password(confirmation: true), placeholder: presentationData.strings.TwoFactorSetup_PasswordRecovery_PlaceholderConfirmPassword, focusUpdated: { node, focused in
TwoFactorDataInputTextNode(theme: presentationData.theme, mode: .password(phoneNumber: nil, confirmation: true), placeholder: presentationData.strings.TwoFactorSetup_PasswordRecovery_PlaceholderConfirmPassword, focusUpdated: { node, focused in
focusUpdated?(node, focused)
}, next: { node in
next?(node)
@ -1453,7 +1504,7 @@ private final class TwoFactorDataInputScreenNode: ViewControllerTracingNode, UIS
changeEmailActionText = ""
resendCodeActionText = ""
inputNodes = [
TwoFactorDataInputTextNode(theme: presentationData.theme, mode: .password(confirmation: false), placeholder: presentationData.strings.TwoFactorRemember_Placeholder, focusUpdated: { node, focused in
TwoFactorDataInputTextNode(theme: presentationData.theme, mode: .password(phoneNumber: nil, confirmation: false), placeholder: presentationData.strings.TwoFactorRemember_Placeholder, focusUpdated: { node, focused in
focusUpdated?(node, focused)
}, next: { node in
next?(node)

View File

@ -18,17 +18,20 @@ public enum TwoFactorAuthSplashMode {
public var text: String
public var actionText: String
public var doneText: String
public var phoneNumber: String?
public init(
title: String,
text: String,
actionText: String,
doneText: String
doneText: String,
phoneNumber: String?
) {
self.title = title
self.text = text
self.actionText = actionText
self.doneText = doneText
self.phoneNumber = phoneNumber
}
}
@ -100,7 +103,7 @@ public final class TwoFactorAuthSplashScreen: ViewController {
}
switch strongSelf.mode {
case let .intro(intro):
strongSelf.push(TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .password(doneText: intro.doneText), stateUpdated: { _ in
strongSelf.push(TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .password(phoneNumber: intro.phoneNumber, doneText: intro.doneText), stateUpdated: { _ in
}, presentation: strongSelf.navigationPresentation))
case .done, .remember:
guard let navigationController = strongSelf.navigationController as? NavigationController else {

View File

@ -13,15 +13,15 @@ import StickerPackPreviewUI
import ItemListStickerPackItem
private final class GroupStickerPackSetupControllerArguments {
let account: Account
let context: AccountContext
let selectStickerPack: (StickerPackCollectionInfo) -> Void
let openStickerPack: (StickerPackCollectionInfo) -> Void
let updateSearchText: (String) -> Void
let openStickersBot: () -> Void
init(account: Account, selectStickerPack: @escaping (StickerPackCollectionInfo) -> Void, openStickerPack: @escaping (StickerPackCollectionInfo) -> Void, updateSearchText: @escaping (String) -> Void, openStickersBot: @escaping () -> Void) {
self.account = account
init(context: AccountContext, selectStickerPack: @escaping (StickerPackCollectionInfo) -> Void, openStickerPack: @escaping (StickerPackCollectionInfo) -> Void, updateSearchText: @escaping (String) -> Void, openStickersBot: @escaping () -> Void) {
self.context = context
self.selectStickerPack = selectStickerPack
self.openStickerPack = openStickerPack
self.updateSearchText = updateSearchText
@ -218,7 +218,7 @@ private enum GroupStickerPackEntry: ItemListNodeEntry {
case let .packsTitle(_, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .pack(_, _, _, info, topItem, count, playAnimatedStickers, selected):
return ItemListStickerPackItem(presentationData: presentationData, account: arguments.account, packInfo: info, itemCount: count, topItem: topItem, unread: false, control: selected ? .selection : .none, editing: ItemListStickerPackItemEditing(editable: false, editing: false, revealed: false, reorderable: false, selectable: false), enabled: true, playAnimatedStickers: playAnimatedStickers, sectionId: self.section, action: {
return ItemListStickerPackItem(presentationData: presentationData, context: arguments.context, packInfo: info, itemCount: count, topItem: topItem, unread: false, control: selected ? .selection : .none, editing: ItemListStickerPackItemEditing(editable: false, editing: false, revealed: false, reorderable: false, selectable: false), enabled: true, playAnimatedStickers: playAnimatedStickers, sectionId: self.section, action: {
if selected {
arguments.openStickerPack(info)
} else {
@ -230,7 +230,7 @@ private enum GroupStickerPackEntry: ItemListNodeEntry {
}, toggleSelected: {
})
case let .currentPack(_, theme, strings, content):
return GroupStickerPackCurrentItem(theme: theme, strings: strings, account: arguments.account, content: content, sectionId: self.section, action: {
return GroupStickerPackCurrentItem(theme: theme, strings: strings, account: arguments.context.account, content: content, sectionId: self.section, action: {
if case let .found(packInfo, _, _) = content {
arguments.openStickerPack(packInfo)
}
@ -385,7 +385,7 @@ public func groupStickerPackSetupController(context: AccountContext, updatedPres
var presentStickerPackController: ((StickerPackCollectionInfo) -> Void)?
let arguments = GroupStickerPackSetupControllerArguments(account: context.account, selectStickerPack: { info in
let arguments = GroupStickerPackSetupControllerArguments(context: context, selectStickerPack: { info in
searchText.set(info.shortName)
}, openStickerPack: { info in
presentStickerPackController?(info)

View File

@ -268,7 +268,7 @@ private class StickerNode: ASDisplayNode {
if self.placeholderNode.supernode != nil {
let placeholderFrame = CGRect(origin: CGPoint(x: -10.0, y: 0.0), size: imageSize)
let thumbnailDimensions = PixelDimensions(width: 512, height: 512)
self.placeholderNode.update(backgroundColor: nil, foregroundColor: UIColor(rgb: 0xffffff, alpha: 0.2), shimmeringColor: UIColor(rgb: 0xffffff, alpha: 0.3), data: self.file.immediateThumbnailData, size: placeholderFrame.size, imageSize: thumbnailDimensions.cgSize)
self.placeholderNode.update(backgroundColor: nil, foregroundColor: UIColor(rgb: 0xffffff, alpha: 0.2), shimmeringColor: UIColor(rgb: 0xffffff, alpha: 0.3), data: self.file.immediateThumbnailData, size: placeholderFrame.size, enableEffect: true, imageSize: thumbnailDimensions.cgSize)
self.placeholderNode.frame = placeholderFrame
}
}

View File

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

View File

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

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,
text: presentationData.strings.TwoFactorSetup_Intro_Text,
actionText: presentationData.strings.TwoFactorSetup_Intro_Action,
doneText: presentationData.strings.TwoFactorSetup_Done_Action
doneText: presentationData.strings.TwoFactorSetup_Done_Action,
phoneNumber: nil
)))
replaceTopControllerImpl?(controller, false)

View File

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

View File

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

View File

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

View File

@ -13,13 +13,13 @@ import StickerPackPreviewUI
import ItemListStickerPackItem
private final class FeaturedStickerPacksControllerArguments {
let account: Account
let context: AccountContext
let openStickerPack: (StickerPackCollectionInfo) -> Void
let addPack: (StickerPackCollectionInfo) -> Void
init(account: Account, openStickerPack: @escaping (StickerPackCollectionInfo) -> Void, addPack: @escaping (StickerPackCollectionInfo) -> Void) {
self.account = account
init(context: AccountContext, openStickerPack: @escaping (StickerPackCollectionInfo) -> Void, addPack: @escaping (StickerPackCollectionInfo) -> Void) {
self.context = context
self.openStickerPack = openStickerPack
self.addPack = addPack
}
@ -102,7 +102,7 @@ private enum FeaturedStickerPacksEntry: ItemListNodeEntry {
let arguments = arguments as! FeaturedStickerPacksControllerArguments
switch self {
case let .pack(_, _, _, info, unread, topItem, count, playAnimatedStickers, installed):
return ItemListStickerPackItem(presentationData: presentationData, account: arguments.account, packInfo: info, itemCount: count, topItem: topItem, unread: unread, control: .installation(installed: installed), editing: ItemListStickerPackItemEditing(editable: false, editing: false, revealed: false, reorderable: false, selectable: false), enabled: true, playAnimatedStickers: playAnimatedStickers, sectionId: self.section, action: {
return ItemListStickerPackItem(presentationData: presentationData, context: arguments.context, packInfo: info, itemCount: count, topItem: topItem, unread: unread, control: .installation(installed: installed), editing: ItemListStickerPackItemEditing(editable: false, editing: false, revealed: false, reorderable: false, selectable: false), enabled: true, playAnimatedStickers: playAnimatedStickers, sectionId: self.section, action: {
arguments.openStickerPack(info)
}, setPackIdWithRevealedOptions: { _, _ in
}, addPack: {
@ -168,7 +168,7 @@ public func featuredStickerPacksController(context: AccountContext) -> ViewContr
var presentStickerPackController: ((StickerPackCollectionInfo) -> Void)?
let arguments = FeaturedStickerPacksControllerArguments(account: context.account, openStickerPack: { info in
let arguments = FeaturedStickerPacksControllerArguments(context: context, openStickerPack: { info in
presentStickerPackController?(info)
}, addPack: { info in
let _ = (context.engine.stickers.loadedStickerPack(reference: .id(id: info.id.id, accessHash: info.accessHash), forceActualized: false)

View File

@ -451,7 +451,7 @@ private indirect enum InstalledStickerPacksEntry: ItemListNodeEntry {
case let .trendingPacksTitle(_, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .trendingPack(_, _, _, info, topItem, count, animatedStickers, unread, installed):
return ItemListStickerPackItem(presentationData: presentationData, account: arguments.context.account, packInfo: info, itemCount: count, topItem: topItem, unread: unread, control: .installation(installed: installed), editing: ItemListStickerPackItemEditing(editable: false, editing: false, revealed: false, reorderable: false, selectable: false), enabled: true, playAnimatedStickers: animatedStickers, sectionId: self.section, action: {
return ItemListStickerPackItem(presentationData: presentationData, context: arguments.context, packInfo: info, itemCount: count, topItem: topItem, unread: unread, control: .installation(installed: installed), editing: ItemListStickerPackItemEditing(editable: false, editing: false, revealed: false, reorderable: false, selectable: false), enabled: true, playAnimatedStickers: animatedStickers, sectionId: self.section, action: {
arguments.openStickerPack(info)
}, setPackIdWithRevealedOptions: { _, _ in
}, addPack: {
@ -466,7 +466,7 @@ private indirect enum InstalledStickerPacksEntry: ItemListNodeEntry {
case let .packsTitle(_, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .pack(_, _, _, info, topItem, count, animatedStickers, enabled, editing, selected):
return ItemListStickerPackItem(presentationData: presentationData, account: arguments.context.account, packInfo: info, itemCount: count, topItem: topItem, unread: false, control: editing.editing ? .check(checked: selected ?? false) : .none, editing: editing, enabled: enabled, playAnimatedStickers: animatedStickers, sectionId: self.section, action: {
return ItemListStickerPackItem(presentationData: presentationData, context: arguments.context, packInfo: info, itemCount: count, topItem: topItem, unread: false, control: editing.editing ? .check(checked: selected ?? false) : .none, editing: editing, enabled: enabled, playAnimatedStickers: animatedStickers, sectionId: self.section, action: {
arguments.openStickerPack(info)
}, setPackIdWithRevealedOptions: { current, previous in
arguments.setPackIdWithRevealedOptions(current, previous)

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())
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
}

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())
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
}

View File

@ -90,6 +90,8 @@ public class StickerShimmerEffectNode: ASDisplayNode {
self.backdropNode = backdropNode
self.insertSubnode(backdropNode, at: 0)
backdropNode.isHidden = self.effectNode.isHidden
self.effectNode.layer.compositingFilter = "screenBlendMode"
}
@ -97,7 +99,7 @@ public class StickerShimmerEffectNode: ASDisplayNode {
self.effectNode.updateAbsoluteRect(rect, within: containerSize)
}
public func update(backgroundColor: UIColor?, foregroundColor: UIColor, shimmeringColor: UIColor, data: Data?, size: CGSize, imageSize: CGSize = CGSize(width: 512.0, height: 512.0)) {
public func update(backgroundColor: UIColor?, foregroundColor: UIColor, shimmeringColor: UIColor, data: Data?, size: CGSize, enableEffect: Bool, imageSize: CGSize = CGSize(width: 512.0, height: 512.0)) {
if data == nil {
return
}
@ -112,13 +114,18 @@ public class StickerShimmerEffectNode: ASDisplayNode {
self.currentSize = size
self.backgroundNode.backgroundColor = foregroundColor
self.backgroundNode.isHidden = !enableEffect
self.effectNode.update(backgroundColor: backgroundColor == nil ? .clear : foregroundColor, foregroundColor: shimmeringColor, horizontal: true, effectSize: nil, globalTimeOffset: true, duration: nil)
if enableEffect {
self.effectNode.update(backgroundColor: backgroundColor == nil ? .clear : foregroundColor, foregroundColor: shimmeringColor, horizontal: true, effectSize: nil, globalTimeOffset: true, duration: nil)
}
self.effectNode.isHidden = !enableEffect
self.backdropNode?.isHidden = !enableEffect
let bounds = CGRect(origin: CGPoint(), size: size)
let image = generateStickerPlaceholderImage(data: data, size: size, imageSize: imageSize, backgroundColor: backgroundColor, foregroundColor: .black)
let image = generateStickerPlaceholderImage(data: data, size: size, imageSize: imageSize, backgroundColor: backgroundColor, foregroundColor: enableEffect ? .black : foregroundColor)
if backgroundColor == nil {
if backgroundColor == nil && enableEffect {
self.foregroundNode.image = nil
let maskView: UIImageView

View File

@ -13,6 +13,7 @@ import TextFormat
import AccountContext
import ContextUI
import StickerPeekUI
import AccountContext
private struct StickerPackPreviewGridEntry: Comparable, Identifiable {
let index: Int
@ -26,8 +27,8 @@ private struct StickerPackPreviewGridEntry: Comparable, Identifiable {
return lhs.index < rhs.index
}
func item(account: Account, interaction: StickerPackPreviewInteraction, theme: PresentationTheme) -> StickerPackPreviewGridItem {
return StickerPackPreviewGridItem(account: account, stickerItem: self.stickerItem, interaction: interaction, theme: theme, isPremium: false, isLocked: false, isEmpty: false)
func item(context: AccountContext, interaction: StickerPackPreviewInteraction, theme: PresentationTheme) -> StickerPackPreviewGridItem {
return StickerPackPreviewGridItem(context: context, stickerItem: self.stickerItem, interaction: interaction, theme: theme, isPremium: false, isLocked: false, isEmpty: false)
}
}
@ -36,12 +37,12 @@ private struct StickerPackPreviewGridTransaction {
let insertions: [GridNodeInsertItem]
let updates: [GridNodeUpdateItem]
init(previousList: [StickerPackPreviewGridEntry], list: [StickerPackPreviewGridEntry], account: Account, interaction: StickerPackPreviewInteraction, theme: PresentationTheme) {
init(previousList: [StickerPackPreviewGridEntry], list: [StickerPackPreviewGridEntry], context: AccountContext, interaction: StickerPackPreviewInteraction, theme: PresentationTheme) {
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: previousList, rightList: list)
self.deletions = deleteIndices
self.insertions = indicesAndItems.map { GridNodeInsertItem(index: $0.0, item: $0.1.item(account: account, interaction: interaction, theme: theme), previousIndex: $0.2) }
self.updates = updateIndices.map { GridNodeUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, interaction: interaction, theme: theme)) }
self.insertions = indicesAndItems.map { GridNodeInsertItem(index: $0.0, item: $0.1.item(context: context, interaction: interaction, theme: theme), previousIndex: $0.2) }
self.updates = updateIndices.map { GridNodeUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, interaction: interaction, theme: theme)) }
}
}
@ -403,7 +404,7 @@ final class StickerPackPreviewControllerNode: ViewControllerTracingNode, UIScrol
self.contentTitleNode.attributedText = stringWithAppliedEntities(info.title, entities: entities, baseColor: self.presentationData.theme.actionSheet.primaryTextColor, linkColor: self.presentationData.theme.actionSheet.controlAccentColor, baseFont: font, linkFont: font, boldFont: font, italicFont: font, boldItalicFont: font, fixedFont: font, blockQuoteFont: font, message: nil)
animateIn = true
}
transaction = StickerPackPreviewGridTransaction(previousList: self.currentItems, list: updatedItems, account: self.context.account, interaction: self.interaction, theme: self.presentationData.theme)
transaction = StickerPackPreviewGridTransaction(previousList: self.currentItems, list: updatedItems, context: self.context, interaction: self.interaction, theme: self.presentationData.theme)
self.currentItems = updatedItems
}
}

View File

@ -33,7 +33,7 @@ final class StickerPackPreviewInteraction {
}
final class StickerPackPreviewGridItem: GridItem {
let account: Account
let context: AccountContext
let stickerItem: StickerPackItem?
let interaction: StickerPackPreviewInteraction
let theme: PresentationTheme
@ -43,8 +43,8 @@ final class StickerPackPreviewGridItem: GridItem {
let section: GridSection? = nil
init(account: Account, stickerItem: StickerPackItem?, interaction: StickerPackPreviewInteraction, theme: PresentationTheme, isPremium: Bool, isLocked: Bool, isEmpty: Bool) {
self.account = account
init(context: AccountContext, stickerItem: StickerPackItem?, interaction: StickerPackPreviewInteraction, theme: PresentationTheme, isPremium: Bool, isLocked: Bool, isEmpty: Bool) {
self.context = context
self.stickerItem = stickerItem
self.interaction = interaction
self.theme = theme
@ -55,7 +55,7 @@ final class StickerPackPreviewGridItem: GridItem {
func node(layout: GridNodeLayout, synchronousLoad: Bool) -> GridItemNode {
let node = StickerPackPreviewGridItemNode()
node.setup(account: self.account, stickerItem: self.stickerItem, interaction: self.interaction, theme: self.theme, isLocked: self.isLocked, isPremium: self.isPremium, isEmpty: self.isEmpty)
node.setup(context: self.context, stickerItem: self.stickerItem, interaction: self.interaction, theme: self.theme, isLocked: self.isLocked, isPremium: self.isPremium, isEmpty: self.isEmpty)
return node
}
@ -64,14 +64,14 @@ final class StickerPackPreviewGridItem: GridItem {
assertionFailure()
return
}
node.setup(account: self.account, stickerItem: self.stickerItem, interaction: self.interaction, theme: self.theme, isLocked: self.isLocked, isPremium: self.isPremium, isEmpty: self.isEmpty)
node.setup(context: self.context, stickerItem: self.stickerItem, interaction: self.interaction, theme: self.theme, isLocked: self.isLocked, isPremium: self.isPremium, isEmpty: self.isEmpty)
}
}
private let textFont = Font.regular(20.0)
final class StickerPackPreviewGridItemNode: GridItemNode {
private var currentState: (Account, StickerPackItem?)?
private var currentState: (AccountContext, StickerPackItem?)?
private var isLocked: Bool?
private var isPremium: Bool?
private var isEmpty: Bool?
@ -173,11 +173,11 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
}
private var setupTimestamp: Double?
func setup(account: Account, stickerItem: StickerPackItem?, interaction: StickerPackPreviewInteraction, theme: PresentationTheme, isLocked: Bool, isPremium: Bool, isEmpty: Bool) {
func setup(context: AccountContext, stickerItem: StickerPackItem?, interaction: StickerPackPreviewInteraction, theme: PresentationTheme, isLocked: Bool, isPremium: Bool, isEmpty: Bool) {
self.interaction = interaction
self.theme = theme
if self.currentState == nil || self.currentState!.0 !== account || self.currentState!.1 != stickerItem || self.isLocked != isLocked || self.isPremium != isPremium || self.isEmpty != isEmpty {
if self.currentState == nil || self.currentState!.0 !== context || self.currentState!.1 != stickerItem || self.isLocked != isLocked || self.isPremium != isPremium || self.isEmpty != isEmpty {
self.isLocked = isLocked
if isLocked {
@ -229,9 +229,9 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
if stickerItem.file.isAnimatedSticker || stickerItem.file.isVideoSticker {
let dimensions = stickerItem.file.dimensions ?? PixelDimensions(width: 512, height: 512)
if stickerItem.file.isVideoSticker {
self.imageNode.setSignal(chatMessageSticker(account: account, userLocation: .other, file: stickerItem.file, small: true))
self.imageNode.setSignal(chatMessageSticker(account: context.account, userLocation: .other, file: stickerItem.file, small: true))
} else {
self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: account.postbox, userLocation: .other, file: stickerItem.file, small: false, size: dimensions.cgSize.aspectFitted(CGSize(width: 160.0, height: 160.0))))
self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: context.account.postbox, userLocation: .other, file: stickerItem.file, small: false, size: dimensions.cgSize.aspectFitted(CGSize(width: 160.0, height: 160.0))))
}
if self.animationNode == nil {
@ -255,14 +255,14 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
}
}
let fittedDimensions = dimensions.cgSize.aspectFitted(CGSize(width: 160.0, height: 160.0))
self.animationNode?.setup(source: AnimatedStickerResourceSource(account: account, resource: stickerItem.file.resource, isVideo: stickerItem.file.isVideoSticker), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), playbackMode: .loop, mode: .cached)
self.animationNode?.setup(source: AnimatedStickerResourceSource(account: context.account, resource: stickerItem.file.resource, isVideo: stickerItem.file.isVideoSticker), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), playbackMode: .loop, mode: .cached)
self.animationNode?.visibility = visibility
self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: account, userLocation: .other, fileReference: stickerPackFileReference(stickerItem.file), resource: stickerItem.file.resource).start())
self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: context.account, userLocation: .other, fileReference: stickerPackFileReference(stickerItem.file), resource: stickerItem.file.resource).start())
if stickerItem.file.isPremiumSticker, let effect = stickerItem.file.videoThumbnails.first {
self.effectFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: account, userLocation: .other, fileReference: stickerPackFileReference(stickerItem.file), resource: effect.resource).start())
self.effectFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: context.account, userLocation: .other, fileReference: stickerPackFileReference(stickerItem.file), resource: effect.resource).start())
}
} else {
if let animationNode = self.animationNode {
@ -270,8 +270,8 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
self.animationNode = nil
animationNode.removeFromSupernode()
}
self.imageNode.setSignal(chatMessageSticker(account: account, userLocation: .other, file: stickerItem.file, small: true))
self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: account, userLocation: .other, fileReference: stickerPackFileReference(stickerItem.file), resource: chatMessageStickerResource(file: stickerItem.file, small: true)).start())
self.imageNode.setSignal(chatMessageSticker(account: context.account, userLocation: .other, file: stickerItem.file, small: true))
self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: context.account, userLocation: .other, fileReference: stickerPackFileReference(stickerItem.file), resource: chatMessageStickerResource(file: stickerItem.file, small: true)).start())
}
} else {
if isEmpty {
@ -287,7 +287,7 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
self.animationNode?.alpha = isLocked ? 0.5 : 1.0
self.imageNode.alpha = isLocked ? 0.5 : 1.0
self.currentState = (account, stickerItem)
self.currentState = (context, stickerItem)
self.setNeedsLayout()
}
self.isEmpty = isEmpty
@ -322,8 +322,8 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
let placeholderFrame = imageFrame
self.placeholderNode.frame = imageFrame
if let theme = self.theme, let (_, stickerItem) = self.currentState, let item = stickerItem {
self.placeholderNode.update(backgroundColor: theme.list.itemBlocksBackgroundColor, foregroundColor: theme.list.mediaPlaceholderColor, shimmeringColor: theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.4), data: item.file.immediateThumbnailData, size: placeholderFrame.size)
if let theme = self.theme, let (context, stickerItem) = self.currentState, let item = stickerItem {
self.placeholderNode.update(backgroundColor: theme.list.itemBlocksBackgroundColor, foregroundColor: theme.list.mediaPlaceholderColor, shimmeringColor: theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.4), data: item.file.immediateThumbnailData, size: placeholderFrame.size, enableEffect: context.sharedContext.energyUsageSettings.fullTranslucency)
}
if let lockBackground = self.lockBackground, let lockTintView = self.lockTintView, let lockIconNode = self.lockIconNode {

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 {
switch self {
case let .sticker(_, _, stickerItem, isEmpty, isPremium, isLocked):
return StickerPackPreviewGridItem(account: context.account, stickerItem: stickerItem, interaction: interaction, theme: theme, isPremium: isPremium, isLocked: isLocked, isEmpty: isEmpty)
return StickerPackPreviewGridItem(context: context, stickerItem: stickerItem, interaction: interaction, theme: theme, isPremium: isPremium, isLocked: isLocked, isEmpty: isEmpty)
case let .emojis(_, _, info, items, title, isInstalled):
return StickerPackEmojisItem(context: context, animationCache: animationCache, animationRenderer: animationRenderer, interaction: interaction, info: info, items: items, theme: theme, strings: strings, title: title, isInstalled: isInstalled, isEmpty: false)
}

View File

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

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 {
enum AppUpdate: TypeConstructorDescription {
case appUpdate(flags: Int32, id: Int32, version: String, text: String, entities: [Api.MessageEntity], document: Api.Document?, url: String?, sticker: Api.Document?)
@ -1274,61 +1328,3 @@ public extension Api.messages {
}
}
public extension Api.messages {
enum AllStickers: TypeConstructorDescription {
case allStickers(hash: Int64, sets: [Api.StickerSet])
case allStickersNotModified
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .allStickers(let hash, let sets):
if boxed {
buffer.appendInt32(-843329861)
}
serializeInt64(hash, buffer: buffer, boxed: false)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(sets.count))
for item in sets {
item.serialize(buffer, true)
}
break
case .allStickersNotModified:
if boxed {
buffer.appendInt32(-395967805)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .allStickers(let hash, let sets):
return ("allStickers", [("hash", hash as Any), ("sets", sets as Any)])
case .allStickersNotModified:
return ("allStickersNotModified", [])
}
}
public static func parse_allStickers(_ reader: BufferReader) -> AllStickers? {
var _1: Int64?
_1 = reader.readInt64()
var _2: [Api.StickerSet]?
if let _ = reader.readInt32() {
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StickerSet.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.messages.AllStickers.allStickers(hash: _1!, sets: _2!)
}
else {
return nil
}
}
public static func parse_allStickersNotModified(_ reader: BufferReader) -> AllStickers? {
return Api.messages.AllStickers.allStickersNotModified
}
}
}

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 {
enum ArchivedStickers: TypeConstructorDescription {
case archivedStickers(count: Int32, sets: [Api.StickerSetCovered])
@ -1346,79 +1404,3 @@ public extension Api.messages {
}
}
public extension Api.messages {
enum HistoryImport: TypeConstructorDescription {
case historyImport(id: Int64)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .historyImport(let id):
if boxed {
buffer.appendInt32(375566091)
}
serializeInt64(id, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .historyImport(let id):
return ("historyImport", [("id", id as Any)])
}
}
public static func parse_historyImport(_ reader: BufferReader) -> HistoryImport? {
var _1: Int64?
_1 = reader.readInt64()
let _c1 = _1 != nil
if _c1 {
return Api.messages.HistoryImport.historyImport(id: _1!)
}
else {
return nil
}
}
}
}
public extension Api.messages {
enum HistoryImportParsed: TypeConstructorDescription {
case historyImportParsed(flags: Int32, title: String?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .historyImportParsed(let flags, let title):
if boxed {
buffer.appendInt32(1578088377)
}
serializeInt32(flags, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 2) != 0 {serializeString(title!, buffer: buffer, boxed: false)}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .historyImportParsed(let flags, let title):
return ("historyImportParsed", [("flags", flags as Any), ("title", title as Any)])
}
}
public static func parse_historyImportParsed(_ reader: BufferReader) -> HistoryImportParsed? {
var _1: Int32?
_1 = reader.readInt32()
var _2: String?
if Int(_1!) & Int(1 << 2) != 0 {_2 = parseString(reader) }
let _c1 = _1 != nil
let _c2 = (Int(_1!) & Int(1 << 2) == 0) || _2 != nil
if _c1 && _c2 {
return Api.messages.HistoryImportParsed.historyImportParsed(flags: _1!, title: _2)
}
else {
return nil
}
}
}
}

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 {
enum InactiveChats: TypeConstructorDescription {
case inactiveChats(dates: [Int32], chats: [Api.Chat], users: [Api.User])
@ -1342,109 +1418,3 @@ public extension Api.messages {
}
}
public extension Api.messages {
enum TranslatedText: TypeConstructorDescription {
case translateResult(result: [Api.TextWithEntities])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .translateResult(let result):
if boxed {
buffer.appendInt32(870003448)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(result.count))
for item in result {
item.serialize(buffer, true)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .translateResult(let result):
return ("translateResult", [("result", result as Any)])
}
}
public static func parse_translateResult(_ reader: BufferReader) -> TranslatedText? {
var _1: [Api.TextWithEntities]?
if let _ = reader.readInt32() {
_1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.TextWithEntities.self)
}
let _c1 = _1 != nil
if _c1 {
return Api.messages.TranslatedText.translateResult(result: _1!)
}
else {
return nil
}
}
}
}
public extension Api.messages {
enum VotesList: TypeConstructorDescription {
case votesList(flags: Int32, count: Int32, votes: [Api.MessageUserVote], users: [Api.User], nextOffset: String?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .votesList(let flags, let count, let votes, let users, let nextOffset):
if boxed {
buffer.appendInt32(136574537)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(count, buffer: buffer, boxed: false)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(votes.count))
for item in votes {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
if Int(flags) & Int(1 << 0) != 0 {serializeString(nextOffset!, buffer: buffer, boxed: false)}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .votesList(let flags, let count, let votes, let users, let nextOffset):
return ("votesList", [("flags", flags as Any), ("count", count as Any), ("votes", votes as Any), ("users", users as Any), ("nextOffset", nextOffset as Any)])
}
}
public static func parse_votesList(_ reader: BufferReader) -> VotesList? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
var _3: [Api.MessageUserVote]?
if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageUserVote.self)
}
var _4: [Api.User]?
if let _ = reader.readInt32() {
_4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
var _5: String?
if Int(_1!) & Int(1 << 0) != 0 {_5 = parseString(reader) }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
let _c5 = (Int(_1!) & Int(1 << 0) == 0) || _5 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 {
return Api.messages.VotesList.votesList(flags: _1!, count: _2!, votes: _3!, users: _4!, nextOffset: _5)
}
else {
return nil
}
}
}
}

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

View File

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

View File

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

View File

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

View File

@ -15,15 +15,21 @@ func addSynchronizeRecentlyUsedMediaOperation(transaction: Transaction, category
}
let peerId = PeerId(0)
var topOperation: (SynchronizeRecentlyUsedMediaOperation, Int32)?
var removeOperations: [(SynchronizeRecentlyUsedMediaOperation, Int32)] = []
transaction.operationLogEnumerateEntries(peerId: peerId, tag: tag, { entry in
if let operation = entry.contents as? SynchronizeRecentlyUsedMediaOperation {
topOperation = (operation, entry.tagLocalIndex)
if case .sync = operation.content {
removeOperations.append((operation, entry.tagLocalIndex))
return true
} else {
return false
}
} else {
return false
}
return false
})
if let (topOperation, topLocalIndex) = topOperation, case .sync = topOperation.content {
for (_, topLocalIndex) in removeOperations {
let _ = transaction.operationLogRemoveEntry(peerId: peerId, tag: tag, tagLocalIndex: topLocalIndex)
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -960,7 +960,7 @@ final class ChatEmptyNode: ASDisplayNode {
self.currentTheme = interfaceState.theme
self.currentStrings = interfaceState.strings
self.backgroundNode.updateColor(color: selectDateFillStaticColor(theme: interfaceState.theme, wallpaper: interfaceState.chatWallpaper), enableBlur: dateFillNeedsBlur(theme: interfaceState.theme, wallpaper: interfaceState.chatWallpaper), transition: .immediate)
self.backgroundNode.updateColor(color: selectDateFillStaticColor(theme: interfaceState.theme, wallpaper: interfaceState.chatWallpaper), enableBlur: self.context.sharedContext.energyUsageSettings.fullTranslucency && dateFillNeedsBlur(theme: interfaceState.theme, wallpaper: interfaceState.chatWallpaper), transition: .immediate)
}
var isScheduledMessages = false

View File

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

View File

@ -383,7 +383,7 @@ final class ChatMediaInputStickerGridItemNode: GridItemNode {
}
let theme = item.theme
placeholderNode.update(backgroundColor: theme.chat.inputMediaPanel.stickersBackgroundColor.withAlphaComponent(1.0), foregroundColor: theme.chat.inputMediaPanel.stickersSectionTextColor.blitOver(theme.chat.inputMediaPanel.stickersBackgroundColor, alpha: 0.15), shimmeringColor: theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.3), data: item.stickerItem.file.immediateThumbnailData, size: placeholderFrame.size)
placeholderNode.update(backgroundColor: theme.chat.inputMediaPanel.stickersBackgroundColor.withAlphaComponent(1.0), foregroundColor: theme.chat.inputMediaPanel.stickersSectionTextColor.blitOver(theme.chat.inputMediaPanel.stickersBackgroundColor, alpha: 0.15), shimmeringColor: theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.3), data: item.stickerItem.file.immediateThumbnailData, size: placeholderFrame.size, enableEffect: true)
}
if let lockBackground = self.lockBackground, let lockTintView = self.lockTintView, let lockIconNode = self.lockIconNode {

View File

@ -269,7 +269,7 @@ final class ChatMediaInputStickerPackItemNode: ListViewItemNode {
immediateThumbnailData = data
}
placeholderNode.update(backgroundColor: nil, foregroundColor: theme.chat.inputMediaPanel.stickersSectionTextColor.blitOver(theme.chat.inputPanel.panelBackgroundColor, alpha: 0.4), shimmeringColor: theme.chat.inputMediaPanel.panelHighlightedIconBackgroundColor.withMultipliedAlpha(0.2), data: immediateThumbnailData, size: boundingImageSize, imageSize: imageSize.cgSize)
placeholderNode.update(backgroundColor: nil, foregroundColor: theme.chat.inputMediaPanel.stickersSectionTextColor.blitOver(theme.chat.inputPanel.panelBackgroundColor, alpha: 0.4), shimmeringColor: theme.chat.inputMediaPanel.panelHighlightedIconBackgroundColor.withMultipliedAlpha(0.2), data: immediateThumbnailData, size: boundingImageSize, enableEffect: true, imageSize: imageSize.cgSize)
}
self.containerNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: expandedBoundingSize)

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)
node.backgroundBlurNode.update(size: node.backgroundBlurNode.bounds.size, cornerRadius: 0.0, animator: animation.animator)
node.backgroundBlurNode.updateColor(color: selectDateFillStaticColor(theme: theme.theme, wallpaper: theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: theme.theme, wallpaper: theme.wallpaper), transition: .immediate)
node.backgroundBlurNode.updateColor(color: selectDateFillStaticColor(theme: theme.theme, wallpaper: theme.wallpaper), enableBlur: context.sharedContext.energyUsageSettings.fullTranslucency && dateFillNeedsBlur(theme: theme.theme, wallpaper: theme.wallpaper), transition: .immediate)
if backgroundNode?.hasExtraBubbleBackground() == true {
if node.backgroundContent == nil, let backgroundContent = backgroundNode?.makeBubbleBackground(for: .free) {

View File

@ -125,7 +125,7 @@ class ChatMessageShareButton: HighlightableButtonNode {
} else {
updatedIconImage = PresentationResourcesChat.chatFreeShareButtonIcon(presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper)
}
self.backgroundNode.updateColor(color: selectDateFillStaticColor(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper), transition: .immediate)
self.backgroundNode.updateColor(color: selectDateFillStaticColor(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper), enableBlur: controllerInteraction.enableFullTranslucency && dateFillNeedsBlur(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper), transition: .immediate)
self.iconNode.image = updatedIconImage
self.iconOffset = updatedIconOffset
}
@ -1444,7 +1444,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
let foregroundColor = bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.stickerPlaceholderColor, wallpaper: item.presentationData.theme.wallpaper)
let shimmeringColor = bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.stickerPlaceholderShimmerColor, wallpaper: item.presentationData.theme.wallpaper)
strongSelf.placeholderNode.update(backgroundColor: nil, foregroundColor: foregroundColor, shimmeringColor: shimmeringColor, data: immediateThumbnailData, size: animationNodeFrame.size, imageSize: file.dimensions?.cgSize ?? CGSize(width: 512.0, height: 512.0))
strongSelf.placeholderNode.update(backgroundColor: nil, foregroundColor: foregroundColor, shimmeringColor: shimmeringColor, data: immediateThumbnailData, size: animationNodeFrame.size, enableEffect: item.context.sharedContext.energyUsageSettings.fullTranslucency, imageSize: file.dimensions?.cgSize ?? CGSize(width: 512.0, height: 512.0))
strongSelf.placeholderNode.frame = animationNodeFrame
}
@ -1488,9 +1488,9 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
if needsReplyBackground {
if let replyBackgroundNode = strongSelf.replyBackgroundNode {
replyBackgroundNode.updateColor(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), transition: .immediate)
replyBackgroundNode.updateColor(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: item.controllerInteraction.enableFullTranslucency && dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), transition: .immediate)
} else {
let replyBackgroundNode = NavigationBackgroundNode(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper))
let replyBackgroundNode = NavigationBackgroundNode(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: item.controllerInteraction.enableFullTranslucency && dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper))
strongSelf.replyBackgroundNode = replyBackgroundNode
strongSelf.contextSourceNode.contentNode.addSubnode(replyBackgroundNode)
}
@ -2442,7 +2442,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
}
if let item = self.item, self.swipeToReplyNode == nil {
let swipeToReplyNode = ChatMessageSwipeToReplyNode(fillColor: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), foregroundColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonForegroundColor, wallpaper: item.presentationData.theme.wallpaper), backgroundNode: item.controllerInteraction.presentationContext.backgroundNode, action: ChatMessageSwipeToReplyNode.Action(self.currentSwipeAction))
let swipeToReplyNode = ChatMessageSwipeToReplyNode(fillColor: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: item.controllerInteraction.enableFullTranslucency && dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), foregroundColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonForegroundColor, wallpaper: item.presentationData.theme.wallpaper), backgroundNode: item.controllerInteraction.presentationContext.backgroundNode, action: ChatMessageSwipeToReplyNode.Action(self.currentSwipeAction))
self.swipeToReplyNode = swipeToReplyNode
self.insertSubnode(swipeToReplyNode, at: 0)
}

View File

@ -4240,7 +4240,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
}
if let item = self.item, self.swipeToReplyNode == nil {
let swipeToReplyNode = ChatMessageSwipeToReplyNode(fillColor: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), foregroundColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonForegroundColor, wallpaper: item.presentationData.theme.wallpaper), backgroundNode: item.controllerInteraction.presentationContext.backgroundNode, action: ChatMessageSwipeToReplyNode.Action(self.currentSwipeAction))
let swipeToReplyNode = ChatMessageSwipeToReplyNode(fillColor: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: item.controllerInteraction.enableFullTranslucency && dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), foregroundColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonForegroundColor, wallpaper: item.presentationData.theme.wallpaper), backgroundNode: item.controllerInteraction.presentationContext.backgroundNode, action: ChatMessageSwipeToReplyNode.Action(self.currentSwipeAction))
self.swipeToReplyNode = swipeToReplyNode
self.insertSubnode(swipeToReplyNode, at: 0)
}

View File

@ -474,7 +474,7 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
let serviceColor = serviceMessageColorComponents(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper)
dateColor = serviceColor.primaryText
blurredBackgroundColor = (selectDateFillStaticColor(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper), dateFillNeedsBlur(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper))
blurredBackgroundColor = (selectDateFillStaticColor(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper), arguments.context.sharedContext.energyUsageSettings.fullTranslucency && dateFillNeedsBlur(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper))
leftInset = 0.0
loadedCheckFullImage = PresentationResourcesChat.chatFreeFullCheck(arguments.presentationData.theme.theme, size: checkSize, isDefaultWallpaper: isDefaultWallpaper)
loadedCheckPartialImage = PresentationResourcesChat.chatFreePartialCheck(arguments.presentationData.theme.theme, size: checkSize, isDefaultWallpaper: isDefaultWallpaper)
@ -492,7 +492,7 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
let serviceColor = serviceMessageColorComponents(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper)
dateColor = serviceColor.primaryText
outgoingStatus = status
blurredBackgroundColor = (selectDateFillStaticColor(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper), dateFillNeedsBlur(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper))
blurredBackgroundColor = (selectDateFillStaticColor(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper), arguments.context.sharedContext.energyUsageSettings.fullTranslucency && dateFillNeedsBlur(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper))
leftInset = 0.0
loadedCheckFullImage = PresentationResourcesChat.chatFreeFullCheck(arguments.presentationData.theme.theme, size: checkSize, isDefaultWallpaper: isDefaultWallpaper)
loadedCheckPartialImage = PresentationResourcesChat.chatFreePartialCheck(arguments.presentationData.theme.theme, size: checkSize, isDefaultWallpaper: isDefaultWallpaper)

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)
self.backgroundNode.updateColor(color: selectDateFillStaticColor(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper), transition: .immediate)
let fullTranslucency: Bool = controllerInteraction?.enableFullTranslucency ?? true
self.backgroundNode.updateColor(color: selectDateFillStaticColor(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper), enableBlur: fullTranslucency && dateFillNeedsBlur(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper), transition: .immediate)
self.stickBackgroundNode.image = graphics.dateFloatingBackground
self.stickBackgroundNode.alpha = 0.0
@ -236,8 +238,10 @@ final class ChatMessageDateHeaderNode: ListViewItemHeaderNode {
self.presentationData = presentationData
let graphics = PresentationResourcesChat.principalGraphics(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper, bubbleCorners: presentationData.chatBubbleCorners)
let fullTranslucency: Bool = self.controllerInteraction?.enableFullTranslucency ?? true
self.backgroundNode.updateColor(color: selectDateFillStaticColor(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper), transition: .immediate)
self.backgroundNode.updateColor(color: selectDateFillStaticColor(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper), enableBlur: fullTranslucency && dateFillNeedsBlur(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper), transition: .immediate)
self.stickBackgroundNode.image = graphics.dateFloatingBackground
let titleFont = Font.medium(min(18.0, floor(presentationData.fontSize.baseDisplaySize * 13.0 / 17.0)))
@ -522,7 +526,7 @@ final class ChatMessageAvatarHeaderNode: ListViewItemHeaderNode {
}
self.avatarNode.setPeer(context: context, theme: theme, peer: EnginePeer(peer), authorOfMessage: authorOfMessage, overrideImage: overrideImage, emptyColor: emptyColor, synchronousLoad: synchronousLoad, displayDimensions: CGSize(width: 38.0, height: 38.0))
if peer.isPremium {
if peer.isPremium && context.sharedContext.energyUsageSettings.playVideoAvatars {
self.cachedDataDisposable.set((context.account.postbox.peerView(id: peer.id)
|> deliverOnMainQueue).start(next: { [weak self] peerView in
guard let strongSelf = self else {

View File

@ -236,7 +236,7 @@ class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
let mediaBackgroundFrame = imageFrame.insetBy(dx: -2.0, dy: -2.0)
strongSelf.mediaBackgroundNode.frame = mediaBackgroundFrame
strongSelf.mediaBackgroundNode.updateColor(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), transition: .immediate)
strongSelf.mediaBackgroundNode.updateColor(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: item.controllerInteraction.enableFullTranslucency && dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), transition: .immediate)
strongSelf.mediaBackgroundNode.update(size: mediaBackgroundFrame.size, transition: .immediate)
strongSelf.buttonNode.backgroundColor = item.presentationData.theme.theme.overallDarkAppearance ? UIColor(rgb: 0xffffff, alpha: 0.12) : UIColor(rgb: 0x000000, alpha: 0.12)

View File

@ -525,10 +525,10 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
if let currentReplyBackgroundNode = currentReplyBackgroundNode {
updatedReplyBackgroundNode = currentReplyBackgroundNode
} else {
updatedReplyBackgroundNode = NavigationBackgroundNode(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper))
updatedReplyBackgroundNode = NavigationBackgroundNode(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: item.controllerInteraction.enableFullTranslucency && dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper))
}
updatedReplyBackgroundNode?.updateColor(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), transition: .immediate)
updatedReplyBackgroundNode?.updateColor(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: item.controllerInteraction.enableFullTranslucency && dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), transition: .immediate)
}
var maxContentWidth = normalDisplaySize.width
@ -1009,7 +1009,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
translation.x = max(-80.0, min(0.0, translation.x))
if let item = self.item, self.swipeToReplyNode == nil {
let swipeToReplyNode = ChatMessageSwipeToReplyNode(fillColor: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), foregroundColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonForegroundColor, wallpaper: item.presentationData.theme.wallpaper), backgroundNode: item.controllerInteraction.presentationContext.backgroundNode, action: ChatMessageSwipeToReplyNode.Action(self.currentSwipeAction))
let swipeToReplyNode = ChatMessageSwipeToReplyNode(fillColor: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: item.controllerInteraction.enableFullTranslucency && dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), foregroundColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonForegroundColor, wallpaper: item.presentationData.theme.wallpaper), backgroundNode: item.controllerInteraction.presentationContext.backgroundNode, action: ChatMessageSwipeToReplyNode.Action(self.currentSwipeAction))
self.swipeToReplyNode = swipeToReplyNode
self.insertSubnode(swipeToReplyNode, at: 0)
}

View File

@ -561,10 +561,10 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
if let currentReplyBackgroundNode = currentReplyBackgroundNode {
updatedReplyBackgroundNode = currentReplyBackgroundNode
} else {
updatedReplyBackgroundNode = NavigationBackgroundNode(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper))
updatedReplyBackgroundNode = NavigationBackgroundNode(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: item.controllerInteraction.enableFullTranslucency && dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper))
}
updatedReplyBackgroundNode?.updateColor(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), transition: .immediate)
updatedReplyBackgroundNode?.updateColor(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: item.controllerInteraction.enableFullTranslucency && dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), transition: .immediate)
}
return (result, { [weak self] layoutData, animation in
@ -625,7 +625,7 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
case .free:
let serviceColor = serviceMessageColorComponents(theme: theme.theme, wallpaper: theme.wallpaper)
durationTextColor = serviceColor.primaryText
durationBlurColor = (selectDateFillStaticColor(theme: theme.theme, wallpaper: theme.wallpaper), dateFillNeedsBlur(theme: theme.theme, wallpaper: theme.wallpaper))
durationBlurColor = (selectDateFillStaticColor(theme: theme.theme, wallpaper: theme.wallpaper), item.controllerInteraction.enableFullTranslucency && dateFillNeedsBlur(theme: theme.theme, wallpaper: theme.wallpaper))
case .bubble:
durationBlurColor = nil
if incoming {

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)
strongSelf.mediaBackgroundNode.frame = mediaBackgroundFrame
strongSelf.mediaBackgroundNode.updateColor(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), transition: .immediate)
strongSelf.mediaBackgroundNode.updateColor(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: item.controllerInteraction.enableFullTranslucency && dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), transition: .immediate)
strongSelf.mediaBackgroundNode.update(size: mediaBackgroundFrame.size, transition: .immediate)
strongSelf.buttonNode.backgroundColor = item.presentationData.theme.theme.overallDarkAppearance ? UIColor(rgb: 0xffffff, alpha: 0.12) : UIColor(rgb: 0x000000, alpha: 0.12)

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 placeholderFrame = updatedImageFrame.insetBy(dx: innerImageInset, dy: innerImageInset)
strongSelf.placeholderNode.update(backgroundColor: nil, foregroundColor: foregroundColor, shimmeringColor: shimmeringColor, data: immediateThumbnailData, size: placeholderFrame.size)
strongSelf.placeholderNode.update(backgroundColor: nil, foregroundColor: foregroundColor, shimmeringColor: shimmeringColor, data: immediateThumbnailData, size: placeholderFrame.size, enableEffect: item.context.sharedContext.energyUsageSettings.fullTranslucency)
strongSelf.placeholderNode.frame = placeholderFrame
}
@ -927,9 +927,9 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
if needsReplyBackground {
if let replyBackgroundNode = strongSelf.replyBackgroundNode {
replyBackgroundNode.updateColor(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), transition: .immediate)
replyBackgroundNode.updateColor(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: item.controllerInteraction.enableFullTranslucency && dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), transition: .immediate)
} else {
let replyBackgroundNode = NavigationBackgroundNode(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper))
let replyBackgroundNode = NavigationBackgroundNode(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: item.controllerInteraction.enableFullTranslucency && dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper))
strongSelf.replyBackgroundNode = replyBackgroundNode
strongSelf.contextSourceNode.contentNode.addSubnode(replyBackgroundNode)
}
@ -1412,7 +1412,7 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
}
if let item = self.item, self.swipeToReplyNode == nil {
let swipeToReplyNode = ChatMessageSwipeToReplyNode(fillColor: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), foregroundColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonForegroundColor, wallpaper: item.presentationData.theme.wallpaper), backgroundNode: item.controllerInteraction.presentationContext.backgroundNode, action: ChatMessageSwipeToReplyNode.Action(self.currentSwipeAction))
let swipeToReplyNode = ChatMessageSwipeToReplyNode(fillColor: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: item.controllerInteraction.enableFullTranslucency && dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), foregroundColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonForegroundColor, wallpaper: item.presentationData.theme.wallpaper), backgroundNode: item.controllerInteraction.presentationContext.backgroundNode, action: ChatMessageSwipeToReplyNode.Action(self.currentSwipeAction))
self.swipeToReplyNode = swipeToReplyNode
self.insertSubnode(swipeToReplyNode, at: 0)
}

View File

@ -447,7 +447,7 @@ class ChatMessageThreadInfoNode: ASDisplayNode {
backgroundNode.frame = backgroundFrame
backgroundNode.update(size: backgroundNode.bounds.size, cornerRadius: 0.0, transition: .immediate)
backgroundNode.updateColor(color: selectDateFillStaticColor(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper), transition: .immediate)
backgroundNode.updateColor(color: selectDateFillStaticColor(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper), enableBlur: arguments.controllerInteraction.enableFullTranslucency && dateFillNeedsBlur(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper), transition: .immediate)
}
} else {
node.contentBackgroundNode.frame = CGRect(origin: CGPoint(x: -1.0, y: -3.0), size: image.size)

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())
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
}

View File

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

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())
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
}

View File

@ -499,7 +499,7 @@ final class HorizontalListContextResultsChatInputPanelItemNode: ListViewItemNode
placeholderNode.bounds = CGRect(origin: CGPoint(), size: CGSize(width: croppedImageDimensions.width, height: croppedImageDimensions.height))
placeholderNode.position = CGPoint(x: height / 2.0, y: (nodeLayout.contentSize.height - sideInset) / 2.0 + sideInset)
placeholderNode.update(backgroundColor: item.theme.list.plainBackgroundColor, foregroundColor: item.theme.list.mediaPlaceholderColor.mixedWith(item.theme.list.plainBackgroundColor, alpha: 0.4), shimmeringColor: item.theme.list.mediaPlaceholderColor.withAlphaComponent(0.3), data: immediateThumbnailData, size: CGSize(width: croppedImageDimensions.width, height: croppedImageDimensions.height))
placeholderNode.update(backgroundColor: item.theme.list.plainBackgroundColor, foregroundColor: item.theme.list.mediaPlaceholderColor.mixedWith(item.theme.list.plainBackgroundColor, alpha: 0.4), shimmeringColor: item.theme.list.mediaPlaceholderColor.withAlphaComponent(0.3), data: immediateThumbnailData, size: CGSize(width: croppedImageDimensions.width, height: croppedImageDimensions.height), enableEffect: item.context.sharedContext.energyUsageSettings.fullTranslucency)
}
}
})

View File

@ -11,9 +11,10 @@ import AnimatedStickerNode
import TelegramAnimatedStickerNode
import ShimmerEffect
import TelegramPresentationData
import AccountContext
final class HorizontalStickerGridItem: GridItem {
let account: Account
let context: AccountContext
let file: TelegramMediaFile
let theme: PresentationTheme
let isPreviewed: (HorizontalStickerGridItem) -> Bool
@ -21,8 +22,8 @@ final class HorizontalStickerGridItem: GridItem {
let section: GridSection? = nil
init(account: Account, file: TelegramMediaFile, theme: PresentationTheme, isPreviewed: @escaping (HorizontalStickerGridItem) -> Bool, sendSticker: @escaping (FileMediaReference, UIView, CGRect) -> Void) {
self.account = account
init(context: AccountContext, file: TelegramMediaFile, theme: PresentationTheme, isPreviewed: @escaping (HorizontalStickerGridItem) -> Bool, sendSticker: @escaping (FileMediaReference, UIView, CGRect) -> Void) {
self.context = context
self.file = file
self.theme = theme
self.isPreviewed = isPreviewed
@ -31,7 +32,7 @@ final class HorizontalStickerGridItem: GridItem {
func node(layout: GridNodeLayout, synchronousLoad: Bool) -> GridItemNode {
let node = HorizontalStickerGridItemNode()
node.setup(account: self.account, item: self)
node.setup(context: self.context, item: self)
node.sendSticker = self.sendSticker
return node
}
@ -41,13 +42,13 @@ final class HorizontalStickerGridItem: GridItem {
assertionFailure()
return
}
node.setup(account: self.account, item: self)
node.setup(context: self.context, item: self)
node.sendSticker = self.sendSticker
}
}
final class HorizontalStickerGridItemNode: GridItemNode {
private var currentState: (Account, HorizontalStickerGridItem, CGSize)?
private var currentState: (AccountContext, HorizontalStickerGridItem, CGSize)?
let imageNode: TransformImageNode
private(set) var animationNode: AnimatedStickerNode?
private(set) var placeholderNode: StickerShimmerEffectNode?
@ -137,8 +138,8 @@ final class HorizontalStickerGridItemNode: GridItemNode {
self.imageNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.imageNodeTap(_:))))
}
func setup(account: Account, item: HorizontalStickerGridItem) {
if self.currentState == nil || self.currentState!.0 !== account || self.currentState!.1.file.id != item.file.id {
func setup(context: AccountContext, item: HorizontalStickerGridItem) {
if self.currentState == nil || self.currentState!.0 !== context || self.currentState!.1.file.id != item.file.id {
if let dimensions = item.file.dimensions {
if item.file.isAnimatedSticker || item.file.isVideoSticker {
let animationNode: AnimatedStickerNode
@ -161,9 +162,9 @@ final class HorizontalStickerGridItemNode: GridItemNode {
let fittedDimensions = dimensions.cgSize.aspectFitted(CGSize(width: 160.0, height: 160.0))
if item.file.isVideoSticker {
self.imageNode.setSignal(chatMessageSticker(postbox: account.postbox, userLocation: .other, file: item.file, small: true, synchronousLoad: false))
self.imageNode.setSignal(chatMessageSticker(postbox: context.account.postbox, userLocation: .other, file: item.file, small: true, synchronousLoad: false))
} else {
self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: account.postbox, userLocation: .other, file: item.file, small: true, size: fittedDimensions, synchronousLoad: false))
self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: context.account.postbox, userLocation: .other, file: item.file, small: true, size: fittedDimensions, synchronousLoad: false))
}
animationNode.started = { [weak self] in
guard let strongSelf = self else {
@ -181,19 +182,19 @@ final class HorizontalStickerGridItemNode: GridItemNode {
strongSelf.removePlaceholder(animated: false)
}
}
animationNode.setup(source: AnimatedStickerResourceSource(account: account, resource: item.file.resource, isVideo: item.file.isVideoSticker), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), playbackMode: .loop, mode: .cached)
animationNode.setup(source: AnimatedStickerResourceSource(account: context.account, resource: item.file.resource, isVideo: item.file.isVideoSticker), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), playbackMode: .loop, mode: .cached)
self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: account, userLocation: .other, fileReference: stickerPackFileReference(item.file), resource: item.file.resource).start())
self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: context.account, userLocation: .other, fileReference: stickerPackFileReference(item.file), resource: item.file.resource).start())
} else {
self.imageNode.alpha = 1.0
self.imageNode.setSignal(chatMessageSticker(account: account, userLocation: .other, file: item.file, small: true))
self.imageNode.setSignal(chatMessageSticker(account: context.account, userLocation: .other, file: item.file, small: true))
if let currentAnimationNode = self.animationNode {
self.animationNode = nil
currentAnimationNode.removeFromSupernode()
}
self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: account, userLocation: .other, fileReference: stickerPackFileReference(item.file), resource: chatMessageStickerResource(file: item.file, small: true)).start())
self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: context.account, userLocation: .other, fileReference: stickerPackFileReference(item.file), resource: chatMessageStickerResource(file: item.file, small: true)).start())
}
if item.file.isPremiumSticker {
@ -237,7 +238,7 @@ final class HorizontalStickerGridItemNode: GridItemNode {
lockIconNode.removeFromSupernode()
}
self.currentState = (account, item, dimensions.cgSize)
self.currentState = (context, item, dimensions.cgSize)
self.setNeedsLayout()
}
}
@ -254,8 +255,8 @@ final class HorizontalStickerGridItemNode: GridItemNode {
if let placeholderNode = self.placeholderNode {
placeholderNode.frame = bounds
if let theme = self.currentState?.1.theme, let file = self.currentState?.1.file {
placeholderNode.update(backgroundColor: theme.list.plainBackgroundColor, foregroundColor: theme.list.mediaPlaceholderColor.mixedWith(theme.list.plainBackgroundColor, alpha: 0.4), shimmeringColor: theme.list.mediaPlaceholderColor.withAlphaComponent(0.3), data: file.immediateThumbnailData, size: bounds.size)
if let context = self.currentState?.0, let theme = self.currentState?.1.theme, let file = self.currentState?.1.file {
placeholderNode.update(backgroundColor: theme.list.plainBackgroundColor, foregroundColor: theme.list.mediaPlaceholderColor.mixedWith(theme.list.plainBackgroundColor, alpha: 0.4), shimmeringColor: theme.list.mediaPlaceholderColor.withAlphaComponent(0.3), data: file.immediateThumbnailData, size: bounds.size, enableEffect: context.sharedContext.energyUsageSettings.fullTranslucency)
}
}

View File

@ -70,8 +70,8 @@ private struct StickerEntry: Identifiable, Comparable {
return lhs.index < rhs.index
}
func item(account: Account, stickersInteraction: HorizontalStickersChatContextPanelInteraction, interfaceInteraction: ChatPanelInterfaceInteraction, theme: PresentationTheme) -> GridItem {
return HorizontalStickerGridItem(account: account, file: self.file, theme: theme, isPreviewed: { item in
func item(context: AccountContext, stickersInteraction: HorizontalStickersChatContextPanelInteraction, interfaceInteraction: ChatPanelInterfaceInteraction, theme: PresentationTheme) -> GridItem {
return HorizontalStickerGridItem(context: context, file: self.file, theme: theme, isPreviewed: { item in
return false//stickersInteraction.previewedStickerItem == item
}, sendSticker: { file, node, rect in
let _ = interfaceInteraction.sendSticker(file, true, node, rect, nil, [])
@ -88,15 +88,15 @@ private struct StickerEntryTransition {
let scrollToItem: GridNodeScrollToItem?
}
private func preparedGridEntryTransition(account: Account, from fromEntries: [StickerEntry], to toEntries: [StickerEntry], stickersInteraction: HorizontalStickersChatContextPanelInteraction, interfaceInteraction: ChatPanelInterfaceInteraction, theme: PresentationTheme) -> StickerEntryTransition {
private func preparedGridEntryTransition(context: AccountContext, from fromEntries: [StickerEntry], to toEntries: [StickerEntry], stickersInteraction: HorizontalStickersChatContextPanelInteraction, interfaceInteraction: ChatPanelInterfaceInteraction, theme: PresentationTheme) -> StickerEntryTransition {
let stationaryItems: GridNodeStationaryItems = .none
let scrollToItem: GridNodeScrollToItem? = nil
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
let deletions = deleteIndices
let insertions = indicesAndItems.map { GridNodeInsertItem(index: $0.0, item: $0.1.item(account: account, stickersInteraction: stickersInteraction, interfaceInteraction: interfaceInteraction, theme: theme), previousIndex: $0.2) }
let updates = updateIndices.map { GridNodeUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, stickersInteraction: stickersInteraction, interfaceInteraction: interfaceInteraction, theme: theme)) }
let insertions = indicesAndItems.map { GridNodeInsertItem(index: $0.0, item: $0.1.item(context: context, stickersInteraction: stickersInteraction, interfaceInteraction: interfaceInteraction, theme: theme), previousIndex: $0.2) }
let updates = updateIndices.map { GridNodeUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, stickersInteraction: stickersInteraction, interfaceInteraction: interfaceInteraction, theme: theme)) }
return StickerEntryTransition(deletions: deletions, insertions: insertions, updates: updates, updateFirstIndexInSectionOffset: nil, stationaryItems: stationaryItems, scrollToItem: scrollToItem)
}
@ -290,7 +290,7 @@ final class HorizontalStickersChatContextPanelNode: ChatInputContextPanelNode {
self.updateLayout(size: validLayout.0, leftInset: validLayout.1, rightInset: validLayout.2, bottomInset: validLayout.3, transition: .immediate, interfaceState: validLayout.4)
}
let transition = preparedGridEntryTransition(account: self.context.account, from: previousEntries, to: entries, stickersInteraction: self.stickersInteraction, interfaceInteraction: self.interfaceInteraction!, theme: self.theme)
let transition = preparedGridEntryTransition(context: self.context, from: previousEntries, to: entries, stickersInteraction: self.stickersInteraction, interfaceInteraction: self.interfaceInteraction!, theme: self.theme)
self.enqueueTransition(transition)
}

View File

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

View File

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

View File

@ -131,7 +131,7 @@ private final class LargeEmojiActionSheetItemNode: ActionSheetItemNode {
}
if let immediateThumbnailData = file.immediateThumbnailData {
self.placeholderNode.update(backgroundColor: nil, foregroundColor: theme.secondaryTextColor.blitOver(theme.itemBackgroundColor, alpha: 0.55), shimmeringColor: theme.itemBackgroundColor.withAlphaComponent(0.4), data: immediateThumbnailData, size: CGSize(width: 96.0, height: 96.0), imageSize: dimensions.cgSize)
self.placeholderNode.update(backgroundColor: nil, foregroundColor: theme.secondaryTextColor.blitOver(theme.itemBackgroundColor, alpha: 0.55), shimmeringColor: theme.itemBackgroundColor.withAlphaComponent(0.4), data: immediateThumbnailData, size: CGSize(width: 96.0, height: 96.0), enableEffect: context.sharedContext.energyUsageSettings.fullTranslucency, imageSize: dimensions.cgSize)
}
}

View File

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

View File

@ -328,7 +328,7 @@ private final class FeaturedPackItemNode: ListViewItemNode {
immediateThumbnailData = data
}
placeholderNode.update(backgroundColor: theme.chat.inputMediaPanel.stickersBackgroundColor.withAlphaComponent(1.0), foregroundColor: theme.chat.inputMediaPanel.stickersSectionTextColor.blitOver(theme.chat.inputMediaPanel.stickersBackgroundColor, alpha: 0.15), shimmeringColor: theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.3), data: immediateThumbnailData, size: boundingImageSize, imageSize: imageSize.cgSize)
placeholderNode.update(backgroundColor: theme.chat.inputMediaPanel.stickersBackgroundColor.withAlphaComponent(1.0), foregroundColor: theme.chat.inputMediaPanel.stickersSectionTextColor.blitOver(theme.chat.inputMediaPanel.stickersBackgroundColor, alpha: 0.15), shimmeringColor: theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.3), data: immediateThumbnailData, size: boundingImageSize, enableEffect: true, imageSize: imageSize.cgSize)
}
self.containerNode.frame = CGRect(origin: CGPoint(), size: boundingSize)

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

View File

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