mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 22:25:57 +00:00
Storage management improvements
This commit is contained in:
@@ -22,6 +22,7 @@ private func interpolateChartData(start: PieChartComponent.ChartData, end: PieCh
|
||||
for i in 0 ..< result.items.count {
|
||||
result.items[i].value = (1.0 - progress) * start.items[i].value + progress * end.items[i].value
|
||||
result.items[i].color = start.items[i].color.interpolateTo(end.items[i].color, fraction: progress) ?? end.items[i].color
|
||||
result.items[i].mergeFactor = (1.0 - progress) * start.items[i].mergeFactor + progress * end.items[i].mergeFactor
|
||||
}
|
||||
|
||||
return result
|
||||
@@ -139,12 +140,16 @@ final class PieChartComponent: Component {
|
||||
var displayValue: Double
|
||||
var value: Double
|
||||
var color: UIColor
|
||||
var mergeable: Bool
|
||||
var mergeFactor: CGFloat
|
||||
|
||||
init(id: StorageUsageScreenComponent.Category, displayValue: Double, value: Double, color: UIColor) {
|
||||
init(id: StorageUsageScreenComponent.Category, displayValue: Double, value: Double, color: UIColor, mergeable: Bool, mergeFactor: CGFloat) {
|
||||
self.id = id
|
||||
self.displayValue = displayValue
|
||||
self.value = value
|
||||
self.color = color
|
||||
self.mergeable = mergeable
|
||||
self.mergeFactor = mergeFactor
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,12 +184,12 @@ final class PieChartComponent: Component {
|
||||
private final class ChartDataView: UIView {
|
||||
private(set) var theme: PresentationTheme?
|
||||
private(set) var data: ChartData?
|
||||
private(set) var selectedKey: StorageUsageScreenComponent.Category?
|
||||
private(set) var selectedKey: AnyHashable?
|
||||
|
||||
private var currentAnimation: (start: ChartData, end: ChartData, current: ChartData, progress: CGFloat)?
|
||||
private var animator: DisplayLinkAnimator?
|
||||
|
||||
private var labels: [StorageUsageScreenComponent.Category: ChartLabel] = [:]
|
||||
private var labels: [AnyHashable: ChartLabel] = [:]
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
@@ -201,7 +206,7 @@ final class PieChartComponent: Component {
|
||||
self.animator?.invalidate()
|
||||
}
|
||||
|
||||
func setItems(theme: PresentationTheme, data: ChartData, selectedKey: StorageUsageScreenComponent.Category?, animated: Bool) {
|
||||
func setItems(theme: PresentationTheme, data: ChartData, selectedKey: AnyHashable?, animated: Bool) {
|
||||
let data = processChartData(data: data)
|
||||
|
||||
if self.theme !== theme || self.data != data || self.selectedKey != selectedKey {
|
||||
@@ -253,7 +258,6 @@ final class PieChartComponent: Component {
|
||||
let innerDiameter: CGFloat = 100.0
|
||||
let spacing: CGFloat = 2.0
|
||||
let innerAngleSpacing: CGFloat = spacing / (innerDiameter * 0.5)
|
||||
//let minAngle: CGFloat = innerAngleSpacing * 2.0 + 2.0 / (innerDiameter * 0.5)
|
||||
|
||||
var angles: [Double] = []
|
||||
for i in 0 ..< data.items.count {
|
||||
@@ -265,13 +269,23 @@ final class PieChartComponent: Component {
|
||||
let diameter: CGFloat = 200.0
|
||||
let reducedDiameter: CGFloat = 170.0
|
||||
|
||||
let shapeLayerFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: diameter, height: diameter))
|
||||
|
||||
struct ItemAngleData {
|
||||
var angleValue: CGFloat
|
||||
var startAngle: CGFloat
|
||||
var endAngle: CGFloat
|
||||
}
|
||||
|
||||
var anglesData: [ItemAngleData] = []
|
||||
|
||||
var startAngle: CGFloat = 0.0
|
||||
for i in 0 ..< data.items.count {
|
||||
let item = data.items[i]
|
||||
|
||||
let itemOuterDiameter: CGFloat
|
||||
if let selectedKey = self.selectedKey {
|
||||
if selectedKey == item.id {
|
||||
if selectedKey == AnyHashable(item.id) {
|
||||
itemOuterDiameter = diameter
|
||||
} else {
|
||||
itemOuterDiameter = reducedDiameter
|
||||
@@ -280,24 +294,54 @@ final class PieChartComponent: Component {
|
||||
itemOuterDiameter = diameter
|
||||
}
|
||||
|
||||
let shapeLayerFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: diameter, height: diameter))
|
||||
|
||||
let angleSpacing: CGFloat = spacing / (itemOuterDiameter * 0.5)
|
||||
|
||||
let angleValue: CGFloat = angles[i]
|
||||
|
||||
var beforeSpacingFraction: CGFloat = 1.0
|
||||
var afterSpacingFraction: CGFloat = 1.0
|
||||
if item.mergeable {
|
||||
let previousItem: ChartData.Item
|
||||
if i == 0 {
|
||||
previousItem = data.items[data.items.count - 1]
|
||||
} else {
|
||||
previousItem = data.items[i - 1]
|
||||
}
|
||||
|
||||
let nextItem: ChartData.Item
|
||||
if i == data.items.count - 1 {
|
||||
nextItem = data.items[0]
|
||||
} else {
|
||||
nextItem = data.items[i + 1]
|
||||
}
|
||||
|
||||
if previousItem.mergeable {
|
||||
beforeSpacingFraction = item.mergeFactor * 1.0 + (1.0 - item.mergeFactor) * (-0.2)
|
||||
}
|
||||
if nextItem.mergeable {
|
||||
afterSpacingFraction = item.mergeFactor * 1.0 + (1.0 - item.mergeFactor) * (-0.2)
|
||||
}
|
||||
}
|
||||
|
||||
let innerStartAngle = startAngle + innerAngleSpacing * 0.5
|
||||
let arcInnerStartAngle = startAngle + innerAngleSpacing * 0.5 * beforeSpacingFraction
|
||||
|
||||
var innerEndAngle = startAngle + angleValue - innerAngleSpacing * 0.5
|
||||
innerEndAngle = max(innerEndAngle, innerStartAngle)
|
||||
var arcInnerEndAngle = startAngle + angleValue - innerAngleSpacing * 0.5 * afterSpacingFraction
|
||||
arcInnerEndAngle = max(arcInnerEndAngle, arcInnerStartAngle)
|
||||
|
||||
let outerStartAngle = startAngle + angleSpacing * 0.5
|
||||
let arcOuterStartAngle = startAngle + angleSpacing * 0.5 * beforeSpacingFraction
|
||||
var outerEndAngle = startAngle + angleValue - angleSpacing * 0.5
|
||||
outerEndAngle = max(outerEndAngle, outerStartAngle)
|
||||
var arcOuterEndAngle = startAngle + angleValue - angleSpacing * 0.5 * afterSpacingFraction
|
||||
arcOuterEndAngle = max(arcOuterEndAngle, arcOuterStartAngle)
|
||||
|
||||
let path = CGMutablePath()
|
||||
|
||||
path.addArc(center: CGPoint(x: diameter * 0.5, y: diameter * 0.5), radius: innerDiameter * 0.5, startAngle: innerEndAngle, endAngle: innerStartAngle, clockwise: true)
|
||||
path.addArc(center: CGPoint(x: diameter * 0.5, y: diameter * 0.5), radius: itemOuterDiameter * 0.5, startAngle: outerStartAngle, endAngle: outerEndAngle, clockwise: false)
|
||||
path.addArc(center: CGPoint(x: diameter * 0.5, y: diameter * 0.5), radius: innerDiameter * 0.5, startAngle: arcInnerEndAngle, endAngle: arcInnerStartAngle, clockwise: true)
|
||||
path.addArc(center: CGPoint(x: diameter * 0.5, y: diameter * 0.5), radius: itemOuterDiameter * 0.5, startAngle: arcOuterStartAngle, endAngle: arcOuterEndAngle, clockwise: false)
|
||||
|
||||
context.addPath(path)
|
||||
context.setFillColor(item.color.cgColor)
|
||||
@@ -305,7 +349,11 @@ final class PieChartComponent: Component {
|
||||
|
||||
startAngle += angleValue
|
||||
|
||||
let fractionValue: Double = floor(item.displayValue * 100.0 * 10.0) / 10.0
|
||||
anglesData.append(ItemAngleData(angleValue: angleValue, startAngle: innerStartAngle, endAngle: innerEndAngle))
|
||||
}
|
||||
|
||||
func updateItemLabel(id: AnyHashable, displayValue: Double, mergeFactor: CGFloat, angleData: ItemAngleData) {
|
||||
let fractionValue: Double = floor(displayValue * 100.0 * 10.0) / 10.0
|
||||
let fractionString: String
|
||||
if fractionValue < 0.1 {
|
||||
fractionString = "<0.1"
|
||||
@@ -316,16 +364,20 @@ final class PieChartComponent: Component {
|
||||
}
|
||||
|
||||
let label: ChartLabel
|
||||
if let current = self.labels[item.id] {
|
||||
if let current = self.labels[id] {
|
||||
label = current
|
||||
} else {
|
||||
label = ChartLabel()
|
||||
self.labels[item.id] = label
|
||||
self.labels[id] = label
|
||||
}
|
||||
let labelSize = label.update(text: "\(fractionString)%")
|
||||
|
||||
var labelFrame: CGRect?
|
||||
|
||||
let angleValue = angleData.angleValue
|
||||
let innerStartAngle = angleData.startAngle
|
||||
let innerEndAngle = angleData.endAngle
|
||||
|
||||
if angleValue >= 0.001 {
|
||||
for step in 0 ... 20 {
|
||||
let stepFraction: CGFloat = CGFloat(step) / 20.0
|
||||
@@ -472,7 +524,8 @@ final class PieChartComponent: Component {
|
||||
|
||||
var labelScale = labelFrame.width / labelSize.width
|
||||
|
||||
let normalAlpha: CGFloat = labelScale < 0.4 ? 0.0 : 1.0
|
||||
var normalAlpha: CGFloat = labelScale < 0.4 ? 0.0 : 1.0
|
||||
normalAlpha *= max(0.0, mergeFactor)
|
||||
|
||||
var relLabelCenter = CGPoint(
|
||||
x: labelFrame.midX - shapeLayerFrame.midX,
|
||||
@@ -481,7 +534,7 @@ final class PieChartComponent: Component {
|
||||
|
||||
let labelAlpha: CGFloat
|
||||
if let selectedKey = self.selectedKey {
|
||||
if selectedKey == item.id {
|
||||
if selectedKey == id {
|
||||
labelAlpha = normalAlpha
|
||||
} else {
|
||||
labelAlpha = 0.0
|
||||
@@ -499,7 +552,7 @@ final class PieChartComponent: Component {
|
||||
}
|
||||
if labelView.alpha != labelAlpha {
|
||||
let transition: Transition
|
||||
if animateIn {
|
||||
if animateIn || "".isEmpty {
|
||||
transition = .immediate
|
||||
} else {
|
||||
transition = Transition(animation: .curve(duration: 0.18, curve: .easeInOut))
|
||||
@@ -516,6 +569,34 @@ final class PieChartComponent: Component {
|
||||
labelView.transform = CGAffineTransformMakeScale(labelScale, labelScale)
|
||||
}
|
||||
}
|
||||
|
||||
var mergedItem: (displayValue: Double, angleData: ItemAngleData, mergeFactor: CGFloat)?
|
||||
for i in 0 ..< data.items.count {
|
||||
let item = data.items[i]
|
||||
let angleData = anglesData[i]
|
||||
updateItemLabel(id: item.id, displayValue: item.displayValue, mergeFactor: item.mergeFactor, angleData: angleData)
|
||||
|
||||
if item.mergeable {
|
||||
if var currentMergedItem = mergedItem {
|
||||
currentMergedItem.displayValue += item.displayValue
|
||||
currentMergedItem.angleData.startAngle = min(currentMergedItem.angleData.startAngle, angleData.startAngle)
|
||||
currentMergedItem.angleData.endAngle = max(currentMergedItem.angleData.endAngle, angleData.endAngle)
|
||||
mergedItem = currentMergedItem
|
||||
} else {
|
||||
let invertedMergeFactor: CGFloat = 1.0 - max(0.0, item.mergeFactor)
|
||||
mergedItem = (item.displayValue, angleData, invertedMergeFactor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let mergedItem {
|
||||
updateItemLabel(id: "merged", displayValue: mergedItem.displayValue, mergeFactor: mergedItem.mergeFactor, angleData: mergedItem.angleData)
|
||||
} else {
|
||||
if let label = self.labels["merged"] {
|
||||
self.labels.removeValue(forKey: "merged")
|
||||
label.removeFromSuperview()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -345,19 +345,22 @@ final class StorageUsagePanelContainerComponent: Component {
|
||||
let dateTimeFormat: PresentationDateTimeFormat
|
||||
let insets: UIEdgeInsets
|
||||
let items: [Item]
|
||||
let currentPanelUpdated: (AnyHashable, Transition) -> Void
|
||||
|
||||
init(
|
||||
theme: PresentationTheme,
|
||||
strings: PresentationStrings,
|
||||
dateTimeFormat: PresentationDateTimeFormat,
|
||||
insets: UIEdgeInsets,
|
||||
items: [Item]
|
||||
items: [Item],
|
||||
currentPanelUpdated: @escaping (AnyHashable, Transition) -> Void
|
||||
) {
|
||||
self.theme = theme
|
||||
self.strings = strings
|
||||
self.dateTimeFormat = dateTimeFormat
|
||||
self.insets = insets
|
||||
self.items = items
|
||||
self.currentPanelUpdated = currentPanelUpdated
|
||||
}
|
||||
|
||||
static func ==(lhs: StorageUsagePanelContainerComponent, rhs: StorageUsagePanelContainerComponent) -> Bool {
|
||||
@@ -497,13 +500,6 @@ final class StorageUsagePanelContainerComponent: Component {
|
||||
}
|
||||
self.transitionFraction = transitionFraction
|
||||
self.state?.updated(transition: .immediate)
|
||||
|
||||
// let nextKey = availablePanes[updatedIndex]
|
||||
// print(transitionFraction)
|
||||
//self.paneTransitionPromise.set(transitionFraction)
|
||||
|
||||
//self.update(size: size, sideInset: sideInset, bottomInset: bottomInset, visibleHeight: visibleHeight, expansionFraction: expansionFraction, presentationData: presentationData, data: data, transition: .immediate)
|
||||
//self.currentPaneUpdated?(false)
|
||||
case .cancelled, .ended:
|
||||
guard let component = self.component, let currentId = self.currentId else {
|
||||
return
|
||||
@@ -533,7 +529,11 @@ final class StorageUsagePanelContainerComponent: Component {
|
||||
}
|
||||
self.transitionFraction = 0.0
|
||||
|
||||
self.state?.updated(transition: Transition(animation: .curve(duration: 0.35, curve: .spring)))
|
||||
let transition = Transition(animation: .curve(duration: 0.35, curve: .spring))
|
||||
if let currentId = self.currentId {
|
||||
self.state?.updated(transition: transition)
|
||||
component.currentPanelUpdated(currentId, transition)
|
||||
}
|
||||
|
||||
self.animatingTransition = false
|
||||
//self.currentPaneUpdated?(false)
|
||||
@@ -615,7 +615,9 @@ final class StorageUsagePanelContainerComponent: Component {
|
||||
}
|
||||
if component.items.contains(where: { $0.id == id }) {
|
||||
self.currentId = id
|
||||
self.state?.updated(transition: Transition(animation: .curve(duration: 0.35, curve: .spring)))
|
||||
let transition = Transition(animation: .curve(duration: 0.35, curve: .spring))
|
||||
self.state?.updated(transition: transition)
|
||||
component.currentPanelUpdated(id, transition)
|
||||
}
|
||||
}
|
||||
)),
|
||||
|
||||
@@ -175,6 +175,16 @@ final class StorageUsageScreenComponent: Component {
|
||||
let selectedPeers: Set<EnginePeer.Id>
|
||||
let selectedMessages: Set<EngineMessage.Id>
|
||||
|
||||
var isEmpty: Bool {
|
||||
if !self.selectedPeers.isEmpty {
|
||||
return false
|
||||
}
|
||||
if !self.selectedMessages.isEmpty {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
init(
|
||||
selectedPeers: Set<EnginePeer.Id>,
|
||||
selectedMessages: Set<EngineMessage.Id>
|
||||
@@ -200,17 +210,31 @@ final class StorageUsageScreenComponent: Component {
|
||||
return true
|
||||
}
|
||||
|
||||
func togglePeer(id: EnginePeer.Id) -> SelectionState {
|
||||
func togglePeer(id: EnginePeer.Id, availableMessages: [EngineMessage.Id: Message]) -> SelectionState {
|
||||
var selectedPeers = self.selectedPeers
|
||||
var selectedMessages = self.selectedMessages
|
||||
|
||||
if selectedPeers.contains(id) {
|
||||
selectedPeers.remove(id)
|
||||
|
||||
for (messageId, _) in availableMessages {
|
||||
if messageId.peerId == id {
|
||||
selectedMessages.remove(messageId)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
selectedPeers.insert(id)
|
||||
|
||||
for (messageId, _) in availableMessages {
|
||||
if messageId.peerId == id {
|
||||
selectedMessages.insert(messageId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SelectionState(
|
||||
selectedPeers: selectedPeers,
|
||||
selectedMessages: Set()
|
||||
selectedMessages: selectedMessages
|
||||
)
|
||||
}
|
||||
|
||||
@@ -223,7 +247,7 @@ final class StorageUsageScreenComponent: Component {
|
||||
}
|
||||
|
||||
return SelectionState(
|
||||
selectedPeers: Set(),
|
||||
selectedPeers: self.selectedPeers,
|
||||
selectedMessages: selectedMessages
|
||||
)
|
||||
}
|
||||
@@ -287,6 +311,7 @@ final class StorageUsageScreenComponent: Component {
|
||||
|
||||
private var currentStats: AllStorageUsageStats?
|
||||
private var existingCategories: Set<Category> = Set()
|
||||
private var otherCategories: Set<Category> = Set()
|
||||
|
||||
private var currentMessages: [MessageId: Message] = [:]
|
||||
private var cacheSettings: CacheStorageSettings?
|
||||
@@ -299,6 +324,8 @@ final class StorageUsageScreenComponent: Component {
|
||||
|
||||
private var selectionState: SelectionState?
|
||||
|
||||
private var currentSelectedPanelId: AnyHashable?
|
||||
|
||||
private var clearingDisplayTimestamp: Double?
|
||||
private var isClearing: Bool = false {
|
||||
didSet {
|
||||
@@ -501,11 +528,22 @@ final class StorageUsageScreenComponent: Component {
|
||||
animatedTransition.setAlpha(view: self.navigationBackgroundView, alpha: navigationBackgroundAlpha)
|
||||
animatedTransition.setAlpha(layer: self.navigationSeparatorLayerContainer, alpha: navigationBackgroundAlpha)
|
||||
|
||||
var buttonsMasterAlpha: CGFloat = 1.0
|
||||
if let component = self.component, component.peer != nil {
|
||||
buttonsMasterAlpha = 0.0
|
||||
} else {
|
||||
if self.currentSelectedPanelId == nil || self.currentSelectedPanelId == AnyHashable("peers") {
|
||||
buttonsMasterAlpha = 1.0
|
||||
} else {
|
||||
buttonsMasterAlpha = 0.0
|
||||
}
|
||||
}
|
||||
|
||||
if let navigationEditButtonView = self.navigationEditButton.view {
|
||||
animatedTransition.setAlpha(view: navigationEditButtonView, alpha: (self.selectionState == nil ? 1.0 : 0.0) * navigationBackgroundAlpha)
|
||||
animatedTransition.setAlpha(view: navigationEditButtonView, alpha: (self.selectionState == nil ? 1.0 : 0.0) * buttonsMasterAlpha * navigationBackgroundAlpha)
|
||||
}
|
||||
if let navigationDoneButtonView = self.navigationDoneButton.view {
|
||||
animatedTransition.setAlpha(view: navigationDoneButtonView, alpha: (self.selectionState == nil ? 0.0 : 1.0) * navigationBackgroundAlpha)
|
||||
animatedTransition.setAlpha(view: navigationDoneButtonView, alpha: (self.selectionState == nil ? 0.0 : 1.0) * buttonsMasterAlpha * navigationBackgroundAlpha)
|
||||
}
|
||||
|
||||
let expansionDistance: CGFloat = 32.0
|
||||
@@ -766,7 +804,7 @@ final class StorageUsageScreenComponent: Component {
|
||||
let sideInset: CGFloat = 16.0 + environment.safeInsets.left
|
||||
|
||||
var bottomInset: CGFloat = environment.safeInsets.bottom
|
||||
if let selectionState = self.selectionState {
|
||||
if let selectionState = self.selectionState, !selectionState.isEmpty {
|
||||
let selectionPanel: ComponentView<Empty>
|
||||
var selectionPanelTransition = transition
|
||||
if let current = self.selectionPanel {
|
||||
@@ -779,15 +817,6 @@ final class StorageUsageScreenComponent: Component {
|
||||
|
||||
var selectedSize: Int64 = 0
|
||||
if let currentStats = self.currentStats {
|
||||
for peerId in selectionState.selectedPeers {
|
||||
if let stats = currentStats.peers[peerId] {
|
||||
let peerSize = stats.stats.categories.values.reduce(0, {
|
||||
$0 + $1.size
|
||||
})
|
||||
selectedSize += peerSize
|
||||
}
|
||||
}
|
||||
|
||||
let contextStats: StorageUsageStats
|
||||
if let peer = component.peer {
|
||||
contextStats = currentStats.peers[peer.id]?.stats ?? StorageUsageStats(categories: [:])
|
||||
@@ -795,10 +824,34 @@ final class StorageUsageScreenComponent: Component {
|
||||
contextStats = currentStats.totalStats
|
||||
}
|
||||
|
||||
for peerId in selectionState.selectedPeers {
|
||||
if let stats = currentStats.peers[peerId] {
|
||||
let peerSize = stats.stats.categories.values.reduce(0, {
|
||||
$0 + $1.size
|
||||
})
|
||||
selectedSize += peerSize
|
||||
|
||||
for (messageId, _) in self.currentMessages {
|
||||
if messageId.peerId == peerId {
|
||||
if !selectionState.selectedMessages.contains(messageId) {
|
||||
inner: for (_, category) in contextStats.categories {
|
||||
if let messageSize = category.messages[messageId] {
|
||||
selectedSize -= messageSize
|
||||
break inner
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for messageId in selectionState.selectedMessages {
|
||||
for (_, category) in contextStats.categories {
|
||||
if let messageSize = category.messages[messageId] {
|
||||
selectedSize += messageSize
|
||||
if !selectionState.selectedPeers.contains(messageId.peerId) {
|
||||
selectedSize += messageSize
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -846,7 +899,7 @@ final class StorageUsageScreenComponent: Component {
|
||||
|
||||
contentHeight += environment.statusBarHeight + topInset
|
||||
|
||||
let chartOrder: [Category] = [
|
||||
let allCategories: [Category] = [
|
||||
.photos,
|
||||
.videos,
|
||||
.files,
|
||||
@@ -869,15 +922,8 @@ final class StorageUsageScreenComponent: Component {
|
||||
self.selectedCategories.removeAll()
|
||||
}
|
||||
|
||||
var chartItems: [PieChartComponent.ChartData.Item] = []
|
||||
var listCategories: [StorageCategoriesComponent.CategoryData] = []
|
||||
|
||||
let otherCategories: [Category] = [
|
||||
.stickers,
|
||||
.avatars,
|
||||
.misc
|
||||
]
|
||||
|
||||
var totalSize: Int64 = 0
|
||||
if let currentStats = self.currentStats {
|
||||
let contextStats: StorageUsageStats
|
||||
@@ -891,7 +937,7 @@ final class StorageUsageScreenComponent: Component {
|
||||
totalSize += value.size
|
||||
}
|
||||
|
||||
for category in chartOrder {
|
||||
for category in allCategories {
|
||||
let mappedCategory: StorageUsageStats.CategoryKey
|
||||
switch category {
|
||||
case .photos:
|
||||
@@ -924,18 +970,6 @@ final class StorageUsageScreenComponent: Component {
|
||||
categoryFraction = Double(categorySize) / Double(totalSize)
|
||||
}
|
||||
|
||||
var categoryChartFraction: CGFloat = categoryFraction
|
||||
if !self.selectedCategories.isEmpty && !self.selectedCategories.contains(category) {
|
||||
categoryChartFraction = 0.0
|
||||
}
|
||||
|
||||
var chartCategoryColor = category.color
|
||||
if !self.isOtherCategoryExpanded && otherCategories.contains(category) {
|
||||
chartCategoryColor = Category.misc.color
|
||||
}
|
||||
|
||||
chartItems.append(PieChartComponent.ChartData.Item(id: category, displayValue: categoryFraction, value: categoryChartFraction, color: chartCategoryColor))
|
||||
|
||||
if categorySize != 0 {
|
||||
listCategories.append(StorageCategoriesComponent.CategoryData(
|
||||
key: category, color: category.color, title: category.title(strings: environment.strings), size: categorySize, sizeFraction: categoryFraction, isSelected: self.selectedCategories.contains(category), subcategories: []))
|
||||
@@ -943,15 +977,18 @@ final class StorageUsageScreenComponent: Component {
|
||||
}
|
||||
}
|
||||
|
||||
listCategories.sort(by: { $0.sizeFraction > $1.sizeFraction })
|
||||
|
||||
var otherListCategories: [StorageCategoriesComponent.CategoryData] = []
|
||||
for listCategory in listCategories {
|
||||
if otherCategories.contains(where: { $0 == listCategory.key }) {
|
||||
otherListCategories.append(listCategory)
|
||||
if listCategories.count > 5 {
|
||||
for i in (4 ..< listCategories.count).reversed() {
|
||||
if listCategories[i].sizeFraction < 0.04 {
|
||||
otherListCategories.insert(listCategories[i], at: 0)
|
||||
listCategories.remove(at: i)
|
||||
}
|
||||
}
|
||||
}
|
||||
listCategories = listCategories.filter { item in
|
||||
return !otherCategories.contains(where: { $0 == item.key })
|
||||
}
|
||||
self.otherCategories = Set(otherListCategories.map(\.key))
|
||||
if !otherListCategories.isEmpty {
|
||||
var totalOtherSize: Int64 = 0
|
||||
for listCategory in otherListCategories {
|
||||
@@ -978,27 +1015,28 @@ final class StorageUsageScreenComponent: Component {
|
||||
key: Category.other, color: listColor, title: Category.other.title(strings: environment.strings), size: totalOtherSize, sizeFraction: categoryFraction, isSelected: isSelected, subcategories: otherListCategories))
|
||||
}
|
||||
|
||||
if !self.isOtherCategoryExpanded {
|
||||
var otherSum: CGFloat = 0.0
|
||||
var otherRealSum: CGFloat = 0.0
|
||||
for i in 0 ..< chartItems.count {
|
||||
if otherCategories.contains(chartItems[i].id) {
|
||||
var itemValue = chartItems[i].value
|
||||
if itemValue > 0.00001 {
|
||||
itemValue = max(itemValue, 0.01)
|
||||
}
|
||||
otherSum += itemValue
|
||||
otherRealSum += chartItems[i].displayValue
|
||||
if case .misc = chartItems[i].id {
|
||||
} else {
|
||||
chartItems[i].value = 0.0
|
||||
}
|
||||
}
|
||||
var chartItems: [PieChartComponent.ChartData.Item] = []
|
||||
for listCategory in listCategories {
|
||||
var categoryChartFraction: CGFloat = listCategory.sizeFraction
|
||||
if !self.selectedCategories.isEmpty && !self.selectedCategories.contains(listCategory.key) {
|
||||
categoryChartFraction = 0.0
|
||||
}
|
||||
if let index = chartItems.firstIndex(where: { $0.id == .misc }) {
|
||||
chartItems[index].value = otherSum
|
||||
chartItems[index].displayValue = otherRealSum
|
||||
chartItems.append(PieChartComponent.ChartData.Item(id: listCategory.key, displayValue: listCategory.sizeFraction, value: categoryChartFraction, color: listCategory.color, mergeable: false, mergeFactor: 1.0))
|
||||
}
|
||||
for listCategory in otherListCategories {
|
||||
var categoryChartFraction: CGFloat = listCategory.sizeFraction
|
||||
if !self.selectedCategories.isEmpty && !self.selectedCategories.contains(listCategory.key) {
|
||||
categoryChartFraction = 0.0
|
||||
}
|
||||
|
||||
let visualMergeFactor: CGFloat
|
||||
if self.isOtherCategoryExpanded {
|
||||
visualMergeFactor = 1.0
|
||||
} else {
|
||||
visualMergeFactor = 0.0
|
||||
}
|
||||
|
||||
chartItems.append(PieChartComponent.ChartData.Item(id: listCategory.key, displayValue: listCategory.sizeFraction, value: categoryChartFraction, color: self.isOtherCategoryExpanded ? listCategory.color : Category.misc.color, mergeable: true, mergeFactor: visualMergeFactor))
|
||||
}
|
||||
|
||||
let chartData = PieChartComponent.ChartData(items: chartItems)
|
||||
@@ -1254,8 +1292,7 @@ final class StorageUsageScreenComponent: Component {
|
||||
return
|
||||
}
|
||||
if key == Category.other {
|
||||
var otherCategories: [Category] = [.stickers, .avatars, .misc]
|
||||
otherCategories = otherCategories.filter(self.existingCategories.contains)
|
||||
let otherCategories = self.otherCategories.filter(self.existingCategories.contains)
|
||||
if !otherCategories.isEmpty {
|
||||
if otherCategories.allSatisfy(self.selectedCategories.contains) {
|
||||
for item in otherCategories {
|
||||
@@ -1557,7 +1594,7 @@ final class StorageUsageScreenComponent: Component {
|
||||
return
|
||||
}
|
||||
if let selectionState = self.selectionState {
|
||||
self.selectionState = selectionState.togglePeer(id: peer.id)
|
||||
self.selectionState = selectionState.togglePeer(id: peer.id, availableMessages: self.currentMessages)
|
||||
self.state?.updated(transition: Transition(animation: .curve(duration: 0.4, curve: .spring)))
|
||||
} else {
|
||||
self.openPeer(peer: peer)
|
||||
@@ -1624,7 +1661,7 @@ final class StorageUsageScreenComponent: Component {
|
||||
if self.selectionState == nil {
|
||||
self.selectionState = SelectionState()
|
||||
}
|
||||
self.selectionState = self.selectionState?.togglePeer(id: peer.id)
|
||||
self.selectionState = self.selectionState?.togglePeer(id: peer.id, availableMessages: self.currentMessages)
|
||||
self.state?.updated(transition: Transition(animation: .curve(duration: 0.4, curve: .spring)))
|
||||
})
|
||||
))
|
||||
@@ -1655,20 +1692,19 @@ final class StorageUsageScreenComponent: Component {
|
||||
panel: AnyComponent(StorageMediaGridPanelComponent(
|
||||
context: component.context,
|
||||
items: self.imageItems,
|
||||
selectionState: self.selectionState,
|
||||
selectionState: self.selectionState ?? SelectionState(),
|
||||
action: { [weak self] messageId in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
guard let message = self.currentMessages[messageId] else {
|
||||
guard let _ = self.currentMessages[messageId] else {
|
||||
return
|
||||
}
|
||||
if self.selectionState == nil {
|
||||
self.openMessage(message: message)
|
||||
} else {
|
||||
self.selectionState = self.selectionState?.toggleMessage(id: messageId)
|
||||
self.state?.updated(transition: Transition(animation: .curve(duration: 0.4, curve: .spring)))
|
||||
self.selectionState = SelectionState()
|
||||
}
|
||||
self.selectionState = self.selectionState?.toggleMessage(id: messageId)
|
||||
self.state?.updated(transition: Transition(animation: .curve(duration: 0.4, curve: .spring)))
|
||||
},
|
||||
contextAction: { [weak self] messageId, containerView, sourceRect, gesture in
|
||||
guard let self else {
|
||||
@@ -1686,20 +1722,19 @@ final class StorageUsageScreenComponent: Component {
|
||||
panel: AnyComponent(StorageFileListPanelComponent(
|
||||
context: component.context,
|
||||
items: self.fileItems,
|
||||
selectionState: self.selectionState,
|
||||
selectionState: self.selectionState ?? SelectionState(),
|
||||
action: { [weak self] messageId in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
guard let message = self.currentMessages[messageId] else {
|
||||
guard let _ = self.currentMessages[messageId] else {
|
||||
return
|
||||
}
|
||||
if self.selectionState == nil {
|
||||
self.openMessage(message: message)
|
||||
} else {
|
||||
self.selectionState = self.selectionState?.toggleMessage(id: messageId)
|
||||
self.state?.updated(transition: Transition(animation: .curve(duration: 0.4, curve: .spring)))
|
||||
self.selectionState = SelectionState()
|
||||
}
|
||||
self.selectionState = self.selectionState?.toggleMessage(id: messageId)
|
||||
self.state?.updated(transition: Transition(animation: .curve(duration: 0.4, curve: .spring)))
|
||||
},
|
||||
contextAction: { [weak self] messageId, containerView, gesture in
|
||||
guard let self else {
|
||||
@@ -1717,7 +1752,7 @@ final class StorageUsageScreenComponent: Component {
|
||||
panel: AnyComponent(StorageFileListPanelComponent(
|
||||
context: component.context,
|
||||
items: self.musicItems,
|
||||
selectionState: self.selectionState,
|
||||
selectionState: self.selectionState ?? SelectionState(),
|
||||
action: { [weak self] messageId in
|
||||
guard let self else {
|
||||
return
|
||||
@@ -1755,8 +1790,15 @@ final class StorageUsageScreenComponent: Component {
|
||||
strings: environment.strings,
|
||||
dateTimeFormat: environment.dateTimeFormat,
|
||||
insets: UIEdgeInsets(top: 0.0, left: environment.safeInsets.left, bottom: bottomInset, right: environment.safeInsets.right),
|
||||
items: panelItems)
|
||||
),
|
||||
items: panelItems,
|
||||
currentPanelUpdated: { [weak self] id, transition in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.currentSelectedPanelId = id
|
||||
self.state?.updated(transition: transition)
|
||||
}
|
||||
)),
|
||||
environment: {
|
||||
StorageUsagePanelContainerEnvironment(isScrollable: wasLockedAtPanels)
|
||||
},
|
||||
@@ -2467,7 +2509,7 @@ final class StorageUsageScreenComponent: Component {
|
||||
self.isClearing = true
|
||||
self.state?.updated(transition: .immediate)
|
||||
|
||||
let _ = (component.context.engine.resources.clearStorage(peerId: peerId, categories: mappedCategories)
|
||||
let _ = (component.context.engine.resources.clearStorage(peerId: peerId, categories: mappedCategories, excludeMessages: [])
|
||||
|> deliverOnMainQueue).start(completed: { [weak self] in
|
||||
guard let self, let component = self.component, let currentStats = self.currentStats else {
|
||||
return
|
||||
@@ -2516,7 +2558,7 @@ final class StorageUsageScreenComponent: Component {
|
||||
}
|
||||
})
|
||||
})
|
||||
} else if !peers.isEmpty {
|
||||
} else if !peers.isEmpty || !messages.isEmpty {
|
||||
self.isClearing = true
|
||||
self.state?.updated(transition: .immediate)
|
||||
|
||||
@@ -2529,7 +2571,22 @@ final class StorageUsageScreenComponent: Component {
|
||||
}
|
||||
}
|
||||
|
||||
let _ = (component.context.engine.resources.clearStorage(peerIds: peers)
|
||||
var includeMessages: [Message] = []
|
||||
var excludeMessages: [Message] = []
|
||||
|
||||
for (id, message) in self.currentMessages {
|
||||
if peers.contains(id.peerId) {
|
||||
if !messages.contains(id) {
|
||||
excludeMessages.append(message)
|
||||
}
|
||||
} else {
|
||||
if messages.contains(id) {
|
||||
includeMessages.append(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let _ = (component.context.engine.resources.clearStorage(peerIds: peers, includeMessages: includeMessages, excludeMessages: excludeMessages)
|
||||
|> deliverOnMainQueue).start(completed: { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
@@ -2539,48 +2596,6 @@ final class StorageUsageScreenComponent: Component {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if totalSize != 0 {
|
||||
self.reportClearedStorage(size: totalSize)
|
||||
}
|
||||
})
|
||||
})
|
||||
} else if !messages.isEmpty {
|
||||
var messageItems: [Message] = []
|
||||
var totalSize: Int64 = 0
|
||||
|
||||
let contextStats: StorageUsageStats
|
||||
if let peer = component.peer {
|
||||
contextStats = self.currentStats?.peers[peer.id]?.stats ?? StorageUsageStats(categories: [:])
|
||||
} else {
|
||||
contextStats = self.currentStats?.totalStats ?? StorageUsageStats(categories: [:])
|
||||
}
|
||||
|
||||
for id in messages {
|
||||
if let message = self.currentMessages[id] {
|
||||
messageItems.append(message)
|
||||
|
||||
for (_, value) in contextStats.categories {
|
||||
if let size = value.messages[id] {
|
||||
totalSize += size
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.isClearing = true
|
||||
self.state?.updated(transition: .immediate)
|
||||
|
||||
let _ = (component.context.engine.resources.clearStorage(messages: messageItems)
|
||||
|> deliverOnMainQueue).start(completed: { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
self.reloadStats(firstTime: false, completion: { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
if totalSize != 0 {
|
||||
self.reportClearedStorage(size: totalSize)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user