From a3f000e8964c7cc84583531b0859cda5885b2cb2 Mon Sep 17 00:00:00 2001 From: Kylmakalle Date: Sun, 23 Mar 2025 00:45:26 +0200 Subject: [PATCH] sgHardReset --- Swiftgram/SGDBReset/Sources/File.swift | 115 ++++++++++++++++++ .../Settings.bundle/Root.plist | 18 +++ .../Settings.bundle/en.lproj/Root.strings | 5 +- .../Settings.bundle/ru.lproj/Root.strings | 5 +- .../TelegramUI/Sources/AppDelegate.swift | 6 + 5 files changed, 147 insertions(+), 2 deletions(-) diff --git a/Swiftgram/SGDBReset/Sources/File.swift b/Swiftgram/SGDBReset/Sources/File.swift index 1029c5e152..89c7369e88 100644 --- a/Swiftgram/SGDBReset/Sources/File.swift +++ b/Swiftgram/SGDBReset/Sources/File.swift @@ -3,6 +3,7 @@ import Foundation import SGLogging private let dbResetKey = "sg_db_reset" +private let dbHardResetKey = "sg_db_hard_reset" public func sgDBResetIfNeeded(databasePath: String, present: ((UIViewController) -> ())?) { guard UserDefaults.standard.bool(forKey: dbResetKey) else { @@ -45,3 +46,117 @@ public func sgDBResetIfNeeded(databasePath: String, present: ((UIViewController) // let semaphore = DispatchSemaphore(value: 0) // semaphore.wait() } + +public func sgHardReset(dataPath: String, present: ((UIViewController) -> ())?) { + let startAlert = UIAlertController( + title: "ATTENTION", + message: "Confirm HARD RESET?", + preferredStyle: .alert + ) + + startAlert.addAction(UIAlertAction(title: "Cancel", style: .cancel) { _ in + exit(0) + }) + startAlert.addAction(UIAlertAction(title: "RESET", style: .destructive) { _ in + let ensureAlert = UIAlertController( + title: "⚠️ ATTENTION ⚠️", + message: "ARE YOU SURE you want to make a HARD RESET?", + preferredStyle: .alert + ) + + ensureAlert.addAction(UIAlertAction(title: "Cancel", style: .default) { _ in + exit(0) + }) + ensureAlert.addAction(UIAlertAction(title: "RESET NOW", style: .destructive) { _ in + NSLog("[SG.DBReset] Hard reset with system settings") + let alert = UIAlertController( + title: "Hard reset.\nPlease wait...", + message: nil, + preferredStyle: .alert + ) + ensureAlert.dismiss(animated: false) { + present?(alert) + } + + do { + let fileManager = FileManager.default + let contents = try fileManager.contentsOfDirectory(atPath: dataPath) + + // Filter directories that match our criteria + let accountDirectories = contents.compactMap { filename in + let fullPath = (dataPath as NSString).appendingPathComponent(filename) + + var isDirectory: ObjCBool = false + if fileManager.fileExists(atPath: fullPath, isDirectory: &isDirectory), isDirectory.boolValue { + if filename.hasPrefix("account-") || filename == "accounts-metadata" { + return fullPath + } + } + return nil + } + + NSLog("[SG.DBReset] Found \(accountDirectories.count) account dirs...") + var deletedPostboxCount = 0 + for accountDir in accountDirectories { + let accountName = (accountDir as NSString).lastPathComponent + let postboxPath = (accountDir as NSString).appendingPathComponent("postbox") + + var isPostboxDir: ObjCBool = false + if fileManager.fileExists(atPath: postboxPath, isDirectory: &isPostboxDir), isPostboxDir.boolValue { + // Delete postbox/db + let dbPath = (postboxPath as NSString).appendingPathComponent("db") + var isDbDir: ObjCBool = false + if fileManager.fileExists(atPath: dbPath, isDirectory: &isDbDir), isDbDir.boolValue { + NSLog("[SG.DBReset] Trying to delete postbox/db in: \(accountName)") + try fileManager.removeItem(atPath: dbPath) + NSLog("[SG.DBReset] OK. Deleted postbox/db directory in: \(accountName)") + } + + // Delete postbox/media + let mediaPath = (postboxPath as NSString).appendingPathComponent("media") + var isMediaDir: ObjCBool = false + if fileManager.fileExists(atPath: mediaPath, isDirectory: &isMediaDir), isMediaDir.boolValue { + NSLog("[SG.DBReset] Trying to delete postbox/media in: \(accountName)") + try fileManager.removeItem(atPath: mediaPath) + NSLog("[SG.DBReset] OK. Deleted postbox/media directory in: \(accountName)") + } + + deletedPostboxCount += 1 + } + } + + + NSLog("[SG.DBReset] Done. Hard Reset completed") + let successAlert = UIAlertController( + title: "Hard reset completed", + message: nil, + preferredStyle: .alert + ) + successAlert.addAction(UIAlertAction(title: "Restart App", style: .cancel) { _ in + exit(0) + }) + alert.dismiss(animated: false) { + present?(successAlert) + } + } catch { + NSLog("[SG.DBReset] ERROR. Hard reset failed: \(error)") + let failAlert = UIAlertController( + title: "ERROR. Hard reset failed", + message: "\(error)", + preferredStyle: .alert + ) + alert.dismiss(animated: false) { + present?(failAlert) + } + } + }) + ensureAlert.addAction(UIAlertAction(title: "Cancel", style: .cancel) { _ in + exit(0) + }) + + present?(ensureAlert) + }) + + present?(startAlert) + UserDefaults.standard.set(false, forKey: dbHardResetKey) +} diff --git a/Swiftgram/SGSettingsBundle/Settings.bundle/Root.plist b/Swiftgram/SGSettingsBundle/Settings.bundle/Root.plist index 92c85b662d..148a22836f 100644 --- a/Swiftgram/SGSettingsBundle/Settings.bundle/Root.plist +++ b/Swiftgram/SGSettingsBundle/Settings.bundle/Root.plist @@ -24,6 +24,24 @@ DefaultValue + + Type + PSGroupSpecifier + FooterText + HardReset.Notice + Title + HardReset.Title + + + Type + PSToggleSwitchSpecifier + Title + HardReset.Toggle + Key + sg_db_hard_reset + DefaultValue + + diff --git a/Swiftgram/SGSettingsBundle/Settings.bundle/en.lproj/Root.strings b/Swiftgram/SGSettingsBundle/Settings.bundle/en.lproj/Root.strings index 6986865c88..fb7c4fe63d 100644 --- a/Swiftgram/SGSettingsBundle/Settings.bundle/en.lproj/Root.strings +++ b/Swiftgram/SGSettingsBundle/Settings.bundle/en.lproj/Root.strings @@ -1,5 +1,8 @@ /* A single strings file, whose title is specified in your preferences schema. The strings files provide the localized content to display to the user for each of your preferences. */ "Reset.Title" = "TROUBLESHOOTING"; -"Reset.Toggle" = "Reset caches on next launch"; +"Reset.Toggle" = "Reset metadata"; "Reset.Notice" = "Use in case you're stuck and can't open the app. This WILL NOT logout your accounts, but all secret chats will be lost."; +"HardReset.Title" = ""; +"HardReset.Toggle" = "Reset all"; +"HardReset.Notice" = "Clears metadata, cached messages and media for all accounts. This should not logout your accounts, but proceed at YOUR OWN RISK. All secret chats will be lost."; \ No newline at end of file diff --git a/Swiftgram/SGSettingsBundle/Settings.bundle/ru.lproj/Root.strings b/Swiftgram/SGSettingsBundle/Settings.bundle/ru.lproj/Root.strings index 42015a1b91..4da4548194 100644 --- a/Swiftgram/SGSettingsBundle/Settings.bundle/ru.lproj/Root.strings +++ b/Swiftgram/SGSettingsBundle/Settings.bundle/ru.lproj/Root.strings @@ -1,3 +1,6 @@ "Reset.Title" = "РЕШЕНИЕ ПРОБЛЕМ"; -"Reset.Toggle" = "Сбросить кэш при следующем запуске"; +"Reset.Toggle" = "Сбросить метаданные"; "Reset.Notice" = "Используйте, если приложение вылетает или не загружается. Эта опция НЕ СБРАСЫВАЕТ ваши аккаунты, но удалит все секретные чаты."; +"HardReset.Title" = ""; +"HardReset.Toggle" = "Сбросить всё"; +"HardReset.Notice" = "Сбрасывает метаданные, кэшированные сообщения и медиа для всех аккаунтов. Эта опция не должна разлогинить ваши аккаунты, но используйте её на СВОЙ СТРАХ И РИСК. Все секретные чаты удалятся."; \ No newline at end of file diff --git a/submodules/TelegramUI/Sources/AppDelegate.swift b/submodules/TelegramUI/Sources/AppDelegate.swift index 49ddba2646..e96d91b200 100644 --- a/submodules/TelegramUI/Sources/AppDelegate.swift +++ b/submodules/TelegramUI/Sources/AppDelegate.swift @@ -605,6 +605,12 @@ private func extractAccountManagerState(records: AccountRecordsView