Combine initial and storage view

This commit is contained in:
Christoph Hagen 2025-02-23 20:34:02 +01:00
parent cdcbe21c0d
commit cf17b513d0
5 changed files with 132 additions and 63 deletions

View File

@ -56,7 +56,7 @@
E2521DFC2D5020BE00C56662 /* PostContentGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2521DFB2D501DAE00C56662 /* PostContentGenerator.swift */; };
E2521E002D50BB6E00C56662 /* ItemLinkResults.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2521DFF2D50BB6E00C56662 /* ItemLinkResults.swift */; };
E2521E022D51776300C56662 /* StorageError.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2521E012D51776000C56662 /* StorageError.swift */; };
E2521E042D51796000C56662 /* StorageErrorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2521E032D51795B00C56662 /* StorageErrorView.swift */; };
E2521E042D51796000C56662 /* StorageStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2521E032D51795B00C56662 /* StorageStatusView.swift */; };
E2581DED2C75202400F1F079 /* Tag.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2581DEC2C75202400F1F079 /* Tag.swift */; };
E25DA5092CFD964E00AEF16D /* TagContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E25DA5082CFD964E00AEF16D /* TagContentView.swift */; };
E25DA50B2CFD988100AEF16D /* PageTagAssignmentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E25DA50A2CFD988100AEF16D /* PageTagAssignmentView.swift */; };
@ -331,7 +331,7 @@
E2521DFB2D501DAE00C56662 /* PostContentGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostContentGenerator.swift; sourceTree = "<group>"; };
E2521DFF2D50BB6E00C56662 /* ItemLinkResults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemLinkResults.swift; sourceTree = "<group>"; };
E2521E012D51776000C56662 /* StorageError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorageError.swift; sourceTree = "<group>"; };
E2521E032D51795B00C56662 /* StorageErrorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorageErrorView.swift; sourceTree = "<group>"; };
E2521E032D51795B00C56662 /* StorageStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorageStatusView.swift; sourceTree = "<group>"; };
E2581DEC2C75202400F1F079 /* Tag.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tag.swift; sourceTree = "<group>"; };
E25A0B882CE4021400F33674 /* LocalizedPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizedPage.swift; sourceTree = "<group>"; };
E25DA5082CFD964E00AEF16D /* TagContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagContentView.swift; sourceTree = "<group>"; };
@ -719,7 +719,7 @@
E29D31372D043EB80051B7F4 /* Main */ = {
isa = PBXGroup;
children = (
E2521E032D51795B00C56662 /* StorageErrorView.swift */,
E2521E032D51795B00C56662 /* StorageStatusView.swift */,
E2FD1D332D3BA2DE00B48627 /* SelectedContent.swift */,
E229904B2D10BE59009F8D77 /* InitialSetupView.swift */,
E29D31422D0488950051B7F4 /* MainContentView.swift */,
@ -1290,7 +1290,7 @@
E29D317D2D086AB00051B7F4 /* Int+Random.swift in Sources */,
E2BF1BC62D6B16FF003089F1 /* HeadlineLink.swift in Sources */,
E25DA56F2D00F9A100AEF16D /* PostFeedSettingsView.swift in Sources */,
E2521E042D51796000C56662 /* StorageErrorView.swift in Sources */,
E2521E042D51796000C56662 /* StorageStatusView.swift in Sources */,
E29D313B2D04464A0051B7F4 /* LocalizedTagDetailView.swift in Sources */,
E2FE0F552D2BCFC4002963B7 /* ContentBlock.swift in Sources */,
E2A37D212CEA94EC0000979F /* Sequence+Sorted.swift in Sources */,

View File

@ -33,7 +33,7 @@ struct MainView: App {
private var showInitialSetupSheet = false
@State
private var showStorageErrorSheet = false
private var showStorageStatusSheet = false
@State
private var showSettingsSheet = false
@ -176,7 +176,7 @@ struct MainView: App {
}
}
ToolbarItem {
Button(action: saveButtonPressed) {
Button(action: { showStorageStatusSheet = true }) {
Image(systemSymbol: content.saveState.symbol)
.foregroundStyle(content.saveState.color)
}
@ -199,8 +199,8 @@ struct MainView: App {
.environmentObject(content)
.environmentObject(selection)
}
.sheet(isPresented: $showStorageErrorSheet) {
StorageErrorView(isPresented: $showStorageErrorSheet)
.sheet(isPresented: $showStorageStatusSheet) {
StorageStatusView(isPresented: $showStorageStatusSheet)
.environmentObject(content)
}
.sheet(isPresented: $showSettingsSheet) {
@ -230,28 +230,15 @@ struct MainView: App {
}
}
private func saveButtonPressed() {
switch content.saveState {
case .storageNotInitialized:
showInitialSheet()
case .isSaved, .needsSave:
content.saveUnconditionally()
case .isSaving:
break
case .failedToSave, .savingPausedDueToLoadErrors:
showStorageErrorSheet = true
}
}
private func loadContent() {
guard content.storage.contentScope != nil else {
showInitialSheet()
showStorageStatusSheet = true
return
}
content.loadFromDisk {
prepareAfterLoad()
if !content.storageErrors.isEmpty {
self.showStorageErrorSheet = true
self.showStorageStatusSheet = true
}
}
}
@ -270,11 +257,5 @@ struct MainView: App {
selection.file = content.files.first
}
}
private func showInitialSheet() {
DispatchQueue.main.async {
showInitialSetupSheet = true
}
}
}

View File

@ -1,33 +0,0 @@
import SwiftUI
struct StorageErrorView: View {
@EnvironmentObject
private var content: Content
@Binding
var isPresented: Bool
var body: some View {
VStack {
Text("Failed to load database")
.font(.headline)
List(content.storageErrors) { error in
VStack {
Text(error.message)
Text(error.date.formatted())
.font(.footnote)
}
}
.frame(minHeight: 300)
if content.saveState == .savingPausedDueToLoadErrors {
Button("Allow saving", action: { content.resumeSavingAfterLoadingErrors() })
.padding()
Text("Saving has been disabled to prevent data corruption due to loading errors. Enable saving to save the partially loaded data.")
}
Button("Dismiss", action: { isPresented = false })
.padding()
}
.padding()
}
}

View File

@ -0,0 +1,121 @@
import SwiftUI
struct StorageStatusView: View {
@EnvironmentObject
private var content: Content
@Binding
var isPresented: Bool
var title: String {
switch content.saveState {
case .storageNotInitialized:
"No Database Loaded"
case .savingPausedDueToLoadErrors:
"Database corrupted"
case .isSaved:
"Database is healthy"
case .needsSave:
"Database will be saved soon"
case .failedToSave:
"Database errors"
case .isSaving:
"Database is being saved"
}
}
var subtitle: String {
switch content.saveState {
case .storageNotInitialized:
"To start editing the content of a website, create a new database or load an existing one. Open a folder with an existing database, or choose an empty folder to create a new project."
case .savingPausedDueToLoadErrors:
"The errors loading the database are listed below. Saving has been disabled to prevent data corruption. Enable saving to save the partially loaded data."
case .isSaved:
"All data is saved to disk"
case .needsSave:
"Wait for a few seconds until the remaining changes are saved."
case .failedToSave:
"The errors while saving the database are listed below."
case .isSaving:
"Changes are being written to disk"
}
}
var buttonText: String {
switch content.saveState {
case .storageNotInitialized:
"Choose folder"
case .savingPausedDueToLoadErrors:
"Save partial data"
case .isSaved, .isSaving, .needsSave:
"Save database"
case .failedToSave:
"Attempt save again"
}
}
var body: some View {
VStack {
Text(title)
.font(.title)
.padding()
Text(subtitle)
.multilineTextAlignment(.center)
List(content.storageErrors) { error in
VStack {
Text(error.message)
Text(error.date.formatted())
.font(.footnote)
}
}
.frame(minHeight: 300)
Button(buttonText, action: saveButtonPressed)
.padding()
.disabled(content.saveState == .isSaving)
Button("Dismiss", action: { isPresented = false })
.padding()
}
.padding()
}
func saveButtonPressed() {
switch content.saveState {
case .storageNotInitialized:
selectContentPath()
case .savingPausedDueToLoadErrors:
content.resumeSavingAfterLoadingErrors()
case .isSaved, .needsSave, .failedToSave:
content.saveUnconditionally()
case .isSaving:
break
}
}
private func selectContentPath() {
let panel = NSOpenPanel()
// Sets up so user can only select a single directory
panel.canChooseFiles = false
panel.canChooseDirectories = true
panel.allowsMultipleSelection = false
panel.showsHiddenFiles = false
panel.title = "Select the database folder"
let response = panel.runModal()
guard response == .OK else {
content.storageErrors.append(.init(message: "Failed to select a folder: \(response)"))
return
}
guard let url = panel.url else {
content.storageErrors.append(.init(message: "No url found for selected content folder"))
return
}
guard content.storage.save(contentPath: url) else {
content.storageErrors.append(.init(message: "Failed to set content path"))
return
}
content.loadFromDisk { }
}
}

View File

@ -68,7 +68,7 @@ struct PathSettingsView: View {
}
.padding()
.sheet(isPresented: $showLoadErrorSheet) {
StorageErrorView(isPresented: $showLoadErrorSheet)
StorageStatusView(isPresented: $showLoadErrorSheet)
}
}
}