ура перехват крашей и информация об устройстве йес

This commit is contained in:
Lain Iwakura 2025-08-07 01:02:07 +03:00
parent a8401d6b19
commit f64df7c5e5
No known key found for this signature in database
GPG Key ID: C7C18257F2ADC6F8
3 changed files with 158 additions and 5 deletions

View File

@ -0,0 +1,77 @@
import SwiftUI
import Foundation
class CrashHandler: ObservableObject {
static let shared = CrashHandler()
@Published var hasCrashed = false
@Published var crashMessage = ""
private init() {
setupCrashHandler()
}
private func setupCrashHandler() {
NSSetUncaughtExceptionHandler { exception in
DispatchQueue.main.async {
CrashHandler.shared.hasCrashed = true
CrashHandler.shared.crashMessage = exception.reason ?? "idk че произошло\nПерезайди и скинь скрин из настроек (самый низ) (ну и че ты делал до краша)"
}
}
signal(SIGABRT) { _ in
DispatchQueue.main.async {
CrashHandler.shared.hasCrashed = true
CrashHandler.shared.crashMessage = "Похоже... приложение упало..? Ты попал на ТЕРРИТОРИИ SIGABRT\nПерезайди и скинь скрин из настроек (самый низ)"
}
}
}
func triggerTestCrash() {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
self.hasCrashed = true
self.crashMessage = "Похоже... приложение упало..? Ты попал на НЕИЗВЕДАННЫЕ ТЕРРИТОРИИ\nПерезайди и скинь скрин из настроек (самый низ)"
}
}
}
struct CrashScreen: View {
@ObservedObject var crashHandler = CrashHandler.shared
var body: some View {
VStack(spacing: 30) {
Image(systemName: "exclamationmark.triangle.fill")
.font(.system(size: 60))
.foregroundColor(.red)
Text("Произошла ошибка")
.font(.largeTitle)
.fontWeight(.bold)
Text(crashHandler.crashMessage)
.font(.body)
.multilineTextAlignment(.center)
.padding(.horizontal)
VStack(spacing: 15) {
Text("Рекомендуется:")
.font(.headline)
Text("Закрыть приложение")
Text("Открыть заново")
Text("Если проблема повторяется - переустановить")
}
.font(.body)
.foregroundColor(.secondary)
Spacer()
Button("окек") {
exit(0)
}
.buttonStyle(.borderedProminent)
.foregroundColor(.red)
}
.padding()
.background(Color(.systemBackground))
}
}

View File

@ -11,9 +11,14 @@ import SwiftUI
struct MobileMkchApp: App { struct MobileMkchApp: App {
@StateObject private var settings = Settings() @StateObject private var settings = Settings()
@StateObject private var apiClient = APIClient() @StateObject private var apiClient = APIClient()
@StateObject private var crashHandler = CrashHandler.shared
var body: some Scene { var body: some Scene {
WindowGroup { WindowGroup {
Group {
if crashHandler.hasCrashed {
CrashScreen()
} else {
NavigationView { NavigationView {
BoardsView() BoardsView()
.environmentObject(settings) .environmentObject(settings)
@ -22,4 +27,6 @@ struct MobileMkchApp: App {
.preferredColorScheme(settings.theme == "dark" ? .dark : .light) .preferredColorScheme(settings.theme == "dark" ? .dark : .light)
} }
} }
}
}
} }

View File

@ -1,5 +1,6 @@
import SwiftUI import SwiftUI
import Combine import Combine
import Darwin
struct SettingsView: View { struct SettingsView: View {
@EnvironmentObject var settings: Settings @EnvironmentObject var settings: Settings
@ -12,6 +13,8 @@ struct SettingsView: View {
@State private var testPasscodeResult: String? @State private var testPasscodeResult: String?
@State private var isTestingKey = false @State private var isTestingKey = false
@State private var isTestingPasscode = false @State private var isTestingPasscode = false
@State private var debugTapCount = 0
@State private var showingDebugMenu = false
var body: some View { var body: some View {
NavigationView { NavigationView {
@ -140,6 +143,24 @@ struct SettingsView: View {
showingInfo = true showingInfo = true
} }
} }
Section("Информация об устройстве") {
VStack(alignment: .leading, spacing: 4) {
Text("Устройство: \(getDeviceModel())")
Text("Система: \(UIDevice.current.systemName) \(UIDevice.current.systemVersion)")
Text("Тип: \(UIDevice.current.name.isEmpty ? "Не удалось определить, увы" : UIDevice.current.name)")
Text("Идентификатор: \(UIDevice.current.identifierForVendor?.uuidString ?? "Неизвестно")")
}
.font(.caption)
.foregroundColor(.secondary)
.onTapGesture {
debugTapCount += 1
if debugTapCount >= 5 {
showingDebugMenu = true
debugTapCount = 0
}
}
}
} }
.navigationTitle("Настройки") .navigationTitle("Настройки")
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
@ -153,6 +174,9 @@ struct SettingsView: View {
.sheet(isPresented: $showingAbout) { .sheet(isPresented: $showingAbout) {
AboutView() AboutView()
} }
.sheet(isPresented: $showingDebugMenu) {
DebugMenuView()
}
.alert("Информация о НЕОЖИДАНЫХ проблемах", isPresented: $showingInfo) { .alert("Информация о НЕОЖИДАНЫХ проблемах", isPresented: $showingInfo) {
Button("Закрыть") { } Button("Закрыть") { }
} message: { } message: {
@ -198,6 +222,18 @@ struct SettingsView: View {
} }
} }
} }
private func getDeviceModel() -> String {
var systemInfo = utsname()
uname(&systemInfo)
let machineMirror = Mirror(reflecting: systemInfo.machine)
let identifier = machineMirror.children.reduce("") { identifier, element in
guard let value = element.value as? Int8, value != 0 else { return identifier }
return identifier + String(UnicodeScalar(UInt8(value)))
}
return identifier
}
} }
struct AboutView: View { struct AboutView: View {
@ -237,6 +273,39 @@ struct AboutView: View {
} }
} }
struct DebugMenuView: View {
@Environment(\.dismiss) private var dismiss
var body: some View {
NavigationView {
VStack(spacing: 20) {
Text("Debug Menu")
.font(.largeTitle)
.fontWeight(.bold)
VStack(spacing: 15) {
Button("Тест краша") {
CrashHandler.shared.triggerTestCrash()
dismiss()
}
.buttonStyle(.borderedProminent)
.foregroundColor(.red)
}
Spacer()
Button("Закрыть") {
dismiss()
}
.buttonStyle(.bordered)
}
.padding()
.navigationTitle("Debug")
.navigationBarTitleDisplayMode(.inline)
}
}
}
#Preview { #Preview {
SettingsView() SettingsView()
.environmentObject(Settings()) .environmentObject(Settings())