diff --git a/submodules/ItemListUI/Sources/Items/ItemListSwitchItem.swift b/submodules/ItemListUI/Sources/Items/ItemListSwitchItem.swift index 71b3670c3b..1976c5c41e 100644 --- a/submodules/ItemListUI/Sources/Items/ItemListSwitchItem.swift +++ b/submodules/ItemListUI/Sources/Items/ItemListSwitchItem.swift @@ -16,6 +16,7 @@ public class ItemListSwitchItem: ListViewItem, ItemListItem { let presentationData: ItemListPresentationData let icon: UIImage? let title: String + let text: String? let value: Bool let type: ItemListSwitchItemNodeType let enableInteractiveChanges: Bool @@ -30,10 +31,11 @@ public class ItemListSwitchItem: ListViewItem, ItemListItem { let activatedWhileDisabled: () -> Void public let tag: ItemListItemTag? - public init(presentationData: ItemListPresentationData, icon: UIImage? = nil, title: String, value: Bool, type: ItemListSwitchItemNodeType = .regular, enableInteractiveChanges: Bool = true, enabled: Bool = true, displayLocked: Bool = false, disableLeadingInset: Bool = false, maximumNumberOfLines: Int = 1, noCorners: Bool = false, sectionId: ItemListSectionId, style: ItemListStyle, updated: @escaping (Bool) -> Void, activatedWhileDisabled: @escaping () -> Void = {}, tag: ItemListItemTag? = nil) { + public init(presentationData: ItemListPresentationData, icon: UIImage? = nil, title: String, text: String? = nil, value: Bool, type: ItemListSwitchItemNodeType = .regular, enableInteractiveChanges: Bool = true, enabled: Bool = true, displayLocked: Bool = false, disableLeadingInset: Bool = false, maximumNumberOfLines: Int = 1, noCorners: Bool = false, sectionId: ItemListSectionId, style: ItemListStyle, updated: @escaping (Bool) -> Void, activatedWhileDisabled: @escaping () -> Void = {}, tag: ItemListItemTag? = nil) { self.presentationData = presentationData self.icon = icon self.title = title + self.text = text self.value = value self.type = type self.enableInteractiveChanges = enableInteractiveChanges @@ -127,6 +129,7 @@ public class ItemListSwitchItemNode: ListViewItemNode, ItemListItemNode { private let iconNode: ASImageNode private let titleNode: TextNode + private let textNode: TextNode private var switchNode: ASDisplayNode & ItemListSwitchNodeImpl private let switchGestureNode: ASDisplayNode private var disabledOverlayNode: ASDisplayNode? @@ -161,6 +164,10 @@ public class ItemListSwitchItemNode: ListViewItemNode, ItemListItemNode { self.titleNode = TextNode() self.titleNode.isUserInteractionEnabled = false + + self.textNode = TextNode() + self.textNode.isUserInteractionEnabled = false + switch type { case .regular: self.switchNode = SwitchNode() @@ -178,6 +185,7 @@ public class ItemListSwitchItemNode: ListViewItemNode, ItemListItemNode { super.init(layerBacked: false, dynamicBounce: false) self.addSubnode(self.titleNode) + self.addSubnode(self.textNode) self.addSubnode(self.switchNode) self.addSubnode(self.switchGestureNode) self.addSubnode(self.activateArea) @@ -204,6 +212,7 @@ public class ItemListSwitchItemNode: ListViewItemNode, ItemListItemNode { func asyncLayout() -> (_ item: ItemListSwitchItem, _ params: ListViewItemLayoutParams, _ insets: ItemListNeighbors) -> (ListViewItemNodeLayout, (Bool) -> Void) { let makeTitleLayout = TextNode.asyncLayout(self.titleNode) + let makeTextLayout = TextNode.asyncLayout(self.textNode) let currentItem = self.item var currentDisabledOverlayNode = self.disabledOverlayNode @@ -216,6 +225,7 @@ public class ItemListSwitchItemNode: ListViewItemNode, ItemListItemNode { let itemSeparatorColor: UIColor let titleFont = Font.regular(item.presentationData.fontSize.itemListBaseFontSize) + let textFont = Font.regular(item.presentationData.fontSize.itemListBaseFontSize * 14.0 / 17.0) var updatedTheme: PresentationTheme? if currentItem?.presentationData.theme !== item.presentationData.theme { @@ -252,7 +262,12 @@ public class ItemListSwitchItemNode: ListViewItemNode, ItemListItemNode { let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.title, font: titleFont, textColor: item.presentationData.theme.list.itemPrimaryTextColor), backgroundColor: nil, maximumNumberOfLines: item.maximumNumberOfLines, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - params.rightInset - 64.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) + let (textLayout, textApply) = makeTextLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.text ?? "", font: textFont, textColor: item.presentationData.theme.list.itemSecondaryTextColor), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - params.rightInset - 64.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) + contentSize.height = max(contentSize.height, titleLayout.size.height + 22.0) + if item.text != nil { + contentSize.height += 2.0 + textLayout.size.height + } if !item.enabled { if currentDisabledOverlayNode == nil { @@ -288,7 +303,12 @@ public class ItemListSwitchItemNode: ListViewItemNode, ItemListItemNode { if updateIcon { strongSelf.iconNode.image = icon } - let iconY = floor((layout.contentSize.height - icon.size.height) / 2.0) + let iconY: CGFloat + if item.text == nil { + iconY = floor((layout.contentSize.height - icon.size.height) / 2.0) + } else { + iconY = max(0.0, floor(11.0 + titleLayout.size.height + 1.0 - icon.size.height * 0.5)) + } strongSelf.iconNode.frame = CGRect(origin: CGPoint(x: params.leftInset + floor((leftInset - params.leftInset - icon.size.width) / 2.0), y: iconY), size: icon.size) } else if strongSelf.iconNode.supernode != nil { strongSelf.iconNode.image = nil @@ -335,6 +355,7 @@ public class ItemListSwitchItemNode: ListViewItemNode, ItemListItemNode { } let _ = titleApply() + let _ = textApply() switch item.style { case .plain: @@ -394,7 +415,10 @@ public class ItemListSwitchItemNode: ListViewItemNode, ItemListItemNode { strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height - separatorHeight), size: CGSize(width: layoutSize.width - bottomStripeInset, height: separatorHeight)) } - strongSelf.titleNode.frame = CGRect(origin: CGPoint(x: leftInset, y: floorToScreenPixels((contentSize.height - titleLayout.size.height) / 2.0)), size: titleLayout.size) + strongSelf.titleNode.frame = CGRect(origin: CGPoint(x: leftInset, y: 11.0), size: titleLayout.size) + + strongSelf.textNode.frame = CGRect(origin: CGPoint(x: leftInset, y: strongSelf.titleNode.frame.maxY + 2.0), size: textLayout.size) + if let switchView = strongSelf.switchNode.view as? UISwitch { if strongSelf.switchNode.bounds.size.width.isZero { switchView.sizeToFit() diff --git a/submodules/SettingsUI/Sources/Data and Storage/DataAndStorageSettingsController.swift b/submodules/SettingsUI/Sources/Data and Storage/DataAndStorageSettingsController.swift index ff452192d3..2915d6a8b9 100644 --- a/submodules/SettingsUI/Sources/Data and Storage/DataAndStorageSettingsController.swift +++ b/submodules/SettingsUI/Sources/Data and Storage/DataAndStorageSettingsController.swift @@ -33,13 +33,12 @@ 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, openEnergySavingSettings: @escaping () -> 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, toggleDownloadInBackground: @escaping (Bool) -> Void, openBrowserSelection: @escaping () -> Void, openIntents: @escaping () -> Void, toggleEnableSensitiveContent: @escaping (Bool) -> Void) { self.openStorageUsage = openStorageUsage self.openNetworkUsage = openNetworkUsage self.openProxy = openProxy @@ -52,7 +51,6 @@ 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 @@ -66,7 +64,6 @@ private enum DataAndStorageSection: Int32 { case autoSave case backgroundDownload case autoPlay - case energySaving case voiceCalls case other case connection @@ -111,8 +108,6 @@ private enum DataAndStorageEntry: ItemListNodeEntry { 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) @@ -141,8 +136,6 @@ 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: @@ -186,8 +179,6 @@ private enum DataAndStorageEntry: ItemListNodeEntry { return 26 case .autoplayVideos: return 27 - case .energySaving: - return 28 case .otherHeader: return 29 case .shareSheet: @@ -285,12 +276,6 @@ 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 @@ -440,11 +425,6 @@ 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) @@ -688,8 +668,6 @@ 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)) @@ -945,8 +923,6 @@ 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 diff --git a/submodules/SettingsUI/Sources/Data and Storage/EnergySavingSettingsScreen.swift b/submodules/SettingsUI/Sources/Data and Storage/EnergySavingSettingsScreen.swift index f8be70bf3f..7a37f488a9 100644 --- a/submodules/SettingsUI/Sources/Data and Storage/EnergySavingSettingsScreen.swift +++ b/submodules/SettingsUI/Sources/Data and Storage/EnergySavingSettingsScreen.swift @@ -11,6 +11,9 @@ import PresentationDataUtils import AccountContext enum ItemType: CaseIterable { + case autoplayVideo + case autoplayGif + case loopStickers case loopEmoji case playVideoAvatars case fullTranslucency @@ -20,6 +23,12 @@ enum ItemType: CaseIterable { var settingsKeyPath: WritableKeyPath { switch self { + case .autoplayVideo: + return \.autoplayVideo + case .autoplayGif: + return \.autoplayGif + case .loopStickers: + return \.loopStickers case .loopEmoji: return \.loopEmoji case .playVideoAvatars: @@ -35,21 +44,63 @@ enum ItemType: CaseIterable { } } - func title(strings: PresentationStrings) -> String { + func title(strings: PresentationStrings) -> (String, String, String) { //TODO:localize switch self { + case .autoplayVideo: + return ( + "Settings/Menu/Reactions", + "Autoplay Videos", + "Autoplay and loop videos and video messages in chats." + ) + case .autoplayGif: + return ( + "Settings/Menu/Reactions", + "Autoplay GIFs", + "Autoplay and loop GIFs in chats and in the keyboard." + ) + case .loopStickers: + return ( + "Settings/Menu/Reactions", + "Sticker Animations", + "Autoplay and loop GIFs in chats and in the keyboard." + ) case .loopEmoji: - return "Loop Animated Emoji" + return ( + "Settings/Menu/Reactions", + "Emoli Animations", + "Loop animated emoji in messages, reactions, statuses." + ) case .playVideoAvatars: - return "Play Video Avatars" + return ( + "Settings/Menu/Reactions", + "Autoplay Video Avatars", + "Autoplay and loop video avatars in chats" + ) case .fullTranslucency: - return "Translucency Effects" + return ( + "Settings/Menu/Reactions", + "Interface Effects", + "Various effects and animations that make Telegram look amazing." + ) case .extendBackgroundWork: - return "Extended Background Time" + return ( + "Settings/Menu/Reactions", + "Extended Background Time", + "Extended Background Time Description" + ) case .synchronizeInBackground: - return "Background Sync" + return ( + "Settings/Menu/Reactions", + "Background Sync", + "Background Sync Description" + ) case .autodownloadInBackground: - return "Preload Media in Chats" + return ( + "Settings/Menu/Reactions", + "Preload Media in Chats", + "Preload Media in Chats Description" + ) } } } @@ -72,17 +123,21 @@ private enum EnergeSavingSettingsScreenSection: Int32 { private enum EnergeSavingSettingsScreenEntry: ItemListNodeEntry { enum StableId: Hashable { case all + case allFooter + case itemsHeader case item(ItemType) } case all(Bool) - case item(index: Int, type: ItemType, value: Bool) + case allFooter + case item(index: Int, type: ItemType, value: Bool, enabled: Bool) + case itemsHeader var section: ItemListSectionId { switch self { - case .all: + case .all, .allFooter: return EnergeSavingSettingsScreenSection.all.rawValue - case .item: + case .item, .itemsHeader: return EnergeSavingSettingsScreenSection.items.rawValue } } @@ -90,8 +145,12 @@ private enum EnergeSavingSettingsScreenEntry: ItemListNodeEntry { var sortIndex: Int { switch self { case .all: + return -3 + case .allFooter: + return -2 + case .itemsHeader: return -1 - case let .item(index, _, _): + case let .item(index, _, _, _): return index } } @@ -100,7 +159,11 @@ private enum EnergeSavingSettingsScreenEntry: ItemListNodeEntry { switch self { case .all: return .all - case let .item(_, type, _): + case .allFooter: + return .allFooter + case .itemsHeader: + return .itemsHeader + case let .item(_, type, _, _): return .item(type) } } @@ -114,11 +177,17 @@ private enum EnergeSavingSettingsScreenEntry: ItemListNodeEntry { 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 + return ItemListSwitchItem(presentationData: presentationData, title: "Power-Saving Mode", 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 + case .allFooter: + return ItemListTextItem(presentationData: presentationData, text: .plain("Reduce all resource-intensive animations and background activity."), sectionId: self.section) + case .itemsHeader: + //TODO:localize + return ItemListSectionHeaderItem(presentationData: presentationData, text: "RESOURCE-INTENSIVE PROCESSES", sectionId: self.section) + case let .item(_, type, value, enabled): + let (iconName, title, text) = type.title(strings: presentationData.strings) + return ItemListSwitchItem(presentationData: presentationData, icon: UIImage(bundleImageName: iconName)?.precomposed(), title: title, text: text, value: value, enableInteractiveChanges: true, enabled: enabled, sectionId: self.section, style: .blocks, updated: { value in arguments.toggleItem(type) }) } @@ -131,10 +200,13 @@ private func energeSavingSettingsScreenEntries( ) -> [EnergeSavingSettingsScreenEntry] { var entries: [EnergeSavingSettingsScreenEntry] = [] - entries.append(.all(ItemType.allCases.allSatisfy({ item in settings.energyUsageSettings[keyPath: item.settingsKeyPath] }))) + let powerSavingOn = ItemType.allCases.allSatisfy({ item in !settings.energyUsageSettings[keyPath: item.settingsKeyPath] }) + entries.append(.all(powerSavingOn)) + entries.append(.allFooter) + entries.append(.itemsHeader) for type in ItemType.allCases { - entries.append(.item(index: entries.count, type: type, value: settings.energyUsageSettings[keyPath: type.settingsKeyPath])) + entries.append(.item(index: entries.count, type: type, value: settings.energyUsageSettings[keyPath: type.settingsKeyPath], enabled: !powerSavingOn)) } return entries @@ -149,7 +221,7 @@ func energySavingSettingsScreen(context: AccountContext) -> ViewController { let _ = updateMediaDownloadSettingsInteractively(accountManager: context.sharedContext.accountManager, { settings in var settings = settings for type in ItemType.allCases { - settings.energyUsageSettings[keyPath: type.settingsKeyPath] = value + settings.energyUsageSettings[keyPath: type.settingsKeyPath] = !value } return settings }).start() diff --git a/submodules/SettingsUI/Sources/Themes/ThemeSettingsController.swift b/submodules/SettingsUI/Sources/Themes/ThemeSettingsController.swift index e80a8336a2..7e258c4541 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemeSettingsController.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemeSettingsController.swift @@ -56,6 +56,7 @@ private final class ThemeSettingsControllerArguments { let openAutoNightTheme: () -> Void let openTextSize: () -> Void let openBubbleSettings: () -> Void + let openPowerSavingSettings: () -> Void let toggleLargeEmoji: (Bool) -> Void let disableAnimations: (Bool) -> Void let selectAppIcon: (PresentationAppIcon) -> Void @@ -63,7 +64,7 @@ private final class ThemeSettingsControllerArguments { let themeContextAction: (Bool, PresentationThemeReference, ASDisplayNode, ContextGesture?) -> Void let colorContextAction: (Bool, PresentationThemeReference, ThemeSettingsColorOption?, ASDisplayNode, ContextGesture?) -> Void - init(context: AccountContext, selectTheme: @escaping (PresentationThemeReference) -> Void, openThemeSettings: @escaping () -> Void, openWallpaperSettings: @escaping () -> Void, selectAccentColor: @escaping (PresentationThemeAccentColor?) -> Void, openAccentColorPicker: @escaping (PresentationThemeReference, Bool) -> Void, toggleNightTheme: @escaping (Bool) -> Void, openAutoNightTheme: @escaping () -> Void, openTextSize: @escaping () -> Void, openBubbleSettings: @escaping () -> Void, toggleLargeEmoji: @escaping (Bool) -> Void, disableAnimations: @escaping (Bool) -> Void, selectAppIcon: @escaping (PresentationAppIcon) -> Void, editTheme: @escaping (PresentationCloudTheme) -> Void, themeContextAction: @escaping (Bool, PresentationThemeReference, ASDisplayNode, ContextGesture?) -> Void, colorContextAction: @escaping (Bool, PresentationThemeReference, ThemeSettingsColorOption?, ASDisplayNode, ContextGesture?) -> Void) { + init(context: AccountContext, selectTheme: @escaping (PresentationThemeReference) -> Void, openThemeSettings: @escaping () -> Void, openWallpaperSettings: @escaping () -> Void, selectAccentColor: @escaping (PresentationThemeAccentColor?) -> Void, openAccentColorPicker: @escaping (PresentationThemeReference, Bool) -> Void, toggleNightTheme: @escaping (Bool) -> Void, openAutoNightTheme: @escaping () -> Void, openTextSize: @escaping () -> Void, openBubbleSettings: @escaping () -> Void, openPowerSavingSettings: @escaping () -> Void, toggleLargeEmoji: @escaping (Bool) -> Void, disableAnimations: @escaping (Bool) -> Void, selectAppIcon: @escaping (PresentationAppIcon) -> Void, editTheme: @escaping (PresentationCloudTheme) -> Void, themeContextAction: @escaping (Bool, PresentationThemeReference, ASDisplayNode, ContextGesture?) -> Void, colorContextAction: @escaping (Bool, PresentationThemeReference, ThemeSettingsColorOption?, ASDisplayNode, ContextGesture?) -> Void) { self.context = context self.selectTheme = selectTheme self.openThemeSettings = openThemeSettings @@ -74,6 +75,7 @@ private final class ThemeSettingsControllerArguments { self.openAutoNightTheme = openAutoNightTheme self.openTextSize = openTextSize self.openBubbleSettings = openBubbleSettings + self.openPowerSavingSettings = openPowerSavingSettings self.toggleLargeEmoji = toggleLargeEmoji self.disableAnimations = disableAnimations self.selectAppIcon = selectAppIcon @@ -88,6 +90,7 @@ private enum ThemeSettingsControllerSection: Int32 { case nightMode case message case icon + case powerSaving case other } @@ -97,6 +100,7 @@ public enum ThemeSettingsEntryTag: ItemListItemTag { case tint case accentColor case icon + case powerSaving case largeEmoji case animations @@ -121,6 +125,7 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry { case bubbleSettings(PresentationTheme, String, String) case iconHeader(PresentationTheme, String) case iconItem(PresentationTheme, PresentationStrings, [PresentationAppIcon], Bool, String?) + case powerSaving case otherHeader(PresentationTheme, String) case largeEmoji(PresentationTheme, String, Bool) case animations(PresentationTheme, String, Bool) @@ -136,6 +141,8 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry { return ThemeSettingsControllerSection.message.rawValue case .iconHeader, .iconItem: return ThemeSettingsControllerSection.icon.rawValue + case .powerSaving: + return ThemeSettingsControllerSection.powerSaving.rawValue case .otherHeader, .largeEmoji, .animations, .animationsInfo: return ThemeSettingsControllerSection.other.rawValue } @@ -165,14 +172,16 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry { return 9 case .iconItem: return 10 - case .otherHeader: + case .powerSaving: return 11 - case .largeEmoji: + case .otherHeader: return 12 - case .animations: + case .largeEmoji: return 13 - case .animationsInfo: + case .animations: return 14 + case .animationsInfo: + return 15 } } @@ -244,6 +253,12 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry { } else { return false } + case .powerSaving: + if case .powerSaving = rhs { + return true + } else { + return false + } case let .otherHeader(lhsTheme, lhsText): if case let .otherHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { return true @@ -318,6 +333,11 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry { return ThemeSettingsAppIconItem(theme: theme, strings: strings, sectionId: self.section, icons: icons, isPremium: isPremium, currentIconName: value, updated: { icon in arguments.selectAppIcon(icon) }) + case .powerSaving: + //TODO:localize + return ItemListDisclosureItem(presentationData: presentationData, icon: nil, title: "Power Saving", label: "", labelStyle: .text, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: { + arguments.openPowerSavingSettings() + }) case let .otherHeader(_, text): return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) case let .largeEmoji(_, title, value): @@ -382,6 +402,8 @@ private func themeSettingsControllerEntries(presentationData: PresentationData, entries.append(.iconItem(presentationData.theme, presentationData.strings, availableAppIcons, isPremium, currentAppIconName)) } + entries.append(.powerSaving) + entries.append(.otherHeader(presentationData.theme, strings.Appearance_Other.uppercased())) entries.append(.largeEmoji(presentationData.theme, strings.Appearance_LargeEmoji, presentationData.largeEmoji)) entries.append(.animations(presentationData.theme, strings.Appearance_ReduceMotion, presentationData.reduceMotion)) @@ -492,6 +514,8 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The let settings = view.entries[ApplicationSpecificSharedDataKeys.presentationThemeSettings]?.get(PresentationThemeSettings.self) ?? PresentationThemeSettings.defaultSettings pushControllerImpl?(BubbleSettingsController(context: context, presentationThemeSettings: settings)) }) + }, openPowerSavingSettings: { + pushControllerImpl?(energySavingSettingsScreen(context: context)) }, toggleLargeEmoji: { largeEmoji in let _ = updatePresentationThemeSettingsInteractively(accountManager: context.sharedContext.accountManager, { current in return current.withUpdatedLargeEmoji(largeEmoji) diff --git a/submodules/TelegramUIPreferences/Sources/MediaAutoDownloadSettings.swift b/submodules/TelegramUIPreferences/Sources/MediaAutoDownloadSettings.swift index 7e65ec0a63..996fdaecbd 100644 --- a/submodules/TelegramUIPreferences/Sources/MediaAutoDownloadSettings.swift +++ b/submodules/TelegramUIPreferences/Sources/MediaAutoDownloadSettings.swift @@ -260,6 +260,9 @@ public struct MediaAutoSaveSettings: Codable, Equatable { public struct EnergyUsageSettings: Codable, Equatable { private enum CodingKeys: CodingKey { + case autoplayVideo + case autoplayGif + case loopStickers case loopEmoji case playVideoAvatars case fullTranslucency @@ -270,6 +273,9 @@ public struct EnergyUsageSettings: Codable, Equatable { public static var `default`: EnergyUsageSettings { return EnergyUsageSettings( + autoplayVideo: true, + autoplayGif: true, + loopStickers: true, loopEmoji: true, playVideoAvatars: true, fullTranslucency: true, @@ -279,6 +285,9 @@ public struct EnergyUsageSettings: Codable, Equatable { ) } + public var autoplayVideo: Bool + public var autoplayGif: Bool + public var loopStickers: Bool public var loopEmoji: Bool public var playVideoAvatars: Bool public var fullTranslucency: Bool @@ -287,6 +296,9 @@ public struct EnergyUsageSettings: Codable, Equatable { public var autodownloadInBackground: Bool public init( + autoplayVideo: Bool, + autoplayGif: Bool, + loopStickers: Bool, loopEmoji: Bool, playVideoAvatars: Bool, fullTranslucency: Bool, @@ -294,6 +306,9 @@ public struct EnergyUsageSettings: Codable, Equatable { synchronizeInBackground: Bool, autodownloadInBackground: Bool ) { + self.autoplayVideo = autoplayVideo + self.autoplayGif = autoplayGif + self.loopStickers = loopStickers self.loopEmoji = loopEmoji self.playVideoAvatars = playVideoAvatars self.fullTranslucency = fullTranslucency @@ -305,6 +320,9 @@ public struct EnergyUsageSettings: Codable, Equatable { public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) + self.autoplayVideo = try container.decodeIfPresent(Bool.self, forKey: .autoplayVideo) ?? EnergyUsageSettings.default.autoplayVideo + self.autoplayGif = try container.decodeIfPresent(Bool.self, forKey: .autoplayGif) ?? EnergyUsageSettings.default.autoplayGif + self.loopStickers = try container.decodeIfPresent(Bool.self, forKey: .loopStickers) ?? EnergyUsageSettings.default.loopStickers 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 @@ -316,7 +334,10 @@ public struct EnergyUsageSettings: Codable, Equatable { public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(self.autoplayVideo, forKey: .autoplayVideo) + try container.encode(self.autoplayGif, forKey: .autoplayGif) try container.encode(self.loopEmoji, forKey: .loopEmoji) + try container.encode(self.loopStickers, forKey: .loopStickers) try container.encode(self.playVideoAvatars, forKey: .playVideoAvatars) try container.encode(self.fullTranslucency, forKey: .fullTranslucency) try container.encode(self.extendBackgroundWork, forKey: .extendBackgroundWork)