mirror of
https://github.com/SideStore/SideStore.git
synced 2026-02-16 02:03:32 +01:00
[ADD] Error log view
This commit is contained in:
@@ -35,6 +35,9 @@
|
|||||||
1F180F94298E7A2500D1C98B /* Source+Trusted.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F180F93298E7A2500D1C98B /* Source+Trusted.swift */; };
|
1F180F94298E7A2500D1C98B /* Source+Trusted.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F180F93298E7A2500D1C98B /* Source+Trusted.swift */; };
|
||||||
1F2EF787297C4D40002FD839 /* LicensesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F2EF786297C4D40002FD839 /* LicensesView.swift */; };
|
1F2EF787297C4D40002FD839 /* LicensesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F2EF786297C4D40002FD839 /* LicensesView.swift */; };
|
||||||
1F44634529744E570070E514 /* HintView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F44634429744E570070E514 /* HintView.swift */; };
|
1F44634529744E570070E514 /* HintView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F44634429744E570070E514 /* HintView.swift */; };
|
||||||
|
1F545E83298D79E400589F68 /* ErrorLogView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F545E82298D79E400589F68 /* ErrorLogView.swift */; };
|
||||||
|
1F545E85298D84CF00589F68 /* FilePreviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F545E84298D84CF00589F68 /* FilePreviewView.swift */; };
|
||||||
|
1F545E87298D86D800589F68 /* ModalNavigationLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F545E86298D86D800589F68 /* ModalNavigationLink.swift */; };
|
||||||
1F5DF9D82974426300DDAA47 /* AppScreenshot.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F5DF9D72974426300DDAA47 /* AppScreenshot.swift */; };
|
1F5DF9D82974426300DDAA47 /* AppScreenshot.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F5DF9D72974426300DDAA47 /* AppScreenshot.swift */; };
|
||||||
1F6284D5295209DA0060AAD8 /* AppAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F6284D4295209DA0060AAD8 /* AppAction.swift */; };
|
1F6284D5295209DA0060AAD8 /* AppAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F6284D4295209DA0060AAD8 /* AppAction.swift */; };
|
||||||
1F6284D7295218980060AAD8 /* DocumentPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F6284D6295218980060AAD8 /* DocumentPicker.swift */; };
|
1F6284D7295218980060AAD8 /* DocumentPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F6284D6295218980060AAD8 /* DocumentPicker.swift */; };
|
||||||
@@ -580,6 +583,9 @@
|
|||||||
1F180F93298E7A2500D1C98B /* Source+Trusted.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Source+Trusted.swift"; sourceTree = "<group>"; };
|
1F180F93298E7A2500D1C98B /* Source+Trusted.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Source+Trusted.swift"; sourceTree = "<group>"; };
|
||||||
1F2EF786297C4D40002FD839 /* LicensesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LicensesView.swift; sourceTree = "<group>"; };
|
1F2EF786297C4D40002FD839 /* LicensesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LicensesView.swift; sourceTree = "<group>"; };
|
||||||
1F44634429744E570070E514 /* HintView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HintView.swift; sourceTree = "<group>"; };
|
1F44634429744E570070E514 /* HintView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HintView.swift; sourceTree = "<group>"; };
|
||||||
|
1F545E82298D79E400589F68 /* ErrorLogView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorLogView.swift; sourceTree = "<group>"; };
|
||||||
|
1F545E84298D84CF00589F68 /* FilePreviewView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilePreviewView.swift; sourceTree = "<group>"; };
|
||||||
|
1F545E86298D86D800589F68 /* ModalNavigationLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalNavigationLink.swift; sourceTree = "<group>"; };
|
||||||
1F5DF9D72974426300DDAA47 /* AppScreenshot.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppScreenshot.swift; sourceTree = "<group>"; };
|
1F5DF9D72974426300DDAA47 /* AppScreenshot.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppScreenshot.swift; sourceTree = "<group>"; };
|
||||||
1F6284D4295209DA0060AAD8 /* AppAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppAction.swift; sourceTree = "<group>"; };
|
1F6284D4295209DA0060AAD8 /* AppAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppAction.swift; sourceTree = "<group>"; };
|
||||||
1F6284D6295218980060AAD8 /* DocumentPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DocumentPicker.swift; sourceTree = "<group>"; };
|
1F6284D6295218980060AAD8 /* DocumentPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DocumentPicker.swift; sourceTree = "<group>"; };
|
||||||
@@ -1108,6 +1114,7 @@
|
|||||||
1FB96FCE292BBBC9007E68D1 /* SiriShortcutSetupView.swift */,
|
1FB96FCE292BBBC9007E68D1 /* SiriShortcutSetupView.swift */,
|
||||||
1F66F5B92938CA5700A910CA /* VisualEffectView.swift */,
|
1F66F5B92938CA5700A910CA /* VisualEffectView.swift */,
|
||||||
1F6284D6295218980060AAD8 /* DocumentPicker.swift */,
|
1F6284D6295218980060AAD8 /* DocumentPicker.swift */,
|
||||||
|
1F545E84298D84CF00589F68 /* FilePreviewView.swift */,
|
||||||
);
|
);
|
||||||
path = "UIView Representables";
|
path = "UIView Representables";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -1192,6 +1199,7 @@
|
|||||||
1FAFC5C02927E13C00B8D837 /* SettingsView.swift */,
|
1FAFC5C02927E13C00B8D837 /* SettingsView.swift */,
|
||||||
1F0DD83E29367F6C007608A4 /* ConnectAppleIDView.swift */,
|
1F0DD83E29367F6C007608A4 /* ConnectAppleIDView.swift */,
|
||||||
1F2EF786297C4D40002FD839 /* LicensesView.swift */,
|
1F2EF786297C4D40002FD839 /* LicensesView.swift */,
|
||||||
|
1F545E82298D79E400589F68 /* ErrorLogView.swift */,
|
||||||
);
|
);
|
||||||
path = Settings;
|
path = Settings;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -1217,6 +1225,7 @@
|
|||||||
1FB96FBD292A20E5007E68D1 /* ObservableScrollView.swift */,
|
1FB96FBD292A20E5007E68D1 /* ObservableScrollView.swift */,
|
||||||
1F6E08E529280F4B005059C0 /* RatingStars.swift */,
|
1F6E08E529280F4B005059C0 /* RatingStars.swift */,
|
||||||
1F0DD8422936B0F9007608A4 /* RoundedTextField.swift */,
|
1F0DD8422936B0F9007608A4 /* RoundedTextField.swift */,
|
||||||
|
1F545E86298D86D800589F68 /* ModalNavigationLink.swift */,
|
||||||
);
|
);
|
||||||
path = "View Components";
|
path = "View Components";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -2769,6 +2778,7 @@
|
|||||||
BFC1F38D22AEE3A4003AC21A /* DownloadAppOperation.swift in Sources */,
|
BFC1F38D22AEE3A4003AC21A /* DownloadAppOperation.swift in Sources */,
|
||||||
1F6E08DA292806E0005059C0 /* AppRowView.swift in Sources */,
|
1F6E08DA292806E0005059C0 /* AppRowView.swift in Sources */,
|
||||||
1FB96FC3292A6D7E007E68D1 /* DateFormatterHelper.swift in Sources */,
|
1FB96FC3292A6D7E007E68D1 /* DateFormatterHelper.swift in Sources */,
|
||||||
|
1F545E87298D86D800589F68 /* ModalNavigationLink.swift in Sources */,
|
||||||
1F943C6D2927F90400ABE095 /* NewsViewModel.swift in Sources */,
|
1F943C6D2927F90400ABE095 /* NewsViewModel.swift in Sources */,
|
||||||
1FB96FF3292D0539007E68D1 /* PillButtonProgressViewStyle.swift in Sources */,
|
1FB96FF3292D0539007E68D1 /* PillButtonProgressViewStyle.swift in Sources */,
|
||||||
1F6E08E829282174005059C0 /* ConfirmAddSourceView.swift in Sources */,
|
1F6E08E829282174005059C0 /* ConfirmAddSourceView.swift in Sources */,
|
||||||
@@ -2836,6 +2846,7 @@
|
|||||||
D5F2F6A92720B7C20081CCF5 /* PatchViewController.swift in Sources */,
|
D5F2F6A92720B7C20081CCF5 /* PatchViewController.swift in Sources */,
|
||||||
B39F16132918D7C5002E9404 /* Consts.swift in Sources */,
|
B39F16132918D7C5002E9404 /* Consts.swift in Sources */,
|
||||||
1F0DD8212933B749007608A4 /* AppPermissionsGrid.swift in Sources */,
|
1F0DD8212933B749007608A4 /* AppPermissionsGrid.swift in Sources */,
|
||||||
|
1F545E83298D79E400589F68 /* ErrorLogView.swift in Sources */,
|
||||||
1F0DD8452936B3FE007608A4 /* FilledButtonStyle.swift in Sources */,
|
1F0DD8452936B3FE007608A4 /* FilledButtonStyle.swift in Sources */,
|
||||||
BF8F69C222E659F700049BA1 /* AppContentViewController.swift in Sources */,
|
BF8F69C222E659F700049BA1 /* AppContentViewController.swift in Sources */,
|
||||||
BF08858522DE7EC800DE9F1E /* UpdateCollectionViewCell.swift in Sources */,
|
BF08858522DE7EC800DE9F1E /* UpdateCollectionViewCell.swift in Sources */,
|
||||||
@@ -2873,6 +2884,7 @@
|
|||||||
BFF00D342501BDCF00746320 /* IntentHandler.swift in Sources */,
|
BFF00D342501BDCF00746320 /* IntentHandler.swift in Sources */,
|
||||||
1F0DD81C2932D2FF007608A4 /* AppScreenshotsScrollView.swift in Sources */,
|
1F0DD81C2932D2FF007608A4 /* AppScreenshotsScrollView.swift in Sources */,
|
||||||
BFDBBD80246CB84F004ED2F3 /* RemoveAppBackupOperation.swift in Sources */,
|
BFDBBD80246CB84F004ED2F3 /* RemoveAppBackupOperation.swift in Sources */,
|
||||||
|
1F545E85298D84CF00589F68 /* FilePreviewView.swift in Sources */,
|
||||||
1FB96FCF292BBBCA007E68D1 /* SiriShortcutSetupView.swift in Sources */,
|
1FB96FCF292BBBCA007E68D1 /* SiriShortcutSetupView.swift in Sources */,
|
||||||
1F2EF787297C4D40002FD839 /* LicensesView.swift in Sources */,
|
1F2EF787297C4D40002FD839 /* LicensesView.swift in Sources */,
|
||||||
BFF0B6942321CB85007A79E1 /* AuthenticationViewController.swift in Sources */,
|
BFF0B6942321CB85007A79E1 /* AuthenticationViewController.swift in Sources */,
|
||||||
|
|||||||
@@ -27,6 +27,14 @@ struct DateFormatterHelper {
|
|||||||
let dateFormatter = DateFormatter()
|
let dateFormatter = DateFormatter()
|
||||||
dateFormatter.dateStyle = .medium
|
dateFormatter.dateStyle = .medium
|
||||||
dateFormatter.timeStyle = .none
|
dateFormatter.timeStyle = .none
|
||||||
|
dateFormatter.doesRelativeDateFormatting = true
|
||||||
|
return dateFormatter
|
||||||
|
}()
|
||||||
|
|
||||||
|
private static let timeFormatter: DateFormatter = {
|
||||||
|
let dateFormatter = DateFormatter()
|
||||||
|
dateFormatter.dateStyle = .none
|
||||||
|
dateFormatter.timeStyle = .short
|
||||||
return dateFormatter
|
return dateFormatter
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@@ -53,4 +61,12 @@ struct DateFormatterHelper {
|
|||||||
static func string(forRelativeDate date: Date, to referenceDate: Date = Date()) -> String {
|
static func string(forRelativeDate date: Date, to referenceDate: Date = Date()) -> String {
|
||||||
self.relativeDateFormatter.localizedString(for: date, relativeTo: referenceDate)
|
self.relativeDateFormatter.localizedString(for: date, relativeTo: referenceDate)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static func string(for date: Date) -> String {
|
||||||
|
self.mediumDateFormatter.string(from: date)
|
||||||
|
}
|
||||||
|
|
||||||
|
static func timeString(for date: Date) -> String {
|
||||||
|
self.timeFormatter.string(from: date)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
33
AltStore/View Components/ModalNavigationLink.swift
Normal file
33
AltStore/View Components/ModalNavigationLink.swift
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
//
|
||||||
|
// ModalNavigationLink.swift
|
||||||
|
// SideStore
|
||||||
|
//
|
||||||
|
// Created by Fabian Thies on 03.02.23.
|
||||||
|
// Copyright © 2023 SideStore. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct ModalNavigationLink<Label: View, Modal: View>: View {
|
||||||
|
let modal: () -> Modal
|
||||||
|
let label: () -> Label
|
||||||
|
|
||||||
|
@State var isPresentingModal: Bool = false
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
SwiftUI.Button {
|
||||||
|
self.isPresentingModal = true
|
||||||
|
} label: {
|
||||||
|
self.label()
|
||||||
|
}
|
||||||
|
.sheet(isPresented: self.$isPresentingModal) {
|
||||||
|
self.modal()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//struct ModalNavigationLink_Previews: PreviewProvider {
|
||||||
|
// static var previews: some View {
|
||||||
|
// ModalNavigationLink()
|
||||||
|
// }
|
||||||
|
//}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
//
|
||||||
|
// FilePreviewView.swift
|
||||||
|
// SideStore
|
||||||
|
//
|
||||||
|
// Created by Fabian Thies on 03.02.23.
|
||||||
|
// Copyright © 2023 SideStore. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
import UIKit
|
||||||
|
import QuickLook
|
||||||
|
|
||||||
|
struct FilePreviewView: UIViewControllerRepresentable {
|
||||||
|
let urls: [URL]
|
||||||
|
|
||||||
|
func makeCoordinator() -> Coordinator {
|
||||||
|
Coordinator(urls: self.urls)
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeUIViewController(context: Context) -> some UIViewController {
|
||||||
|
let previewController = QLPreviewController()
|
||||||
|
previewController.dataSource = context.coordinator
|
||||||
|
return UINavigationController(rootViewController: previewController)
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
|
||||||
|
context.coordinator.urls = self.urls
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension FilePreviewView {
|
||||||
|
|
||||||
|
class Coordinator: QLPreviewControllerDataSource {
|
||||||
|
var urls: [URL]
|
||||||
|
|
||||||
|
init(urls: [URL]) {
|
||||||
|
self.urls = urls
|
||||||
|
}
|
||||||
|
|
||||||
|
func numberOfPreviewItems(in controller: QLPreviewController) -> Int {
|
||||||
|
urls.count
|
||||||
|
}
|
||||||
|
|
||||||
|
func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem {
|
||||||
|
urls[index] as QLPreviewItem
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
169
AltStore/Views/Settings/ErrorLogView.swift
Normal file
169
AltStore/Views/Settings/ErrorLogView.swift
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
//
|
||||||
|
// ErrorLogView.swift
|
||||||
|
// SideStore
|
||||||
|
//
|
||||||
|
// Created by Fabian Thies on 03.02.23.
|
||||||
|
// Copyright © 2023 SideStore. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
import AltStoreCore
|
||||||
|
import ExpandableText
|
||||||
|
|
||||||
|
struct ErrorLogView: View {
|
||||||
|
@Environment(\.dismiss) var dismiss
|
||||||
|
|
||||||
|
@SwiftUI.FetchRequest(sortDescriptors: [
|
||||||
|
NSSortDescriptor(keyPath: \LoggedError.date, ascending: false)
|
||||||
|
])
|
||||||
|
var loggedErrors: FetchedResults<LoggedError>
|
||||||
|
|
||||||
|
var groupedLoggedErrors: [Date: [LoggedError]] {
|
||||||
|
Dictionary(grouping: loggedErrors, by: { Calendar.current.startOfDay(for: $0.date) })
|
||||||
|
}
|
||||||
|
|
||||||
|
@State var currentFaqUrl: URL?
|
||||||
|
@State var isShowingMinimuxerLog: Bool = false
|
||||||
|
@State var isShowingDeleteConfirmation: Bool = false
|
||||||
|
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
List {
|
||||||
|
ForEach(groupedLoggedErrors.keys.sorted(by: { $0 > $1 }), id: \.self) { date in
|
||||||
|
Section {
|
||||||
|
let errors = groupedLoggedErrors[date] ?? []
|
||||||
|
ForEach(errors, id: \.date) { error in
|
||||||
|
VStack(spacing: 8) {
|
||||||
|
HStack(alignment: .top) {
|
||||||
|
Group {
|
||||||
|
if let storeApp = error.storeApp {
|
||||||
|
AppIconView(iconUrl: storeApp.iconURL, size: 50)
|
||||||
|
} else {
|
||||||
|
ZStack {
|
||||||
|
RoundedRectangle(cornerRadius: 50*0.234, style: .continuous)
|
||||||
|
.foregroundColor(Color(UIColor.secondarySystemFill))
|
||||||
|
|
||||||
|
Image(systemSymbol: .exclamationmarkCircle)
|
||||||
|
.imageScale(.large)
|
||||||
|
.foregroundColor(.red)
|
||||||
|
}
|
||||||
|
.frame(width: 50, height: 50)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
Text(error.localizedFailure ?? "Operation Failed")
|
||||||
|
.bold()
|
||||||
|
|
||||||
|
Group {
|
||||||
|
switch error.domain {
|
||||||
|
case AltServerErrorDomain: Text("SideServer Error \(error.code)")
|
||||||
|
case OperationError.domain: Text("SideStore Error \(error.code)")
|
||||||
|
default: Text(error.error.localizedErrorCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
Text(DateFormatterHelper.timeString(for: error.date))
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
}
|
||||||
|
|
||||||
|
let nsError = error.error as NSError
|
||||||
|
let errorDescription = [nsError.localizedDescription, nsError.localizedRecoverySuggestion].compactMap { $0 }.joined(separator: "\n\n")
|
||||||
|
|
||||||
|
Menu {
|
||||||
|
SwiftUI.Button {
|
||||||
|
UIPasteboard.general.string = errorDescription
|
||||||
|
} label: {
|
||||||
|
Label("Copy Error Message", systemSymbol: .docOnDoc)
|
||||||
|
}
|
||||||
|
|
||||||
|
SwiftUI.Button {
|
||||||
|
UIPasteboard.general.string = error.error.localizedErrorCode
|
||||||
|
} label: {
|
||||||
|
Label("Copy Error Code", systemSymbol: .docOnDoc)
|
||||||
|
}
|
||||||
|
|
||||||
|
SwiftUI.Button {
|
||||||
|
self.searchFAQ(for: error)
|
||||||
|
} label: {
|
||||||
|
Label("Search FAQ", systemSymbol: .magnifyingglass)
|
||||||
|
}
|
||||||
|
|
||||||
|
} label: {
|
||||||
|
Text(errorDescription)
|
||||||
|
.multilineTextAlignment(.leading)
|
||||||
|
.foregroundColor(.primary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} header: {
|
||||||
|
Text(DateFormatterHelper.string(for: date))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.navigationBarTitle("Error Log")
|
||||||
|
.toolbar {
|
||||||
|
ToolbarItemGroup(placement: .navigationBarTrailing) {
|
||||||
|
ModalNavigationLink {
|
||||||
|
FilePreviewView(urls: [
|
||||||
|
FileManager.default.documentsDirectory.appendingPathComponent("minimuxer.log")
|
||||||
|
])
|
||||||
|
.ignoresSafeArea()
|
||||||
|
} label: {
|
||||||
|
Image(systemSymbol: .ladybug)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SwiftUI.Button {
|
||||||
|
self.isShowingDeleteConfirmation = true
|
||||||
|
} label: {
|
||||||
|
Image(systemSymbol: .trash)
|
||||||
|
}
|
||||||
|
.actionSheet(isPresented: self.$isShowingDeleteConfirmation) {
|
||||||
|
ActionSheet(
|
||||||
|
title: Text("Are you sure you want to clear the error log?"),
|
||||||
|
buttons: [
|
||||||
|
.destructive(Text("Clear Error Log"), action: self.clearLoggedErrors),
|
||||||
|
.cancel()
|
||||||
|
]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.sheet(item: self.$currentFaqUrl) { url in
|
||||||
|
SafariView(url: url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func searchFAQ(for error: LoggedError) {
|
||||||
|
let baseURL = URL(string: "https://faq.altstore.io/getting-started/troubleshooting-guide")!
|
||||||
|
var components = URLComponents(url: baseURL, resolvingAgainstBaseURL: false)!
|
||||||
|
|
||||||
|
let query = [error.domain, "\(error.code)"].joined(separator: "+")
|
||||||
|
components.queryItems = [URLQueryItem(name: "q", value: query)]
|
||||||
|
|
||||||
|
self.currentFaqUrl = components.url ?? baseURL
|
||||||
|
}
|
||||||
|
|
||||||
|
func clearLoggedErrors() {
|
||||||
|
DatabaseManager.shared.purgeLoggedErrors { result in
|
||||||
|
if case let .failure(error) = result {
|
||||||
|
NotificationManager.shared.reportError(error: error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ErrorLogView_Previews: PreviewProvider {
|
||||||
|
static var previews: some View {
|
||||||
|
NavigationView {
|
||||||
|
ErrorLogView()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -154,6 +154,12 @@ struct SettingsView: View {
|
|||||||
SwiftUI.Button(action: resetImageCache) {
|
SwiftUI.Button(action: resetImageCache) {
|
||||||
Text(L10n.SettingsView.resetImageCache)
|
Text(L10n.SettingsView.resetImageCache)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NavigationLink {
|
||||||
|
ErrorLogView()
|
||||||
|
} label: {
|
||||||
|
Text("Show Error Log")
|
||||||
|
}
|
||||||
} header: {
|
} header: {
|
||||||
Text(L10n.SettingsView.debug)
|
Text(L10n.SettingsView.debug)
|
||||||
}
|
}
|
||||||
@@ -193,7 +199,11 @@ struct SettingsView: View {
|
|||||||
|
|
||||||
|
|
||||||
func connectAppleID() {
|
func connectAppleID() {
|
||||||
AppManager.shared.authenticate(presentingViewController: nil) { (result) in
|
guard let rootViewController = UIApplication.shared.keyWindow?.rootViewController else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
AppManager.shared.authenticate(presentingViewController: rootViewController) { (result) in
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
switch result
|
switch result
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user