mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Implement max storage size slider
This commit is contained in:
parent
f7c73e6ccb
commit
ae9eb245c4
@ -37,6 +37,7 @@ swift_library(
|
|||||||
"//submodules/UndoUI",
|
"//submodules/UndoUI",
|
||||||
"//submodules/AnimatedStickerNode",
|
"//submodules/AnimatedStickerNode",
|
||||||
"//submodules/TelegramAnimatedStickerNode",
|
"//submodules/TelegramAnimatedStickerNode",
|
||||||
|
"//submodules/LegacyComponents",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
@ -181,7 +181,7 @@ final class StorageCategoryItemComponent: Component {
|
|||||||
|
|
||||||
let rightInset: CGFloat = 16.0
|
let rightInset: CGFloat = 16.0
|
||||||
|
|
||||||
var availableWidth: CGFloat = availableSize.width - leftInset
|
var availableWidth: CGFloat = availableSize.width - leftInset - rightInset
|
||||||
|
|
||||||
if !component.category.subcategories.isEmpty {
|
if !component.category.subcategories.isEmpty {
|
||||||
let iconView: UIImageView
|
let iconView: UIImageView
|
||||||
@ -218,23 +218,23 @@ final class StorageCategoryItemComponent: Component {
|
|||||||
|
|
||||||
let labelSize = self.label.update(
|
let labelSize = self.label.update(
|
||||||
transition: transition,
|
transition: transition,
|
||||||
component: AnyComponent(Text(text: dataSizeString(Int(component.category.size), formatting: DataSizeStringFormatting(strings: component.strings, decimalSeparator: ".")), font: Font.regular(17.0), color: component.theme.list.itemSecondaryTextColor)),
|
component: AnyComponent(MultilineTextComponent(text: .plain(NSAttributedString(string: dataSizeString(Int(component.category.size), formatting: DataSizeStringFormatting(strings: component.strings, decimalSeparator: ".")), font: Font.regular(17.0), textColor: component.theme.list.itemSecondaryTextColor)))),
|
||||||
environment: {},
|
environment: {},
|
||||||
containerSize: CGSize(width: availableWidth, height: 100.0)
|
containerSize: CGSize(width: availableWidth, height: 100.0)
|
||||||
)
|
)
|
||||||
availableWidth = max(1.0, availableWidth - labelSize.width - 4.0)
|
availableWidth = max(1.0, availableWidth - labelSize.width - 1.0)
|
||||||
|
|
||||||
let titleValueSize = self.titleValue.update(
|
let titleValueSize = self.titleValue.update(
|
||||||
transition: transition,
|
transition: transition,
|
||||||
component: AnyComponent(Text(text: "\(fractionString)%", font: Font.regular(17.0), color: component.theme.list.itemSecondaryTextColor)),
|
component: AnyComponent(MultilineTextComponent(text: .plain(NSAttributedString(string: "\(fractionString)%", font: Font.regular(17.0), textColor: component.theme.list.itemSecondaryTextColor)))),
|
||||||
environment: {},
|
environment: {},
|
||||||
containerSize: CGSize(width: availableWidth, height: 100.0)
|
containerSize: CGSize(width: availableWidth, height: 100.0)
|
||||||
)
|
)
|
||||||
availableWidth = max(1.0, availableWidth - titleValueSize.width - 1.0)
|
availableWidth = max(1.0, availableWidth - titleValueSize.width - 4.0)
|
||||||
|
|
||||||
let titleSize = self.title.update(
|
let titleSize = self.title.update(
|
||||||
transition: transition,
|
transition: transition,
|
||||||
component: AnyComponent(Text(text: component.category.title, font: Font.regular(17.0), color: component.theme.list.itemPrimaryTextColor)),
|
component: AnyComponent(MultilineTextComponent(text: .plain(NSAttributedString(string: component.category.title, font: Font.regular(17.0), textColor: component.theme.list.itemPrimaryTextColor)))),
|
||||||
environment: {},
|
environment: {},
|
||||||
containerSize: CGSize(width: availableWidth, height: 100.0)
|
containerSize: CGSize(width: availableWidth, height: 100.0)
|
||||||
)
|
)
|
||||||
|
@ -0,0 +1,208 @@
|
|||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
import Display
|
||||||
|
import AsyncDisplayKit
|
||||||
|
import ComponentFlow
|
||||||
|
import SwiftSignalKit
|
||||||
|
import ViewControllerComponent
|
||||||
|
import ComponentDisplayAdapters
|
||||||
|
import TelegramPresentationData
|
||||||
|
import AccountContext
|
||||||
|
import TelegramCore
|
||||||
|
import MultilineTextComponent
|
||||||
|
import EmojiStatusComponent
|
||||||
|
import Postbox
|
||||||
|
import CheckNode
|
||||||
|
import SolidRoundedButtonComponent
|
||||||
|
import LegacyComponents
|
||||||
|
|
||||||
|
private func stringForCacheSize(strings: PresentationStrings, size: Int32) -> String {
|
||||||
|
if size > 100 {
|
||||||
|
return strings.Cache_NoLimit
|
||||||
|
} else {
|
||||||
|
return dataSizeString(Int64(size) * 1024 * 1024 * 1024, formatting: DataSizeStringFormatting(strings: strings, decimalSeparator: "."))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func totalDiskSpace() -> Int64 {
|
||||||
|
do {
|
||||||
|
let systemAttributes = try FileManager.default.attributesOfFileSystem(forPath: NSHomeDirectory() as String)
|
||||||
|
return (systemAttributes[FileAttributeKey.systemSize] as? NSNumber)?.int64Value ?? 0
|
||||||
|
} catch {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private let maximumCacheSizeValues: [Int32] = {
|
||||||
|
let diskSpace = totalDiskSpace()
|
||||||
|
if diskSpace > 100 * 1024 * 1024 * 1024 {
|
||||||
|
return [5, 20, 50, Int32.max]
|
||||||
|
} else if diskSpace > 50 * 1024 * 1024 * 1024 {
|
||||||
|
return [5, 16, 32, Int32.max]
|
||||||
|
} else if diskSpace > 24 * 1024 * 1024 * 1024 {
|
||||||
|
return [2, 8, 16, Int32.max]
|
||||||
|
} else {
|
||||||
|
return [1, 4, 8, Int32.max]
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
final class StorageKeepSizeComponent: Component {
|
||||||
|
let theme: PresentationTheme
|
||||||
|
let strings: PresentationStrings
|
||||||
|
let value: Int32
|
||||||
|
let updateValue: (Int32) -> Void
|
||||||
|
|
||||||
|
init(
|
||||||
|
theme: PresentationTheme,
|
||||||
|
strings: PresentationStrings,
|
||||||
|
value: Int32,
|
||||||
|
updateValue: @escaping (Int32) -> Void
|
||||||
|
) {
|
||||||
|
self.theme = theme
|
||||||
|
self.strings = strings
|
||||||
|
self.value = value
|
||||||
|
self.updateValue = updateValue
|
||||||
|
}
|
||||||
|
|
||||||
|
static func ==(lhs: StorageKeepSizeComponent, rhs: StorageKeepSizeComponent) -> Bool {
|
||||||
|
if lhs.theme !== rhs.theme {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.strings !== rhs.strings {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.value != rhs.value {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
class View: UIView {
|
||||||
|
private let titles: [ComponentView<Empty>]
|
||||||
|
private var sliderView: TGPhotoEditorSliderView?
|
||||||
|
|
||||||
|
private var component: StorageKeepSizeComponent?
|
||||||
|
private weak var state: EmptyComponentState?
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
self.titles = (0 ..< 4).map { _ in ComponentView<Empty>() }
|
||||||
|
|
||||||
|
super.init(frame: frame)
|
||||||
|
|
||||||
|
self.clipsToBounds = true
|
||||||
|
self.layer.cornerRadius = 10.0
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func update(component: StorageKeepSizeComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
|
||||||
|
let themeUpdated = self.component?.theme !== component.theme
|
||||||
|
|
||||||
|
self.component = component
|
||||||
|
self.state = state
|
||||||
|
|
||||||
|
if themeUpdated {
|
||||||
|
self.backgroundColor = component.theme.list.itemBlocksBackgroundColor
|
||||||
|
}
|
||||||
|
|
||||||
|
let height: CGFloat = 88.0
|
||||||
|
|
||||||
|
var titleSizes: [CGSize] = []
|
||||||
|
for i in 0 ..< self.titles.count {
|
||||||
|
let titleSize = self.titles[i].update(
|
||||||
|
transition: .immediate,
|
||||||
|
component: AnyComponent(Text(text: stringForCacheSize(strings: component.strings, size: maximumCacheSizeValues[i]), font: Font.regular(13.0), color: component.theme.list.itemSecondaryTextColor)),
|
||||||
|
environment: {},
|
||||||
|
containerSize: CGSize(width: 100.0, height: 100.0)
|
||||||
|
)
|
||||||
|
titleSizes.append(titleSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
let delta = (availableSize.width - 18.0 * 2.0) / CGFloat(titleSizes.count - 1)
|
||||||
|
for i in 0 ..< titleSizes.count {
|
||||||
|
let titleSize = titleSizes[i]
|
||||||
|
if let titleView = self.titles[i].view {
|
||||||
|
if titleView.superview == nil {
|
||||||
|
self.addSubview(titleView)
|
||||||
|
}
|
||||||
|
|
||||||
|
var position: CGFloat = 18.0 + delta * CGFloat(i)
|
||||||
|
if i == titleSizes.count - 1 {
|
||||||
|
position -= titleSize.width
|
||||||
|
} else if i > 0 {
|
||||||
|
position -= titleSize.width / 2.0
|
||||||
|
}
|
||||||
|
transition.setFrame(view: titleView, frame: CGRect(origin: CGPoint(x: position, y: 15.0), size: titleSize))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var sliderFirstTime = false
|
||||||
|
let sliderView: TGPhotoEditorSliderView
|
||||||
|
if let current = self.sliderView {
|
||||||
|
sliderView = current
|
||||||
|
} else {
|
||||||
|
sliderFirstTime = true
|
||||||
|
sliderView = TGPhotoEditorSliderView()
|
||||||
|
sliderView.enablePanHandling = true
|
||||||
|
sliderView.trackCornerRadius = 2.0
|
||||||
|
sliderView.lineSize = 4.0
|
||||||
|
sliderView.dotSize = 5.0
|
||||||
|
sliderView.minimumValue = 0.0
|
||||||
|
sliderView.maximumValue = 3.0
|
||||||
|
sliderView.startValue = 0.0
|
||||||
|
sliderView.disablesInteractiveTransitionGestureRecognizer = true
|
||||||
|
sliderView.positionsCount = 4
|
||||||
|
sliderView.useLinesForPositions = true
|
||||||
|
sliderView.addTarget(self, action: #selector(self.sliderValueChanged), for: .valueChanged)
|
||||||
|
self.sliderView = sliderView
|
||||||
|
self.addSubview(sliderView)
|
||||||
|
}
|
||||||
|
|
||||||
|
if sliderFirstTime || themeUpdated {
|
||||||
|
sliderView.backgroundColor = component.theme.list.itemBlocksBackgroundColor
|
||||||
|
sliderView.backColor = component.theme.list.itemSwitchColors.frameColor
|
||||||
|
sliderView.startColor = component.theme.list.itemSwitchColors.frameColor
|
||||||
|
sliderView.trackColor = component.theme.list.itemAccentColor
|
||||||
|
sliderView.knobImage = PresentationResourcesItemList.knobImage(component.theme)
|
||||||
|
}
|
||||||
|
|
||||||
|
transition.setFrame(view: sliderView, frame: CGRect(origin: CGPoint(x: 15.0, y: 37.0), size: CGSize(width: availableSize.width - 15.0 * 2.0, height: 44.0)))
|
||||||
|
sliderView.hitTestEdgeInsets = UIEdgeInsets(top: -sliderView.frame.minX, left: 0.0, bottom: 0.0, right: -sliderView.frame.minX)
|
||||||
|
|
||||||
|
self.updateSliderView()
|
||||||
|
|
||||||
|
return CGSize(width: availableSize.width, height: height)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateSliderView() {
|
||||||
|
guard let sliderView = self.sliderView, let component = self.component else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sliderView.maximumValue = 3.0
|
||||||
|
sliderView.positionsCount = 4
|
||||||
|
|
||||||
|
let value = maximumCacheSizeValues.firstIndex(where: { $0 == component.value }) ?? 0
|
||||||
|
sliderView.value = CGFloat(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc private func sliderValueChanged() {
|
||||||
|
guard let component = self.component, let sliderView = self.sliderView else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let position = Int(sliderView.value)
|
||||||
|
let value = maximumCacheSizeValues[position]
|
||||||
|
component.updateValue(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeView() -> View {
|
||||||
|
return View(frame: CGRect())
|
||||||
|
}
|
||||||
|
|
||||||
|
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
|
||||||
|
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
|
||||||
|
}
|
||||||
|
}
|
@ -262,6 +262,10 @@ final class StorageUsageScreenComponent: Component {
|
|||||||
private var keepDurationSectionContainerView: UIView
|
private var keepDurationSectionContainerView: UIView
|
||||||
private var keepDurationItems: [AnyHashable: ComponentView<Empty>] = [:]
|
private var keepDurationItems: [AnyHashable: ComponentView<Empty>] = [:]
|
||||||
|
|
||||||
|
private let keepSizeTitleView = ComponentView<Empty>()
|
||||||
|
private let keepSizeView = ComponentView<Empty>()
|
||||||
|
private let keepSizeDescriptionView = ComponentView<Empty>()
|
||||||
|
|
||||||
private let panelContainer = ComponentView<StorageUsagePanelContainerEnvironment>()
|
private let panelContainer = ComponentView<StorageUsagePanelContainerEnvironment>()
|
||||||
|
|
||||||
private var selectionPanel: ComponentView<Empty>?
|
private var selectionPanel: ComponentView<Empty>?
|
||||||
@ -1261,6 +1265,91 @@ final class StorageUsageScreenComponent: Component {
|
|||||||
}
|
}
|
||||||
contentHeight += keepDurationDescriptionSize.height
|
contentHeight += keepDurationDescriptionSize.height
|
||||||
contentHeight += 40.0
|
contentHeight += 40.0
|
||||||
|
|
||||||
|
//TODO:localize
|
||||||
|
let keepSizeTitleSize = self.keepSizeTitleView.update(
|
||||||
|
transition: transition,
|
||||||
|
component: AnyComponent(MultilineTextComponent(
|
||||||
|
text: .markdown(
|
||||||
|
text: "MAXIMUM CACHE SIZE", attributes: MarkdownAttributes(
|
||||||
|
body: body,
|
||||||
|
bold: bold,
|
||||||
|
link: body,
|
||||||
|
linkAttribute: { _ in nil }
|
||||||
|
)
|
||||||
|
),
|
||||||
|
maximumNumberOfLines: 0
|
||||||
|
)),
|
||||||
|
environment: {},
|
||||||
|
containerSize: CGSize(width: availableSize.width - sideInset * 2.0 - 15.0 * 2.0, height: 10000.0)
|
||||||
|
)
|
||||||
|
let keepSizeTitleFrame = CGRect(origin: CGPoint(x: sideInset + 15.0, y: contentHeight), size: keepSizeTitleSize)
|
||||||
|
if let keepSizeTitleComponentView = self.keepSizeTitleView.view {
|
||||||
|
if keepSizeTitleComponentView.superview == nil {
|
||||||
|
self.scrollView.addSubview(keepSizeTitleComponentView)
|
||||||
|
}
|
||||||
|
transition.setFrame(view: keepSizeTitleComponentView, frame: keepSizeTitleFrame)
|
||||||
|
}
|
||||||
|
contentHeight += keepSizeTitleSize.height
|
||||||
|
contentHeight += 8.0
|
||||||
|
|
||||||
|
let keepSizeSize = self.keepSizeView.update(
|
||||||
|
transition: transition,
|
||||||
|
component: AnyComponent(StorageKeepSizeComponent(
|
||||||
|
theme: environment.theme,
|
||||||
|
strings: environment.strings,
|
||||||
|
value: cacheSettings?.defaultCacheStorageLimitGigabytes ?? 32,
|
||||||
|
updateValue: { [weak self] value in
|
||||||
|
guard let self, let component = self.component else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let value = max(5, value)
|
||||||
|
let _ = updateCacheStorageSettingsInteractively(accountManager: component.context.sharedContext.accountManager, { current in
|
||||||
|
var current = current
|
||||||
|
current.defaultCacheStorageLimitGigabytes = value
|
||||||
|
return current
|
||||||
|
}).start()
|
||||||
|
}
|
||||||
|
)),
|
||||||
|
environment: {},
|
||||||
|
containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 10000.0)
|
||||||
|
)
|
||||||
|
let keepSizeFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: keepSizeSize)
|
||||||
|
if let keepSizeComponentView = self.keepSizeView.view {
|
||||||
|
if keepSizeComponentView.superview == nil {
|
||||||
|
self.scrollView.addSubview(keepSizeComponentView)
|
||||||
|
}
|
||||||
|
transition.setFrame(view: keepSizeComponentView, frame: keepSizeFrame)
|
||||||
|
}
|
||||||
|
contentHeight += keepSizeSize.height
|
||||||
|
contentHeight += 8.0
|
||||||
|
|
||||||
|
//TODO:localize
|
||||||
|
let keepSizeDescriptionSize = self.keepSizeDescriptionView.update(
|
||||||
|
transition: transition,
|
||||||
|
component: AnyComponent(MultilineTextComponent(
|
||||||
|
text: .markdown(
|
||||||
|
text: "If your cache size exceeds this limit, the oldest media will be deleted.", attributes: MarkdownAttributes(
|
||||||
|
body: body,
|
||||||
|
bold: bold,
|
||||||
|
link: body,
|
||||||
|
linkAttribute: { _ in nil }
|
||||||
|
)
|
||||||
|
),
|
||||||
|
maximumNumberOfLines: 0
|
||||||
|
)),
|
||||||
|
environment: {},
|
||||||
|
containerSize: CGSize(width: availableSize.width - sideInset * 2.0 - 15.0 * 2.0, height: 10000.0)
|
||||||
|
)
|
||||||
|
let keepSizeDescriptionFrame = CGRect(origin: CGPoint(x: sideInset + 15.0, y: contentHeight), size: keepSizeDescriptionSize)
|
||||||
|
if let keepSizeDescriptionComponentView = self.keepSizeDescriptionView.view {
|
||||||
|
if keepSizeDescriptionComponentView.superview == nil {
|
||||||
|
self.scrollView.addSubview(keepSizeDescriptionComponentView)
|
||||||
|
}
|
||||||
|
transition.setFrame(view: keepSizeDescriptionComponentView, frame: keepSizeDescriptionFrame)
|
||||||
|
}
|
||||||
|
contentHeight += keepSizeDescriptionSize.height
|
||||||
|
contentHeight += 40.0
|
||||||
}
|
}
|
||||||
|
|
||||||
var panelItems: [StorageUsagePanelContainerComponent.Item] = []
|
var panelItems: [StorageUsagePanelContainerComponent.Item] = []
|
||||||
|
Loading…
x
Reference in New Issue
Block a user