Swiftgram/submodules/SettingsUI/Sources/Data and Storage/EnergySavingSettingsScreen.swift
2023-02-28 22:20:44 +04:00

324 lines
12 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import Foundation
import UIKit
import Display
import SwiftSignalKit
import Postbox
import TelegramCore
import TelegramPresentationData
import TelegramUIPreferences
import ItemListUI
import PresentationDataUtils
import AccountContext
import UndoUI
enum ItemType: CaseIterable {
case autoplayVideo
case autoplayGif
case loopStickers
case loopEmoji
case fullTranslucency
case extendBackgroundWork
case autodownloadInBackground
var settingsKeyPath: WritableKeyPath<EnergyUsageSettings, Bool> {
switch self {
case .autoplayVideo:
return \.autoplayVideo
case .autoplayGif:
return \.autoplayGif
case .loopStickers:
return \.loopStickers
case .loopEmoji:
return \.loopEmoji
case .fullTranslucency:
return \.fullTranslucency
case .extendBackgroundWork:
return \.extendBackgroundWork
case .autodownloadInBackground:
return \.autodownloadInBackground
}
}
func title(strings: PresentationStrings) -> (String, String, String) {
//TODO:localize
switch self {
case .autoplayVideo:
return (
"Settings/Power/PowerIconVideo",
"Autoplay Videos",
"Autoplay and loop videos and video messages in chats."
)
case .autoplayGif:
return (
"Settings/Power/PowerIconGif",
"Autoplay GIFs",
"Autoplay and loop GIFs in chats and in the keyboard."
)
case .loopStickers:
return (
"Settings/Power/PowerIconStickers",
"Sticker Animations",
"Loop animated stickers, play full-screen premium effects."
)
case .loopEmoji:
return (
"Settings/Power/PowerIconEmoji",
"Emoli Animations",
"Loop animated emoji in messages, reactions, statuses."
)
case .fullTranslucency:
return (
"Settings/Power/PowerIconEffects",
"Interface Effects",
"Various effects and animations that make Telegram look amazing."
)
case .extendBackgroundWork:
return (
"Settings/Power/PowerIconBackgroundTime",
"Extended Background Time",
"Update chats faster when switching between apps."
)
case .autodownloadInBackground:
return (
"Settings/Power/PowerIconMedia",
"Preload Media",
"Start loading media while in the chat list for faster access."
)
}
}
}
private final class EnergeSavingSettingsScreenArguments {
let updateThreshold: (Int32) -> Void
let toggleItem: (ItemType) -> Void
let displayDisabledTooltip: () -> Void
init(updateThreshold: @escaping (Int32) -> Void, toggleItem: @escaping (ItemType) -> Void, displayDisabledTooltip: @escaping () -> Void) {
self.updateThreshold = updateThreshold
self.toggleItem = toggleItem
self.displayDisabledTooltip = displayDisabledTooltip
}
}
private enum EnergeSavingSettingsScreenSection: Int32 {
case all
case items
}
private enum EnergeSavingSettingsScreenEntry: ItemListNodeEntry {
enum StableId: Hashable {
case allHeader
case all
case allFooter
case itemsHeader
case item(ItemType)
}
case allHeader(Bool?)
case all(Int32)
case allFooter(String)
case item(index: Int, type: ItemType, value: Bool, enabled: Bool)
case itemsHeader
var section: ItemListSectionId {
switch self {
case .allHeader, .all, .allFooter:
return EnergeSavingSettingsScreenSection.all.rawValue
case .item, .itemsHeader:
return EnergeSavingSettingsScreenSection.items.rawValue
}
}
var sortIndex: Int {
switch self {
case .allHeader:
return -4
case .all:
return -3
case .allFooter:
return -2
case .itemsHeader:
return -1
case let .item(index, _, _, _):
return index
}
}
var stableId: StableId {
switch self {
case .allHeader:
return .allHeader
case .all:
return .all
case .allFooter:
return .allFooter
case .itemsHeader:
return .itemsHeader
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 .allHeader(value):
//TODO:localize
let text: String
if let value {
let modeValue = value ? "ON" : "OFF"
text = "POWER SAVING MODE (\(modeValue))"
} else {
text = "POWER SAVING MODE"
}
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .all(value):
return EnergyUsageBatteryLevelItem(
theme: presentationData.theme,
strings: presentationData.strings,
value: value,
sectionId: self.section,
updated: { value in
arguments.updateThreshold(value)
}
)
case let .allFooter(text):
return ItemListTextItem(presentationData: presentationData, text: .plain(text), 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)
}, activatedWhileDisabled: {
arguments.displayDisabledTooltip()
})
}
}
}
private func energeSavingSettingsScreenEntries(
presentationData: PresentationData,
settings: MediaAutoDownloadSettings
) -> [EnergeSavingSettingsScreenEntry] {
var entries: [EnergeSavingSettingsScreenEntry] = []
let isOn = automaticEnergyUsageShouldBeOnNow(settings: settings)
let allIsOn: Bool?
if settings.energyUsageSettings.activationThreshold == 0 || settings.energyUsageSettings.activationThreshold == 100 {
allIsOn = nil
} else {
allIsOn = isOn
}
entries.append(.allHeader(allIsOn))
entries.append(.all(settings.energyUsageSettings.activationThreshold))
let allText: String
if settings.energyUsageSettings.activationThreshold == 0 {
allText = "Dont disable all resource-intensive processes even when the battery is low."
} else if settings.energyUsageSettings.activationThreshold >= 100 {
allText = "Always disable all resource-intensive processes, regardless of the battery charge level."
} else {
allText = "Automatically disable all resource-intensive processes when your battery is below \(settings.energyUsageSettings.activationThreshold)%."
}
entries.append(.allFooter(allText))
let itemsEnabled: Bool
if settings.energyUsageSettings.activationThreshold == 0 {
itemsEnabled = true
} else if settings.energyUsageSettings.activationThreshold == 100 {
itemsEnabled = false
} else if isOn {
itemsEnabled = false
} else {
itemsEnabled = true
}
entries.append(.itemsHeader)
for type in ItemType.allCases {
entries.append(.item(index: entries.count, type: type, value: settings.energyUsageSettings[keyPath: type.settingsKeyPath], enabled: itemsEnabled))
}
return entries
}
public func energySavingSettingsScreen(context: AccountContext) -> ViewController {
var pushControllerImpl: ((ViewController) -> Void)?
let _ = pushControllerImpl
var displayTooltipImpl: ((UndoOverlayContent) -> Void)?
let arguments = EnergeSavingSettingsScreenArguments(
updateThreshold: { value in
let _ = updateMediaDownloadSettingsInteractively(accountManager: context.sharedContext.accountManager, { settings in
var settings = settings
settings.energyUsageSettings.activationThreshold = max(0, min(100, 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()
},
displayDisabledTooltip: {
//TODO:localize
let text: String
if context.sharedContext.currentAutomaticMediaDownloadSettings.energyUsageSettings.activationThreshold == 100 {
text = "Turn off Power Saving Mode to change these settings."
} else {
text = "Turn off Power Saving Mode or charge your phone to change these settings."
}
displayTooltipImpl?(.universal(animation: "lowbattery_30", scale: 1.0, colors: [:], title: nil, text: text, customUndoText: nil))
}
)
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)
}
}
displayTooltipImpl = { [weak controller] c in
if let controller = controller {
let presentationData = context.sharedContext.currentPresentationData.with({ $0 })
controller.present(UndoOverlayController(presentationData: presentationData, content: c, elevatedLayout: false, action: { _ in return false }), in: .current)
}
}
return controller
}