Compare commits
No commits in common. "bcbbe99d8f13d1c6be6be44cb0799ab9cba055cc" and "0ea5fbf996872ff1ca88d31c6f2db1b63aee1509" have entirely different histories.
bcbbe99d8f
...
0ea5fbf996
@ -432,15 +432,6 @@
|
|||||||
},
|
},
|
||||||
"Вы можете включить защиту снова в любой момент." : {
|
"Вы можете включить защиту снова в любой момент." : {
|
||||||
"comment" : "Сообщение после отключения 2FA"
|
"comment" : "Сообщение после отключения 2FA"
|
||||||
},
|
|
||||||
"Вы уверены, что хотите очистить весь кэш аватаров? Это действие необратимо." : {
|
|
||||||
|
|
||||||
},
|
|
||||||
"Вы уверены, что хотите очистить кэш для всех, кроме текущего пользователя?" : {
|
|
||||||
|
|
||||||
},
|
|
||||||
"Вы уверены, что хотите очистить кэш для текущего пользователя?" : {
|
|
||||||
|
|
||||||
},
|
},
|
||||||
"Выберите оценку — это поможет нам понять настроение." : {
|
"Выберите оценку — это поможет нам понять настроение." : {
|
||||||
"comment" : "feedback: rating hint",
|
"comment" : "feedback: rating hint",
|
||||||
@ -492,9 +483,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"Данные и кэш" : {
|
|
||||||
|
|
||||||
},
|
},
|
||||||
"Двухфакторная аутентификация" : {
|
"Двухфакторная аутентификация" : {
|
||||||
"comment" : "Заголовок экрана 2FA\nПереход к настройкам двухфакторной аутентификации",
|
"comment" : "Заголовок экрана 2FA\nПереход к настройкам двухфакторной аутентификации",
|
||||||
@ -606,6 +594,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"Заглушка: Хранилище данных" : {
|
||||||
|
|
||||||
},
|
},
|
||||||
"Загружаем ранние сообщения…" : {
|
"Загружаем ранние сообщения…" : {
|
||||||
|
|
||||||
@ -898,12 +889,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"Кэш по пользователям" : {
|
|
||||||
|
|
||||||
},
|
|
||||||
"Кэш пуст" : {
|
|
||||||
|
|
||||||
},
|
},
|
||||||
"Лента" : {
|
"Лента" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@ -973,9 +958,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"Массовая отчистка" : {
|
|
||||||
|
|
||||||
},
|
},
|
||||||
"Мессенджер-режим сейчас проработан примерно на 50%." : {
|
"Мессенджер-режим сейчас проработан примерно на 50%." : {
|
||||||
|
|
||||||
@ -1539,12 +1521,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"Общая информация" : {
|
|
||||||
|
|
||||||
},
|
|
||||||
"Общий размер" : {
|
|
||||||
|
|
||||||
},
|
},
|
||||||
"Ограничить таймер автоудаления (максимум)" : {
|
"Ограничить таймер автоудаления (максимум)" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@ -1637,21 +1613,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"Очистить" : {
|
|
||||||
|
|
||||||
},
|
|
||||||
"Очистить весь кэш" : {
|
|
||||||
|
|
||||||
},
|
|
||||||
"Очистить всё" : {
|
|
||||||
|
|
||||||
},
|
|
||||||
"Очистить кэш (кроме текущего)" : {
|
|
||||||
|
|
||||||
},
|
|
||||||
"Очистить кэш текущего пользователя" : {
|
|
||||||
|
|
||||||
},
|
},
|
||||||
"Ошибка" : {
|
"Ошибка" : {
|
||||||
"comment" : "Common error title\nContacts load error title\nProfile update error title\nЗаголовок сообщения об ошибке",
|
"comment" : "Common error title\nContacts load error title\nProfile update error title\nЗаголовок сообщения об ошибке",
|
||||||
@ -2617,9 +2578,6 @@
|
|||||||
},
|
},
|
||||||
"Текущая сессия останется активной" : {
|
"Текущая сессия останется активной" : {
|
||||||
"comment" : "Подсказка под кнопкой завершения других сессий"
|
"comment" : "Подсказка под кнопкой завершения других сессий"
|
||||||
},
|
|
||||||
"Текущий" : {
|
|
||||||
|
|
||||||
},
|
},
|
||||||
"Тема: %@" : {
|
"Тема: %@" : {
|
||||||
"comment" : "feedback: success category",
|
"comment" : "feedback: success category",
|
||||||
|
|||||||
@ -157,15 +157,6 @@ class AvatarCacheService {
|
|||||||
|
|
||||||
func clearCache(forUserId userId: String) {
|
func clearCache(forUserId userId: String) {
|
||||||
guard let directory = cacheDirectory(for: userId) else { return }
|
guard let directory = cacheDirectory(for: userId) else { return }
|
||||||
|
|
||||||
// Try to delete files inside first, ignoring errors
|
|
||||||
if let fileUrls = try? fileManager.contentsOfDirectory(at: directory, includingPropertiesForKeys: nil, options: []) {
|
|
||||||
for fileUrl in fileUrls {
|
|
||||||
try? fileManager.removeItem(at: fileUrl)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Then try to delete the directory itself
|
|
||||||
try? fileManager.removeItem(at: directory)
|
try? fileManager.removeItem(at: directory)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,43 +164,6 @@ class AvatarCacheService {
|
|||||||
guard let directory = baseCacheDirectory else { return }
|
guard let directory = baseCacheDirectory else { return }
|
||||||
try? fileManager.removeItem(at: directory)
|
try? fileManager.removeItem(at: directory)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAllCachedUserIds() -> [String] {
|
|
||||||
guard let baseDir = baseCacheDirectory else { return [] }
|
|
||||||
do {
|
|
||||||
let directoryContents = try fileManager.contentsOfDirectory(at: baseDir, includingPropertiesForKeys: nil, options: .skipsHiddenFiles)
|
|
||||||
return directoryContents.map { $0.lastPathComponent }
|
|
||||||
} catch {
|
|
||||||
// This can happen if the directory doesn't exist yet, which is not an error.
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func sizeOfCache(forUserId userId: String) -> Int64 {
|
|
||||||
guard let directory = cacheDirectory(for: userId) else { return 0 }
|
|
||||||
return directorySize(url: directory)
|
|
||||||
}
|
|
||||||
|
|
||||||
func sizeOfAllCache() -> Int64 {
|
|
||||||
guard let directory = baseCacheDirectory else { return 0 }
|
|
||||||
return directorySize(url: directory)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func directorySize(url: URL) -> Int64 {
|
|
||||||
let contents: [URL]
|
|
||||||
do {
|
|
||||||
contents = try fileManager.contentsOfDirectory(at: url, includingPropertiesForKeys: [.fileSizeKey], options: .skipsHiddenFiles)
|
|
||||||
} catch {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
var totalSize: Int64 = 0
|
|
||||||
for url in contents {
|
|
||||||
let fileSize = (try? url.resourceValues(forKeys: [.fileSizeKey]))?.fileSize ?? 0
|
|
||||||
totalSize += Int64(fileSize)
|
|
||||||
}
|
|
||||||
return totalSize
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class ImageLoader: ObservableObject {
|
class ImageLoader: ObservableObject {
|
||||||
|
|||||||
@ -1,141 +0,0 @@
|
|||||||
//
|
|
||||||
// DataSettingsView.swift
|
|
||||||
// yobble
|
|
||||||
//
|
|
||||||
// Created by cheykrym on 10.12.2025.
|
|
||||||
//
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
|
|
||||||
struct DataSettingsView: View {
|
|
||||||
let currentUserId: String
|
|
||||||
private let cacheService = AvatarCacheService.shared
|
|
||||||
|
|
||||||
@State private var cachedUsers: [CachedUserInfo] = []
|
|
||||||
@State private var totalCacheSize: Int64 = 0
|
|
||||||
@State private var showClearAllConfirmation = false
|
|
||||||
@State private var showClearOthersConfirmation = false
|
|
||||||
@State private var showClearCurrentConfirmation = false
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
Form {
|
|
||||||
Section(header: Text("Общая информация")) {
|
|
||||||
HStack {
|
|
||||||
Text("Общий размер")
|
|
||||||
Spacer()
|
|
||||||
Text(format(bytes: totalCacheSize))
|
|
||||||
.foregroundColor(.secondary)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Section(header: Text("Массовая отчистка")) {
|
|
||||||
Button("Очистить кэш текущего пользователя", role: .destructive) {
|
|
||||||
showClearCurrentConfirmation = true
|
|
||||||
}
|
|
||||||
.confirmationDialog(
|
|
||||||
"Вы уверены, что хотите очистить кэш для текущего пользователя?",
|
|
||||||
isPresented: $showClearCurrentConfirmation,
|
|
||||||
titleVisibility: .visible
|
|
||||||
) {
|
|
||||||
Button("Очистить", role: .destructive) {
|
|
||||||
clearCache(for: currentUserId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Button("Очистить кэш (кроме текущего)", role: .destructive) {
|
|
||||||
showClearOthersConfirmation = true
|
|
||||||
}
|
|
||||||
.confirmationDialog(
|
|
||||||
"Вы уверены, что хотите очистить кэш для всех, кроме текущего пользователя?",
|
|
||||||
isPresented: $showClearOthersConfirmation,
|
|
||||||
titleVisibility: .visible
|
|
||||||
) {
|
|
||||||
Button("Очистить", role: .destructive, action: clearOtherUsersCache)
|
|
||||||
}
|
|
||||||
|
|
||||||
Button("Очистить весь кэш", role: .destructive) {
|
|
||||||
showClearAllConfirmation = true
|
|
||||||
}
|
|
||||||
.confirmationDialog(
|
|
||||||
"Вы уверены, что хотите очистить весь кэш аватаров? Это действие необратимо.",
|
|
||||||
isPresented: $showClearAllConfirmation,
|
|
||||||
titleVisibility: .visible
|
|
||||||
) {
|
|
||||||
Button("Очистить всё", role: .destructive, action: clearAllCache)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Section(header: Text("Кэш по пользователям")) {
|
|
||||||
if cachedUsers.isEmpty {
|
|
||||||
Text("Кэш пуст")
|
|
||||||
.foregroundColor(.secondary)
|
|
||||||
} else {
|
|
||||||
ForEach(cachedUsers) { user in
|
|
||||||
HStack {
|
|
||||||
VStack(alignment: .leading) {
|
|
||||||
Text(user.id)
|
|
||||||
.font(.system(.body, design: .monospaced))
|
|
||||||
.lineLimit(1)
|
|
||||||
.truncationMode(.middle)
|
|
||||||
if user.id == currentUserId {
|
|
||||||
Text("Текущий")
|
|
||||||
.font(.caption)
|
|
||||||
.foregroundColor(.accentColor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Spacer()
|
|
||||||
Text(format(bytes: user.size))
|
|
||||||
.foregroundColor(.secondary)
|
|
||||||
Button("Очистить") {
|
|
||||||
clearCache(for: user.id)
|
|
||||||
}
|
|
||||||
.buttonStyle(.borderless)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.navigationTitle("Данные и кэш")
|
|
||||||
.onAppear(perform: refreshCacheStats)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func refreshCacheStats() {
|
|
||||||
let userIds = cacheService.getAllCachedUserIds()
|
|
||||||
self.cachedUsers = userIds.map { id in
|
|
||||||
let size = cacheService.sizeOfCache(forUserId: id)
|
|
||||||
return CachedUserInfo(id: id, size: size)
|
|
||||||
}.sorted { $0.size > $1.size }
|
|
||||||
|
|
||||||
self.totalCacheSize = cacheService.sizeOfAllCache()
|
|
||||||
}
|
|
||||||
|
|
||||||
private func clearCache(for userId: String) {
|
|
||||||
cacheService.clearCache(forUserId: userId)
|
|
||||||
refreshCacheStats()
|
|
||||||
}
|
|
||||||
|
|
||||||
private func clearAllCache() {
|
|
||||||
cacheService.clearAllCache()
|
|
||||||
refreshCacheStats()
|
|
||||||
}
|
|
||||||
|
|
||||||
private func clearOtherUsersCache() {
|
|
||||||
let otherUsers = cachedUsers.filter { $0.id != currentUserId }
|
|
||||||
for user in otherUsers {
|
|
||||||
cacheService.clearCache(forUserId: user.id)
|
|
||||||
}
|
|
||||||
refreshCacheStats()
|
|
||||||
}
|
|
||||||
|
|
||||||
private func format(bytes: Int64) -> String {
|
|
||||||
let formatter = ByteCountFormatter()
|
|
||||||
formatter.allowedUnits = [.useAll]
|
|
||||||
formatter.countStyle = .file
|
|
||||||
return formatter.string(fromByteCount: bytes)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CachedUserInfo: Identifiable {
|
|
||||||
let id: String
|
|
||||||
let size: Int64
|
|
||||||
}
|
|
||||||
@ -67,7 +67,7 @@ struct SettingsView: View {
|
|||||||
Label("Темы", systemImage: "moon.fill")
|
Label("Темы", systemImage: "moon.fill")
|
||||||
}
|
}
|
||||||
|
|
||||||
NavigationLink(destination: DataSettingsView(currentUserId: viewModel.userId)) {
|
NavigationLink(destination: Text("Заглушка: Хранилище данных")) {
|
||||||
Label("Данные", systemImage: "externaldrive")
|
Label("Данные", systemImage: "externaldrive")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user