import SwiftUI import SFSafeSymbols #warning("Fix podcast") #warning("Fix CV") #warning("Fix endeavor basics (image compare)") #warning("Fix cap mosaic GIF") #warning("Add custom url string to external files (optional)") #warning("Show all warnings on page content") #warning("Button to delete file, show in finder, replace, mark changed (-> images)") #warning("Transfer images of posts to other language") #warning("Show tag selection view for pages") #warning("Button to replace files") #warning("Replace links to files inside pages when id changes") #warning("Calculate file sizes") #warning("Specify image aspect ratio to prevent page jumps") #warning("Add version and source url properties to file resources") #warning("Show errors during loading of content") #warning("Generate pages for posts") #warning("Clean up mock content") #warning("Show posts linking to a page") #warning("Add author to settings and page headers") #warning("Check for files in output folder not generated by app") #warning("Fix GIFs: Don't rescale, don't use image set") @main struct MainView: App { private let sidebarWidth: CGFloat = 250 private let detailWidth: CGFloat = 300 @StateObject private var content: Content = .init() @State private var language: ContentLanguage = .english @State private var selectedTab: MainViewTab = .posts @State private var selectedPost: Post? @State private var selectedPage: Page? @State private var selectedTag: Tag? @State private var selectedImage: ImageResource? @State private var selectedFile: FileResource? @State private var selectedSection: SettingsSection = .folders @State private var showAddSheet = false @State private var showInitialSetupSheet = false @ViewBuilder var sidebar: some View { switch selectedTab { case .posts: PostListView(selectedPost: $selectedPost) case .pages: PageListView(selectedPage: $selectedPage) case .tags: TagListView(selectedTag: $selectedTag) case .files: FileListView(selectedFile: $selectedFile) case .generation: SettingsListView(selectedSection: $selectedSection) } } @ViewBuilder var viewContent: some View { switch selectedTab { case .posts: SelectedContentView(selected: $selectedPost) case .pages: SelectedContentView(selected: $selectedPage) case .tags: SelectedContentView(selected: $selectedTag) case .files: SelectedContentView(selected: $selectedFile) case .generation: GenerationContentView(selected: $selectedSection) } } @ViewBuilder var detail: some View { switch selectedTab { case .posts: SelectedDetailView(selected: $selectedPost) case .pages: SelectedDetailView(selected: $selectedPage) case .tags: SelectedDetailView(selected: $selectedTag) case .files: SelectedDetailView(selected: $selectedFile) case .generation: GenerationDetailView(section: selectedSection) } } @ViewBuilder var addItemSheet: some View { switch selectedTab { case .posts: AddPostView(selected: $selectedPost) case .pages: AddPageView(selected: $selectedPage) case .tags: AddTagView(selected: $selectedTag) case .files: AddFileView(selectedImage: $selectedImage, selectedFile: $selectedFile) case .generation: Text("Not implemented") } } var body: some Scene { WindowGroup { NavigationSplitView { sidebar .toolbar { ToolbarItem(placement: .navigation) { Picker("", selection: $selectedTab) { Text("Posts").tag(MainViewTab.posts) Text("Pages").tag(MainViewTab.pages) Text("Tags").tag(MainViewTab.tags) Text("Files").tag(MainViewTab.files) Text("Generation").tag(MainViewTab.generation) }.pickerStyle(.segmented) } } .navigationSplitViewColumnWidth(min: sidebarWidth, ideal: sidebarWidth, max: sidebarWidth) .toolbar { ToolbarItem(placement: .primaryAction) { Button(action: { showAddSheet = true }) { Label("Add", systemSymbol: .plus) } .disabled(!selectedTab.canAddItems) } } } content: { viewContent } detail: { detail .navigationSplitViewColumnWidth(min: detailWidth, ideal: detailWidth, max: detailWidth) } .toolbar { ToolbarItem(placement: .primaryAction) { Picker("", selection: $language) { Text("English") .tag(ContentLanguage.english) Text("German") .tag(ContentLanguage.german) }.pickerStyle(.segmented) } ToolbarItem(placement: .primaryAction) { if content.storage.contentScope != nil { Button(action: save) { Text("Save") } } else { Button(action: showInitialSheet) { Text("Setup") } .background(RoundedRectangle(cornerRadius: 8).fill(Color.red)) } } } .navigationTitle("") .environment(\.language, language) .environmentObject(content) .onAppear(perform: loadContent) .onReceive(Timer.publish(every: 60.0, on: .main, in: .common).autoconnect()) { _ in save() } .sheet(isPresented: $showAddSheet) { addItemSheet .environment(\.language, language) .environmentObject(content) } .sheet(isPresented: $showInitialSetupSheet) { InitialSetupView() .environment(\.language, language) .environmentObject(content) } } } private func save() { do { try content.saveToDisk() } catch { print("Failed to save content: \(error.localizedDescription)") } } private func loadContent() { guard content.storage.contentScope != nil else { showInitialSheet() return } do { try content.loadFromDisk() } catch { print("Failed to load content: \(error.localizedDescription)") } } private func showInitialSheet() { DispatchQueue.main.async { selectedSection = .folders selectedTab = .generation showInitialSetupSheet = true } } }