mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Storage management improvements
This commit is contained in:
parent
c714d23730
commit
4d84b04173
@ -8561,3 +8561,33 @@ Sorry for the inconvenience.";
|
||||
|
||||
"Paint.MoveForward" = "Move Forward";
|
||||
|
||||
"StorageManagement.Title" = "Storage Usage";
|
||||
"StorageManagement.TitleCleared" = "Storage Cleared";
|
||||
|
||||
"StorageManagement.DescriptionCleared" = "All media can be re-downloaded from the Telegram cloud if you need it again.";
|
||||
"StorageManagement.DescriptionChatUsage" = "This chat uses %1$@%% of your Telegram cache.";
|
||||
"StorageManagement.DescriptionAppUsage" = "Telegram uses %1$@%% of your free disk space.";
|
||||
|
||||
"StorageManagement.ClearAll" = "Clear All Cache";
|
||||
"StorageManagement.ClearSelected" = "Clear Selected";
|
||||
|
||||
"StorageManagement.SectionPhotos" = "Photos";
|
||||
"StorageManagement.SectionVideos" = "Videos";
|
||||
"StorageManagement.SectionFiles" = "Files";
|
||||
"StorageManagement.SectionMusic" = "Music";
|
||||
"StorageManagement.SectionOther" = "Other";
|
||||
"StorageManagement.SectionStickers" = "Stickers";
|
||||
"StorageManagement.SectionAvatars" = "Avatars";
|
||||
"StorageManagement.SectionMiscellaneous" = "Miscellaneous";
|
||||
|
||||
"StorageManagement.SectionsDescription" = "All media will stay in the Telegram cloud and can be re-downloaded if you need it again.";
|
||||
|
||||
"StorageManagement.AutoremoveHeader" = "AUTO-REMOVE CACHED MEDIA";
|
||||
"StorageManagement.AutoremoveDescription" = "Photos, videos and other files from cloud chats that you have **not accessed** during this period will be removed from this device to save disk space.";
|
||||
|
||||
"StorageManagement.AutoremoveSpaceDescription" = "If your cache size exceeds this limit, the oldest media will be deleted.";
|
||||
|
||||
"StorageManagement.TabChats" = "Chats";
|
||||
"StorageManagement.TabMedia" = "Media";
|
||||
"StorageManagement.TabFiles" = "Files";
|
||||
"StorageManagement.TabMusic" = "Music";
|
||||
|
@ -84,6 +84,54 @@ private func processChartData(data: PieChartComponent.ChartData) -> PieChartComp
|
||||
return data
|
||||
}
|
||||
|
||||
private let chartLabelFont = Font.with(size: 16.0, design: .round, weight: .semibold)
|
||||
|
||||
private final class ChartLabel: UIView {
|
||||
private let label: ImmediateTextView
|
||||
private var currentText: String?
|
||||
|
||||
override init(frame: CGRect) {
|
||||
self.label = ImmediateTextView()
|
||||
|
||||
super.init(frame: frame)
|
||||
|
||||
self.addSubview(self.label)
|
||||
}
|
||||
|
||||
required init(coder: NSCoder) {
|
||||
preconditionFailure()
|
||||
}
|
||||
|
||||
func update(text: String) -> CGSize {
|
||||
if self.currentText == text {
|
||||
return self.label.bounds.size
|
||||
}
|
||||
|
||||
var snapshotView: UIView?
|
||||
if self.currentText != nil {
|
||||
snapshotView = self.label.snapshotView(afterScreenUpdates: false)
|
||||
snapshotView?.frame = self.label.frame
|
||||
}
|
||||
|
||||
self.currentText = text
|
||||
self.label.attributedText = NSAttributedString(string: text, font: chartLabelFont, textColor: .white)
|
||||
let size = self.label.updateLayout(CGSize(width: 100.0, height: 100.0))
|
||||
self.label.frame = CGRect(origin: CGPoint(x: floor(-size.width * 0.5), y: floor(-size.height * 0.5)), size: size)
|
||||
|
||||
if let snapshotView {
|
||||
self.addSubview(snapshotView)
|
||||
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak snapshotView] _ in
|
||||
snapshotView?.removeFromSuperview()
|
||||
})
|
||||
snapshotView.layer.animateScale(from: 1.0, to: 0.001, duration: 0.2, removeOnCompletion: false)
|
||||
self.label.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
self.label.layer.animateScale(from: 0.001, to: 1.0, duration: 0.2)
|
||||
}
|
||||
|
||||
return size
|
||||
}
|
||||
}
|
||||
|
||||
final class PieChartComponent: Component {
|
||||
struct ChartData: Equatable {
|
||||
struct Item: Equatable {
|
||||
@ -136,7 +184,7 @@ final class PieChartComponent: Component {
|
||||
private var currentAnimation: (start: ChartData, end: ChartData, current: ChartData, progress: CGFloat)?
|
||||
private var animator: DisplayLinkAnimator?
|
||||
|
||||
private var labels: [StorageUsageScreenComponent.Category: ComponentView<Empty>] = [:]
|
||||
private var labels: [StorageUsageScreenComponent.Category: ChartLabel] = [:]
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
@ -195,7 +243,7 @@ final class PieChartComponent: Component {
|
||||
guard let context = UIGraphicsGetCurrentContext() else {
|
||||
return
|
||||
}
|
||||
guard let theme = self.theme, let data = self.currentAnimation?.current ?? self.data else {
|
||||
guard let _ = self.theme, let data = self.currentAnimation?.current ?? self.data else {
|
||||
return
|
||||
}
|
||||
if data.items.isEmpty {
|
||||
@ -267,14 +315,14 @@ final class PieChartComponent: Component {
|
||||
fractionString = "\(fractionValue)"
|
||||
}
|
||||
|
||||
let label: ComponentView<Empty>
|
||||
let label: ChartLabel
|
||||
if let current = self.labels[item.id] {
|
||||
label = current
|
||||
} else {
|
||||
label = ComponentView<Empty>()
|
||||
label = ChartLabel()
|
||||
self.labels[item.id] = label
|
||||
}
|
||||
let labelSize = label.update(transition: .immediate, component: AnyComponent(Text(text: "\(fractionString)%", font: Font.with(size: 16.0, design: .round, weight: .semibold), color: theme.list.itemCheckColors.foregroundColor)), environment: {}, containerSize: CGSize(width: 100.0, height: 100.0))
|
||||
let labelSize = label.update(text: "\(fractionString)%")
|
||||
|
||||
var labelFrame: CGRect?
|
||||
|
||||
@ -408,14 +456,14 @@ final class PieChartComponent: Component {
|
||||
labelFrame = CGRect(origin: CGPoint(x: labelCenter.x - minSize.width * 0.5, y: labelCenter.y - minSize.height * 0.5), size: minSize)
|
||||
}
|
||||
|
||||
if let labelView = label.view, let labelFrame {
|
||||
let labelView = label
|
||||
if let labelFrame {
|
||||
var animateIn: Bool = false
|
||||
if labelView.superview == nil {
|
||||
animateIn = true
|
||||
self.addSubview(labelView)
|
||||
}
|
||||
|
||||
labelView.bounds = CGRect(origin: CGPoint(), size: labelSize)
|
||||
var labelScale = labelFrame.width / labelSize.width
|
||||
|
||||
let normalAlpha: CGFloat = labelScale < 0.4 ? 0.0 : 1.0
|
||||
|
@ -199,13 +199,13 @@ final class StorageCategoriesComponent: Component {
|
||||
let clearTitle: String
|
||||
let label: String?
|
||||
if totalSelectedSize == 0 {
|
||||
clearTitle = "Clear"
|
||||
clearTitle = component.strings.StorageManagement_ClearSelected
|
||||
label = nil
|
||||
} else if hasDeselected {
|
||||
clearTitle = "Clear Selected"
|
||||
clearTitle = component.strings.StorageManagement_ClearSelected
|
||||
label = dataSizeString(totalSelectedSize, formatting: DataSizeStringFormatting(strings: component.strings, decimalSeparator: "."))
|
||||
} else {
|
||||
clearTitle = "Clear All Cache"
|
||||
clearTitle = component.strings.StorageManagement_ClearAll
|
||||
label = dataSizeString(totalSelectedSize, formatting: DataSizeStringFormatting(strings: component.strings, decimalSeparator: "."))
|
||||
}
|
||||
|
||||
|
@ -768,7 +768,7 @@ final class StorageFileListPanelComponent: Component {
|
||||
let _ = isAudio
|
||||
let _ = isVoice
|
||||
|
||||
var title: String = "File"
|
||||
var title: String = environment.strings.Message_File
|
||||
|
||||
var subtitle = stringForFullDate(timestamp: item.message.timestamp, strings: environment.strings, dateTimeFormat: environment.dateTimeFormat)
|
||||
|
||||
@ -800,7 +800,7 @@ final class StorageFileListPanelComponent: Component {
|
||||
//iconImage = .albumArt(file, SharedMediaPlaybackAlbumArt(thumbnailResource: ExternalMusicAlbumArtResource(file: .message(message: MessageReference(message), media: file), title: title ?? "", performer: performer ?? "", isThumbnail: true), fullSizeResource: ExternalMusicAlbumArtResource(file: .message(message: MessageReference(message), media: file), title: title ?? "", performer: performer ?? "", isThumbnail: false)))
|
||||
}
|
||||
} else {
|
||||
title = "Audio"
|
||||
title = environment.strings.Message_Audio
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -851,7 +851,7 @@ final class StorageFileListPanelComponent: Component {
|
||||
descriptionText = NSAttributedString(string: descriptionString, font: descriptionFont, textColor: item.presentationData.theme.theme.list.itemSecondaryTextColor)
|
||||
iconImage = .roundVideo(file)*/
|
||||
} else if !isAudio {
|
||||
var fileName: String = file.fileName ?? "File"
|
||||
var fileName: String = file.fileName ?? environment.strings.Message_File
|
||||
if file.isVideo {
|
||||
fileName = environment.strings.Message_Video
|
||||
}
|
||||
@ -868,8 +868,7 @@ final class StorageFileListPanelComponent: Component {
|
||||
}
|
||||
}
|
||||
} else if let image = media as? TelegramMediaImage {
|
||||
//TODO:localize
|
||||
title = "Photo"
|
||||
title = environment.strings.Message_Photo
|
||||
|
||||
if let representation = largestImageRepresentation(image.representations) {
|
||||
imageIconValue = .media(image, representation)
|
||||
|
@ -24,6 +24,7 @@ final class StoragePeerTypeItemComponent: Component {
|
||||
let theme: PresentationTheme
|
||||
let iconName: String
|
||||
let title: String
|
||||
let subtitle: String?
|
||||
let value: String
|
||||
let hasNext: Bool
|
||||
let action: (View) -> Void
|
||||
@ -32,6 +33,7 @@ final class StoragePeerTypeItemComponent: Component {
|
||||
theme: PresentationTheme,
|
||||
iconName: String,
|
||||
title: String,
|
||||
subtitle: String?,
|
||||
value: String,
|
||||
hasNext: Bool,
|
||||
action: @escaping (View) -> Void
|
||||
@ -39,6 +41,7 @@ final class StoragePeerTypeItemComponent: Component {
|
||||
self.theme = theme
|
||||
self.iconName = iconName
|
||||
self.title = title
|
||||
self.subtitle = subtitle
|
||||
self.value = value
|
||||
self.hasNext = hasNext
|
||||
self.action = action
|
||||
@ -54,6 +57,9 @@ final class StoragePeerTypeItemComponent: Component {
|
||||
if lhs.title != rhs.title {
|
||||
return false
|
||||
}
|
||||
if lhs.subtitle != rhs.subtitle {
|
||||
return false
|
||||
}
|
||||
if lhs.value != rhs.value {
|
||||
return false
|
||||
}
|
||||
@ -66,6 +72,7 @@ final class StoragePeerTypeItemComponent: Component {
|
||||
class View: HighlightTrackingButton {
|
||||
private let iconView: UIImageView
|
||||
private let title = ComponentView<Empty>()
|
||||
private var subtitle: ComponentView<Empty>?
|
||||
private let label = ComponentView<Empty>()
|
||||
private let separatorLayer: SimpleLayer
|
||||
private let arrowIconView: UIImageView
|
||||
@ -171,9 +178,48 @@ final class StoragePeerTypeItemComponent: Component {
|
||||
containerSize: CGSize(width: availableWidth, height: 100.0)
|
||||
)
|
||||
|
||||
let height: CGFloat = 44.0
|
||||
var subtitleSize: CGSize?
|
||||
if let subtitleValue = component.subtitle {
|
||||
let subtitle: ComponentView<Empty>
|
||||
if let current = self.subtitle {
|
||||
subtitle = current
|
||||
} else {
|
||||
subtitle = ComponentView()
|
||||
self.subtitle = subtitle
|
||||
}
|
||||
|
||||
let subtitleSizeValue = subtitle.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(Text(text: subtitleValue, font: Font.regular(15.0), color: component.theme.list.itemSecondaryTextColor)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: availableWidth, height: 100.0)
|
||||
)
|
||||
subtitleSize = subtitleSizeValue
|
||||
} else {
|
||||
if let subtitle = self.subtitle {
|
||||
self.subtitle = nil
|
||||
subtitle.view?.removeFromSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
var height: CGFloat = 44.0
|
||||
if subtitleSize != nil {
|
||||
height = 60.0
|
||||
}
|
||||
|
||||
let titleFrame: CGRect
|
||||
var subtitleFrame: CGRect?
|
||||
|
||||
if let subtitleSize = subtitleSize {
|
||||
let spacing: CGFloat = 1.0
|
||||
let verticalSize: CGFloat = titleSize.height + subtitleSize.height + spacing
|
||||
|
||||
titleFrame = CGRect(origin: CGPoint(x: leftInset, y: floor((height - verticalSize) / 2.0)), size: titleSize)
|
||||
subtitleFrame = CGRect(origin: CGPoint(x: leftInset, y: titleFrame.maxY + spacing), size: subtitleSize)
|
||||
} else {
|
||||
titleFrame = CGRect(origin: CGPoint(x: leftInset, y: floor((height - titleSize.height) / 2.0)), size: titleSize)
|
||||
}
|
||||
|
||||
let titleFrame = CGRect(origin: CGPoint(x: leftInset, y: floor((height - titleSize.height) / 2.0)), size: titleSize)
|
||||
let labelFrame = CGRect(origin: CGPoint(x: availableSize.width - rightInset - labelSize.width, y: floor((height - labelSize.height) / 2.0)), size: labelSize)
|
||||
|
||||
if let titleView = self.title.view {
|
||||
@ -183,6 +229,13 @@ final class StoragePeerTypeItemComponent: Component {
|
||||
}
|
||||
transition.setFrame(view: titleView, frame: titleFrame)
|
||||
}
|
||||
if let subtitleView = self.subtitle?.view, let subtitleFrame {
|
||||
if subtitleView.superview == nil {
|
||||
subtitleView.isUserInteractionEnabled = false
|
||||
self.addSubview(subtitleView)
|
||||
}
|
||||
transition.setFrame(view: subtitleView, frame: subtitleFrame)
|
||||
}
|
||||
if let labelView = self.label.view {
|
||||
if labelView.superview == nil {
|
||||
labelView.isUserInteractionEnabled = false
|
||||
|
@ -195,21 +195,21 @@ final class StorageUsageScreenComponent: Component {
|
||||
func title(strings: PresentationStrings) -> String {
|
||||
switch self {
|
||||
case .photos:
|
||||
return "Photos"
|
||||
return strings.StorageManagement_SectionPhotos
|
||||
case .videos:
|
||||
return "Videos"
|
||||
return strings.StorageManagement_SectionVideos
|
||||
case .files:
|
||||
return "Files"
|
||||
return strings.StorageManagement_SectionFiles
|
||||
case .music:
|
||||
return "Music"
|
||||
return strings.StorageManagement_SectionMusic
|
||||
case .other:
|
||||
return "Other"
|
||||
return strings.StorageManagement_SectionOther
|
||||
case .stickers:
|
||||
return "Stickers"
|
||||
return strings.StorageManagement_SectionStickers
|
||||
case .avatars:
|
||||
return "Avatars"
|
||||
return strings.StorageManagement_SectionAvatars
|
||||
case .misc:
|
||||
return "Miscellaneous"
|
||||
return strings.StorageManagement_SectionMiscellaneous
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -222,6 +222,8 @@ final class StorageUsageScreenComponent: Component {
|
||||
|
||||
private var currentMessages: [MessageId: Message] = [:]
|
||||
private var cacheSettings: CacheStorageSettings?
|
||||
private var cacheSettingsExceptionCount: [CacheStorageSettings.PeerStorageCategory: Int32]?
|
||||
|
||||
private var peerItems: StoragePeerListPanelComponent.Items?
|
||||
private var imageItems: StorageFileListPanelComponent.Items?
|
||||
private var fileItems: StorageFileListPanelComponent.Items?
|
||||
@ -449,22 +451,69 @@ final class StorageUsageScreenComponent: Component {
|
||||
let environment = environment[ViewControllerComponentContainer.Environment.self].value
|
||||
|
||||
if self.statsDisposable == nil {
|
||||
self.cacheSettingsDisposable = (component.context.sharedContext.accountManager.sharedData(keys: [SharedDataKeys.cacheStorageSettings])
|
||||
|> map { sharedData -> CacheStorageSettings in
|
||||
let cacheSettings: CacheStorageSettings
|
||||
if let value = sharedData.entries[SharedDataKeys.cacheStorageSettings]?.get(CacheStorageSettings.self) {
|
||||
let context = component.context
|
||||
let viewKey: PostboxViewKey = .preferences(keys: Set([PreferencesKeys.accountSpecificCacheStorageSettings]))
|
||||
let cacheSettingsExceptionCount: Signal<[CacheStorageSettings.PeerStorageCategory: Int32], NoError> = component.context.account.postbox.combinedView(keys: [viewKey])
|
||||
|> map { views -> AccountSpecificCacheStorageSettings in
|
||||
let cacheSettings: AccountSpecificCacheStorageSettings
|
||||
if let view = views.views[viewKey] as? PreferencesView, let value = view.values[PreferencesKeys.accountSpecificCacheStorageSettings]?.get(AccountSpecificCacheStorageSettings.self) {
|
||||
cacheSettings = value
|
||||
} else {
|
||||
cacheSettings = CacheStorageSettings.defaultSettings
|
||||
cacheSettings = AccountSpecificCacheStorageSettings.defaultSettings
|
||||
}
|
||||
|
||||
return cacheSettings
|
||||
}
|
||||
|> deliverOnMainQueue).start(next: { [weak self] cacheSettings in
|
||||
|> distinctUntilChanged
|
||||
|> mapToSignal { accountSpecificSettings -> Signal<[CacheStorageSettings.PeerStorageCategory: Int32], NoError> in
|
||||
return context.engine.data.get(
|
||||
EngineDataMap(accountSpecificSettings.peerStorageTimeoutExceptions.map(\.key).map(TelegramEngine.EngineData.Item.Peer.Peer.init(id:)))
|
||||
)
|
||||
|> map { peers -> [CacheStorageSettings.PeerStorageCategory: Int32] in
|
||||
var result: [CacheStorageSettings.PeerStorageCategory: Int32] = [:]
|
||||
|
||||
for (_, peer) in peers {
|
||||
guard let peer else {
|
||||
continue
|
||||
}
|
||||
switch peer {
|
||||
case .user, .secretChat:
|
||||
result[.privateChats, default: 0] += 1
|
||||
case .legacyGroup:
|
||||
result[.groups, default: 0] += 1
|
||||
case let .channel(channel):
|
||||
if case .group = channel.info {
|
||||
result[.groups, default: 0] += 1
|
||||
} else {
|
||||
result[.channels, default: 0] += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
self.cacheSettingsDisposable = (combineLatest(queue: .mainQueue(),
|
||||
component.context.sharedContext.accountManager.sharedData(keys: [SharedDataKeys.cacheStorageSettings])
|
||||
|> map { sharedData -> CacheStorageSettings in
|
||||
let cacheSettings: CacheStorageSettings
|
||||
if let value = sharedData.entries[SharedDataKeys.cacheStorageSettings]?.get(CacheStorageSettings.self) {
|
||||
cacheSettings = value
|
||||
} else {
|
||||
cacheSettings = CacheStorageSettings.defaultSettings
|
||||
}
|
||||
|
||||
return cacheSettings
|
||||
},
|
||||
cacheSettingsExceptionCount
|
||||
)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] cacheSettings, cacheSettingsExceptionCount in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.cacheSettings = cacheSettings
|
||||
self.cacheSettingsExceptionCount = cacheSettingsExceptionCount
|
||||
if self.currentStats != nil {
|
||||
self.state?.updated(transition: .immediate)
|
||||
}
|
||||
@ -620,7 +669,7 @@ final class StorageUsageScreenComponent: Component {
|
||||
transition: selectionPanelTransition,
|
||||
component: AnyComponent(StorageUsageScreenSelectionPanelComponent(
|
||||
theme: environment.theme,
|
||||
title: "Clear Selected",
|
||||
title: environment.strings.StorageManagement_ClearSelected,
|
||||
label: selectedSize == 0 ? nil : dataSizeString(Int(selectedSize), formatting: DataSizeStringFormatting(strings: environment.strings, decimalSeparator: ".")),
|
||||
isEnabled: selectedSize != 0,
|
||||
insets: UIEdgeInsets(top: 0.0, left: sideInset, bottom: environment.safeInsets.bottom, right: sideInset),
|
||||
@ -887,19 +936,19 @@ final class StorageUsageScreenComponent: Component {
|
||||
}
|
||||
}
|
||||
|
||||
contentHeight += 26.0
|
||||
contentHeight += 23.0
|
||||
|
||||
let headerText: String
|
||||
if listCategories.isEmpty {
|
||||
headerText = "Storage Cleared"
|
||||
headerText = environment.strings.StorageManagement_TitleCleared
|
||||
} else if let peer = component.peer {
|
||||
headerText = peer.displayTitle(strings: environment.strings, displayOrder: .firstLast)
|
||||
} else {
|
||||
headerText = "Storage Usage"
|
||||
headerText = environment.strings.StorageManagement_Title
|
||||
}
|
||||
let headerViewSize = self.headerView.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(Text(text: headerText, font: Font.semibold(22.0), color: environment.theme.list.itemPrimaryTextColor)),
|
||||
component: AnyComponent(Text(text: headerText, font: Font.semibold(20.0), color: environment.theme.list.itemPrimaryTextColor)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: floor((availableSize.width - navigationRightButtonMaxWidth * 2.0) / 0.8), height: 100.0)
|
||||
)
|
||||
@ -913,16 +962,15 @@ final class StorageUsageScreenComponent: Component {
|
||||
}
|
||||
contentHeight += headerViewSize.height
|
||||
|
||||
contentHeight += 4.0
|
||||
contentHeight += 6.0
|
||||
|
||||
let body = MarkdownAttributeSet(font: Font.regular(13.0), textColor: environment.theme.list.freeTextColor)
|
||||
let bold = MarkdownAttributeSet(font: Font.semibold(13.0), textColor: environment.theme.list.freeTextColor)
|
||||
|
||||
//TODO:localize
|
||||
var usageFraction: Double = 0.0
|
||||
let totalUsageText: String
|
||||
if listCategories.isEmpty {
|
||||
totalUsageText = "All media can be re-downloaded from the Telegram cloud if you need it again."
|
||||
totalUsageText = environment.strings.StorageManagement_DescriptionCleared
|
||||
} else if let currentStats = self.currentStats {
|
||||
let contextStats: StorageUsageStats
|
||||
if let peer = component.peer {
|
||||
@ -959,7 +1007,7 @@ final class StorageUsageScreenComponent: Component {
|
||||
fractionString = "\(fractionValue)"
|
||||
}
|
||||
|
||||
totalUsageText = "This chat uses \(fractionString)% of your Telegram cache."
|
||||
totalUsageText = environment.strings.StorageManagement_DescriptionChatUsage(fractionString).string
|
||||
} else {
|
||||
let fraction: Double
|
||||
if currentStats.deviceFreeSpace != 0 && totalStatsSize != 0 {
|
||||
@ -978,7 +1026,7 @@ final class StorageUsageScreenComponent: Component {
|
||||
fractionString = "\(fractionValue)"
|
||||
}
|
||||
|
||||
totalUsageText = "Telegram uses \(fractionString)% of your free disk space."
|
||||
totalUsageText = environment.strings.StorageManagement_DescriptionAppUsage(fractionString).string
|
||||
}
|
||||
} else {
|
||||
totalUsageText = " "
|
||||
@ -1117,10 +1165,9 @@ final class StorageUsageScreenComponent: Component {
|
||||
contentHeight += 8.0
|
||||
|
||||
|
||||
//TODO:localize
|
||||
let categoriesDescriptionSize = self.categoriesDescriptionView.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(MultilineTextComponent(text: .markdown(text: "All media will stay in the Telegram cloud and can be re-downloaded if you need it again.", attributes: MarkdownAttributes(
|
||||
component: AnyComponent(MultilineTextComponent(text: .markdown(text: environment.strings.StorageManagement_SectionsDescription, attributes: MarkdownAttributes(
|
||||
body: body,
|
||||
bold: bold,
|
||||
link: body,
|
||||
@ -1144,12 +1191,11 @@ final class StorageUsageScreenComponent: Component {
|
||||
}
|
||||
|
||||
if component.peer == nil {
|
||||
//TODO:localize
|
||||
let keepDurationTitleSize = self.keepDurationTitleView.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(MultilineTextComponent(
|
||||
text: .markdown(
|
||||
text: "KEEP MEDIA", attributes: MarkdownAttributes(
|
||||
text: environment.strings.StorageManagement_AutoremoveHeader, attributes: MarkdownAttributes(
|
||||
body: body,
|
||||
bold: bold,
|
||||
link: body,
|
||||
@ -1184,21 +1230,20 @@ final class StorageUsageScreenComponent: Component {
|
||||
|
||||
let mappedCategory: CacheStorageSettings.PeerStorageCategory
|
||||
|
||||
//TODO:localize
|
||||
let iconName: String
|
||||
let title: String
|
||||
switch i {
|
||||
case 0:
|
||||
iconName = "Settings/Menu/EditProfile"
|
||||
title = "Private Chats"
|
||||
title = environment.strings.Notifications_PrivateChats
|
||||
mappedCategory = .privateChats
|
||||
case 1:
|
||||
iconName = "Settings/Menu/GroupChats"
|
||||
title = "Group Chats"
|
||||
title = environment.strings.Notifications_GroupChats
|
||||
mappedCategory = .groups
|
||||
default:
|
||||
iconName = "Settings/Menu/Channels"
|
||||
title = "Channels"
|
||||
title = environment.strings.Notifications_Channels
|
||||
mappedCategory = .channels
|
||||
}
|
||||
|
||||
@ -1210,12 +1255,18 @@ final class StorageUsageScreenComponent: Component {
|
||||
optionText = timeIntervalString(strings: environment.strings, value: value)
|
||||
}
|
||||
|
||||
var subtitle: String?
|
||||
if let cacheSettingsExceptionCount = self.cacheSettingsExceptionCount, let categoryCount = cacheSettingsExceptionCount[mappedCategory] {
|
||||
subtitle = environment.strings.CacheEvictionMenu_CategoryExceptions(Int32(categoryCount))
|
||||
}
|
||||
|
||||
let itemSize = item.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(StoragePeerTypeItemComponent(
|
||||
theme: environment.theme,
|
||||
iconName: iconName,
|
||||
title: title,
|
||||
subtitle: subtitle,
|
||||
value: optionText,
|
||||
hasNext: i != 3 - 1,
|
||||
action: { [weak self] sourceView in
|
||||
@ -1242,12 +1293,11 @@ final class StorageUsageScreenComponent: Component {
|
||||
contentHeight += keepContentHeight
|
||||
contentHeight += 8.0
|
||||
|
||||
//TODO:localize
|
||||
let keepDurationDescriptionSize = self.keepDurationDescriptionView.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(MultilineTextComponent(
|
||||
text: .markdown(
|
||||
text: "Photos, videos and other files from cloud chats that you have **not accessed** during this period will be removed from this device to save disk space.", attributes: MarkdownAttributes(
|
||||
text: environment.strings.StorageManagement_AutoremoveDescription, attributes: MarkdownAttributes(
|
||||
body: body,
|
||||
bold: bold,
|
||||
link: body,
|
||||
@ -1269,12 +1319,11 @@ final class StorageUsageScreenComponent: Component {
|
||||
contentHeight += keepDurationDescriptionSize.height
|
||||
contentHeight += 40.0
|
||||
|
||||
//TODO:localize
|
||||
let keepSizeTitleSize = self.keepSizeTitleView.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(MultilineTextComponent(
|
||||
text: .markdown(
|
||||
text: "MAXIMUM CACHE SIZE", attributes: MarkdownAttributes(
|
||||
text: environment.strings.Cache_MaximumCacheSize.uppercased(), attributes: MarkdownAttributes(
|
||||
body: body,
|
||||
bold: bold,
|
||||
link: body,
|
||||
@ -1327,12 +1376,11 @@ final class StorageUsageScreenComponent: Component {
|
||||
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(
|
||||
text: environment.strings.StorageManagement_AutoremoveSpaceDescription, attributes: MarkdownAttributes(
|
||||
body: body,
|
||||
bold: bold,
|
||||
link: body,
|
||||
@ -1356,10 +1404,10 @@ final class StorageUsageScreenComponent: Component {
|
||||
}
|
||||
|
||||
var panelItems: [StorageUsagePanelContainerComponent.Item] = []
|
||||
if let peerItems = self.peerItems, !peerItems.items.isEmpty {
|
||||
if let peerItems = self.peerItems, !peerItems.items.isEmpty, !listCategories.isEmpty {
|
||||
panelItems.append(StorageUsagePanelContainerComponent.Item(
|
||||
id: "peers",
|
||||
title: "Chats",
|
||||
title: environment.strings.StorageManagement_TabChats,
|
||||
panel: AnyComponent(StoragePeerListPanelComponent(
|
||||
context: component.context,
|
||||
items: self.peerItems,
|
||||
@ -1378,10 +1426,10 @@ final class StorageUsageScreenComponent: Component {
|
||||
))
|
||||
))
|
||||
}
|
||||
if let imageItems = self.imageItems, !imageItems.items.isEmpty {
|
||||
if let imageItems = self.imageItems, !imageItems.items.isEmpty, !listCategories.isEmpty {
|
||||
panelItems.append(StorageUsagePanelContainerComponent.Item(
|
||||
id: "images",
|
||||
title: "Media",
|
||||
title: environment.strings.StorageManagement_TabMedia,
|
||||
panel: AnyComponent(StorageFileListPanelComponent(
|
||||
context: component.context,
|
||||
items: self.imageItems,
|
||||
@ -1399,10 +1447,10 @@ final class StorageUsageScreenComponent: Component {
|
||||
))
|
||||
))
|
||||
}
|
||||
if let fileItems = self.fileItems, !fileItems.items.isEmpty {
|
||||
if let fileItems = self.fileItems, !fileItems.items.isEmpty, !listCategories.isEmpty {
|
||||
panelItems.append(StorageUsagePanelContainerComponent.Item(
|
||||
id: "files",
|
||||
title: "Files",
|
||||
title: environment.strings.StorageManagement_TabFiles,
|
||||
panel: AnyComponent(StorageFileListPanelComponent(
|
||||
context: component.context,
|
||||
items: self.fileItems,
|
||||
@ -1420,10 +1468,10 @@ final class StorageUsageScreenComponent: Component {
|
||||
))
|
||||
))
|
||||
}
|
||||
if let musicItems = self.musicItems, !musicItems.items.isEmpty {
|
||||
if let musicItems = self.musicItems, !musicItems.items.isEmpty, !listCategories.isEmpty {
|
||||
panelItems.append(StorageUsagePanelContainerComponent.Item(
|
||||
id: "music",
|
||||
title: "Music",
|
||||
title: environment.strings.StorageManagement_TabMusic,
|
||||
panel: AnyComponent(StorageFileListPanelComponent(
|
||||
context: component.context,
|
||||
items: self.musicItems,
|
||||
@ -1651,8 +1699,11 @@ final class StorageUsageScreenComponent: Component {
|
||||
if let message = messages[id] {
|
||||
var matches = false
|
||||
for media in message.media {
|
||||
if media is TelegramMediaFile {
|
||||
matches = true
|
||||
if let file = media as? TelegramMediaFile {
|
||||
if file.isSticker || file.isCustomEmoji {
|
||||
} else {
|
||||
matches = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1772,11 +1823,19 @@ final class StorageUsageScreenComponent: Component {
|
||||
}
|
||||
let context = component.context
|
||||
|
||||
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let actionSheet = ActionSheetController(presentationData: presentationData)
|
||||
//TODO:localizable
|
||||
|
||||
let clearTitle: String
|
||||
if categories == self.existingCategories {
|
||||
clearTitle = presentationData.strings.StorageManagement_ClearAll
|
||||
} else {
|
||||
clearTitle = presentationData.strings.StorageManagement_ClearSelected
|
||||
}
|
||||
|
||||
actionSheet.setItemGroups([ActionSheetItemGroup(items: [
|
||||
ActionSheetButtonItem(title: "Clear Selected", color: .destructive, action: { [weak self, weak actionSheet] in
|
||||
ActionSheetButtonItem(title: clearTitle, color: .destructive, action: { [weak self, weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
|
||||
self?.commitClear(categories: categories, peers: peers, messages: messages)
|
||||
|
@ -2695,7 +2695,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||
}
|
||||
subtitleStringText = subtitle
|
||||
subtitleAttributes = MultiScaleTextState.Attributes(font: Font.regular(17.0), color: presentationData.theme.list.itemSecondaryTextColor)
|
||||
smallSubtitleAttributes = MultiScaleTextState.Attributes(font: Font.regular(15.0), color: presentationData.theme.list.itemSecondaryTextColor)
|
||||
smallSubtitleAttributes = MultiScaleTextState.Attributes(font: Font.regular(15.0), color: UIColor(white: 1.0, alpha: 0.7))
|
||||
|
||||
usernameString = ("", MultiScaleTextState.Attributes(font: Font.regular(15.0), color: presentationData.theme.list.itemSecondaryTextColor))
|
||||
} else if let _ = threadData {
|
||||
|
Loading…
x
Reference in New Issue
Block a user