diff --git a/Shared/WriteFreely_MultiPlatformApp.swift b/Shared/WriteFreely_MultiPlatformApp.swift index bb6974a..b121314 100644 --- a/Shared/WriteFreely_MultiPlatformApp.swift +++ b/Shared/WriteFreely_MultiPlatformApp.swift @@ -1,220 +1,212 @@ import SwiftUI #if os(macOS) import Sparkle #endif @main struct CheckForDebugModifier { static func main() { #if os(macOS) if NSEvent.modifierFlags.contains(.shift) { // Clear the launch-to-last-draft values to load a new draft. UserDefaults.shared.setValue(false, forKey: WFDefaults.showAllPostsFlag) UserDefaults.shared.setValue(nil, forKey: WFDefaults.selectedCollectionURL) UserDefaults.shared.setValue(nil, forKey: WFDefaults.lastDraftURL) } else { // No-op } #endif WriteFreely_MultiPlatformApp.main() } } struct WriteFreely_MultiPlatformApp: App { @StateObject private var model = WriteFreelyModel.shared private let logger = Logging(for: String(describing: WriteFreely_MultiPlatformApp.self)) #if os(macOS) @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate @StateObject var updaterViewModel = MacUpdatesViewModel() @State private var selectedTab = 0 #endif @State private var didCrash = UserDefaults.shared.bool(forKey: WFDefaults.didHaveFatalError) var body: some Scene { WindowGroup { ContentView() .onAppear(perform: { if model.editor.showAllPostsFlag { DispatchQueue.main.async { self.model.selectedCollection = nil self.model.showAllPosts = true showLastDraftOrCreateNewLocalPost() } } else { DispatchQueue.main.async { self.model.selectedCollection = model.editor.fetchSelectedCollectionFromAppStorage() self.model.showAllPosts = false showLastDraftOrCreateNewLocalPost() } } }) .alert(isPresented: $didCrash) { var helpMsg = "Alert the humans by sharing what happened on the help forum." if let errorMsg = UserDefaults.shared.object(forKey: WFDefaults.fatalErrorDescription) as? String { helpMsg.append("\n\n\(errorMsg)") } return Alert( title: Text("Crash Detected"), message: Text(helpMsg), primaryButton: .default( Text("Let us know"), action: didPressCrashAlertButton ), secondaryButton: .cancel( Text("Dismiss"), action: resetCrashFlags ) ) } .onAppear { if #available(iOS 15, *) { if didCrash { generateCrashLogPost() } } } .withErrorHandling() .environmentObject(model) .environment(\.managedObjectContext, LocalStorageManager.standard.container.viewContext) // .preferredColorScheme(preferences.selectedColorScheme) // See PreferencesModel for info. } .commands { #if os(macOS) CommandGroup(after: .appInfo) { CheckForUpdatesView(updaterViewModel: updaterViewModel) } #endif CommandGroup(replacing: .newItem, addition: { Button("New Post") { createNewLocalPost() } .keyboardShortcut("n", modifiers: [.command]) }) CommandGroup(after: .newItem) { Button("Refresh Posts") { DispatchQueue.main.async { model.fetchUserCollections() model.fetchUserPosts() } } .disabled(!model.account.isLoggedIn) .keyboardShortcut("r", modifiers: [.command]) } SidebarCommands() #if os(macOS) PostCommands(model: model) + HelpCommands(model: model) #endif - CommandGroup(after: .help) { - Button("Visit Support Forum") { - #if os(macOS) - NSWorkspace().open(model.helpURL) - #else - UIApplication.shared.open(model.helpURL) - #endif - } - } ToolbarCommands() TextEditingCommands() } #if os(macOS) Settings { TabView(selection: $selectedTab) { MacAccountView() .environmentObject(model) .tabItem { Image(systemName: "person.crop.circle") Text("Account") } .tag(0) MacPreferencesView(preferences: model.preferences) .tabItem { Image(systemName: "gear") Text("Preferences") } .tag(1) MacUpdatesView(updaterViewModel: updaterViewModel) .tabItem { Image(systemName: "arrow.down.circle") Text("Updates") } .tag(2) } .environmentObject(model) .withErrorHandling() .frame(minWidth: 500, maxWidth: 500, minHeight: 200) .padding() // .preferredColorScheme(preferences.selectedColorScheme) // See PreferencesModel for info. } #endif } private func showLastDraftOrCreateNewLocalPost() { if model.editor.lastDraftURL != nil { DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) { self.model.selectedPost = model.editor.fetchLastDraftFromAppStorage() } } else { createNewLocalPost() } } private func createNewLocalPost() { withAnimation { // Un-set the currently selected post self.model.selectedPost = nil } // Create the new-post managed object let managedPost = model.editor.generateNewLocalPost(withFont: model.preferences.font) withAnimation { // Set it as the selectedPost DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) { self.model.selectedPost = managedPost } } } @available(iOS 15, *) private func generateCrashLogPost() { logger.log("Generating local log post...") DispatchQueue.main.asyncAfter(deadline: .now()) { // Unset selected post and collection and navigate to local drafts. self.model.selectedPost = nil self.model.selectedCollection = nil self.model.showAllPosts = false // Create the new log post. let newLogPost = model.editor.generateNewLocalPost(withFont: 2) newLogPost.title = "Logs For Support" var postBody: [String] = [ "WriteFreely-Multiplatform v\(Bundle.main.appMarketingVersion) (\(Bundle.main.appBuildVersion))", "Generated \(Date())", "" ] postBody.append(contentsOf: logger.fetchLogs()) newLogPost.body = postBody.joined(separator: "\n") self.model.selectedPost = newLogPost } logger.log("Generated local log post.") } private func resetCrashFlags() { UserDefaults.shared.set(false, forKey: WFDefaults.didHaveFatalError) UserDefaults.shared.removeObject(forKey: WFDefaults.fatalErrorDescription) } private func didPressCrashAlertButton() { resetCrashFlags() #if os(macOS) NSWorkspace().open(model.helpURL) #else UIApplication.shared.open(model.helpURL) #endif } } diff --git a/macOS/Navigation/HelpCommands.swift b/macOS/Navigation/HelpCommands.swift index 2aef271..135e081 100644 --- a/macOS/Navigation/HelpCommands.swift +++ b/macOS/Navigation/HelpCommands.swift @@ -1,8 +1,40 @@ -// -// HelpCommands.swift -// WriteFreely-MultiPlatform (macOS) -// -// Created by Angelo Stavrow on 2023-04-16. -// - -import Foundation +import SwiftUI + +struct HelpCommands: Commands { + @ObservedObject var model: WriteFreelyModel + + private let logger = Logging(for: String(describing: PostCommands.self)) + + var body: some Commands { + CommandGroup(replacing: .help) { + Button("Visit Support Forum") { + NSWorkspace().open(model.helpURL) + } + Button(action: createLogsPost, label: { Text("Generate Log for Support") }) + } + } + + private func createLogsPost() { + logger.log("Generating local log post...") + + DispatchQueue.main.asyncAfter(deadline: .now()) { + // Unset selected post and collection and navigate to local drafts. + self.model.selectedPost = nil + self.model.selectedCollection = nil + self.model.showAllPosts = false + + // Create the new log post. + let newLogPost = model.editor.generateNewLocalPost(withFont: 2) + newLogPost.title = "Logs For Support" + var postBody: [String] = [ + "WriteFreely-Multiplatform v\(Bundle.main.appMarketingVersion) (\(Bundle.main.appBuildVersion))", + "Generated \(Date())", + "" + ] + postBody.append(contentsOf: logger.fetchLogs()) + newLogPost.body = postBody.joined(separator: "\n") + } + + logger.log("Generated local log post.") + } +} diff --git a/macOS/Navigation/PostCommands.swift b/macOS/Navigation/PostCommands.swift index b8d5f11..2b2d45a 100644 --- a/macOS/Navigation/PostCommands.swift +++ b/macOS/Navigation/PostCommands.swift @@ -1,53 +1,25 @@ import SwiftUI struct PostCommands: Commands { @ObservedObject var model: WriteFreelyModel - private let logger = Logging(for: String(describing: PostCommands.self)) - var body: some Commands { CommandMenu("Post") { Group { Button(action: sendPostUrlToPasteboard, label: { Text("Copy Link To Published Post") }) .disabled(model.selectedPost?.status == PostStatus.local.rawValue) } .disabled(model.selectedPost == nil || !model.account.isLoggedIn) - - Button(action: createLogsPost, label: { Text("Create Log Post") }) } } private func sendPostUrlToPasteboard() { guard let activePost = model.selectedPost else { return } guard let postId = activePost.postId else { return } guard let urlString = activePost.slug != nil ? "\(model.account.server)/\((activePost.collectionAlias)!)/\((activePost.slug)!)" : "\(model.account.server)/\((postId))" else { return } NSPasteboard.general.clearContents() NSPasteboard.general.setString(urlString, forType: .string) } - - private func createLogsPost() { - logger.log("Generating local log post...") - - DispatchQueue.main.asyncAfter(deadline: .now()) { - // Unset selected post and collection and navigate to local drafts. - self.model.selectedPost = nil - self.model.selectedCollection = nil - self.model.showAllPosts = false - - // Create the new log post. - let newLogPost = model.editor.generateNewLocalPost(withFont: 2) - newLogPost.title = "Logs For Support" - var postBody: [String] = [ - "WriteFreely-Multiplatform v\(Bundle.main.appMarketingVersion) (\(Bundle.main.appBuildVersion))", - "Generated \(Date())", - "" - ] - postBody.append(contentsOf: logger.fetchLogs()) - newLogPost.body = postBody.joined(separator: "\n") - } - - logger.log("Generated local log post.") - } }