diff --git a/Shared/Navigation/ContentView.swift b/Shared/Navigation/ContentView.swift index e8cd97c..09d389f 100644 --- a/Shared/Navigation/ContentView.swift +++ b/Shared/Navigation/ContentView.swift @@ -6,7 +6,7 @@ struct ContentView: View { var body: some View { NavigationView { #if os(macOS) - SidebarView() + CollectionListView() .toolbar { Button( action: { @@ -20,28 +20,18 @@ struct ContentView: View { Spacer() Button(action: { withAnimation { + // Un-set the currently selected post self.model.selectedPost = nil + + // Navigate to the Drafts list + self.model.showAllPosts = false + self.model.selectedCollection = nil } - let managedPost = WFAPost(context: LocalStorageManager.persistentContainer.viewContext) - managedPost.createdDate = Date() - managedPost.title = "" - managedPost.body = "" - managedPost.status = PostStatus.local.rawValue - managedPost.collectionAlias = nil - switch model.preferences.font { - case 1: - managedPost.appearance = "sans" - case 2: - managedPost.appearance = "wrap" - default: - managedPost.appearance = "serif" - } - if let languageCode = Locale.current.languageCode { - managedPost.language = languageCode - managedPost.rtl = Locale.characterDirection(forLanguage: languageCode) == .rightToLeft - } + // Create the new-post managed object + let managedPost = model.editor.generateNewLocalPost(withFont: model.preferences.font) withAnimation { - DispatchQueue.main.async { + DispatchQueue.main.asyncAfter(deadline: .now()) { + // Load the new post in the editor self.model.selectedPost = managedPost } } @@ -49,12 +39,12 @@ struct ContentView: View { .help("Create a new local draft.") } #else - SidebarView() + CollectionListView() #endif #if os(macOS) ZStack { - PostListView(selectedCollection: nil, showAllPosts: model.account.isLoggedIn) + PostListView() if model.isProcessingRequest { ZStack { Color(NSColor.controlBackgroundColor).opacity(0.75) @@ -63,7 +53,7 @@ struct ContentView: View { } } #else - PostListView(selectedCollection: nil, showAllPosts: model.account.isLoggedIn) + PostListView() #endif Text("Select a post, or create a new local draft.") diff --git a/Shared/Navigation/SidebarView.swift b/Shared/Navigation/SidebarView.swift deleted file mode 100644 index b4c9719..0000000 --- a/Shared/Navigation/SidebarView.swift +++ /dev/null @@ -1,18 +0,0 @@ -import SwiftUI - -struct SidebarView: View { - var body: some View { - CollectionListView() - } -} - -struct SidebarView_Previews: PreviewProvider { - static var previews: some View { - let context = LocalStorageManager.persistentContainer.viewContext - let model = WriteFreelyModel() - - return SidebarView() - .environment(\.managedObjectContext, context) - .environmentObject(model) - } -} diff --git a/Shared/PostCollection/CollectionListView.swift b/Shared/PostCollection/CollectionListView.swift index 23a4aa5..c835613 100644 --- a/Shared/PostCollection/CollectionListView.swift +++ b/Shared/PostCollection/CollectionListView.swift @@ -9,25 +9,64 @@ struct CollectionListView: View { ) var collections: FetchedResults var body: some View { - List { + List(selection: $model.selectedCollection) { if model.account.isLoggedIn { - NavigationLink(destination: PostListView(selectedCollection: nil, showAllPosts: true)) { - Text("All Posts") - } - NavigationLink(destination: PostListView(selectedCollection: nil, showAllPosts: false)) { - Text(model.account.server == "https://write.as" ? "Anonymous" : "Drafts") - } - Section(header: Text("Your Blogs")) { - ForEach(collections, id: \.alias) { collection in - NavigationLink( - destination: PostListView(selectedCollection: collection, showAllPosts: false) - ) { - Text(collection.title) + NavigationLink( + destination: PostListView(), + isActive: Binding( + get: { () -> Bool in + model.selectedCollection == nil && model.showAllPosts + }, set: { newValue in + if newValue { + self.model.showAllPosts = true + self.model.selectedCollection = nil + } else { + // No-op + } } + ), + label: { + Text("All Posts") + }) + NavigationLink( + destination: PostListView(), + isActive: Binding( + get: { () -> Bool in + model.selectedCollection == nil && !model.showAllPosts + }, set: { newValue in + if newValue { + self.model.showAllPosts = false + self.model.selectedCollection = nil + } else { + // No-op + } + } + ), + label: { + Text(model.account.server == "https://write.as" ? "Anonymous" : "Drafts") + }) + Section(header: Text("Your Blogs")) { + ForEach(collections, id: \.self) { collection in + NavigationLink( + destination: PostListView(), + isActive: Binding( + get: { () -> Bool in + model.selectedCollection == collection && !model.showAllPosts + }, set: { newValue in + if newValue { + self.model.showAllPosts = false + self.model.selectedCollection = collection + } else { + // No-op + } + } + ), + label: { Text(collection.title) } + ) } } } else { - NavigationLink(destination: PostListView(selectedCollection: nil, showAllPosts: false)) { + NavigationLink(destination: PostListView()) { Text("Drafts") } } @@ -36,6 +75,16 @@ struct CollectionListView: View { model.account.isLoggedIn ? "\(URL(string: model.account.server)?.host ?? "WriteFreely")" : "WriteFreely" ) .listStyle(SidebarListStyle()) + .onChange(of: model.selectedCollection) { collection in + if collection != model.editor.fetchSelectedCollectionFromAppStorage() { + self.model.editor.selectedCollectionURL = collection?.objectID.uriRepresentation() + } + } + .onChange(of: model.showAllPosts) { value in + if value != model.editor.showAllPostsFlag { + self.model.editor.showAllPostsFlag = model.showAllPosts + } + } } } diff --git a/Shared/PostEditor/PostEditorModel.swift b/Shared/PostEditor/PostEditorModel.swift index 7580271..014681f 100644 --- a/Shared/PostEditor/PostEditorModel.swift +++ b/Shared/PostEditor/PostEditorModel.swift @@ -8,7 +8,9 @@ enum PostAppearance: String { } struct PostEditorModel { - @AppStorage("lastDraftURL") private var lastDraftURL: URL? + @AppStorage("showAllPostsFlag") var showAllPostsFlag: Bool = false + @AppStorage("selectedCollectionURL") var selectedCollectionURL: URL? + @AppStorage("lastDraftURL") var lastDraftURL: URL? func saveLastDraft(_ post: WFAPost) { self.lastDraftURL = post.status != PostStatus.published.rawValue ? post.objectID.uriRepresentation() : nil @@ -18,15 +20,44 @@ struct PostEditorModel { self.lastDraftURL = nil } - func fetchLastDraftFromUserDefaults() -> WFAPost? { + func fetchLastDraftFromAppStorage() -> WFAPost? { guard let postURL = lastDraftURL else { return nil } - - let coordinator = LocalStorageManager.persistentContainer.persistentStoreCoordinator - guard let postManagedObjectID = coordinator.managedObjectID(forURIRepresentation: postURL) else { return nil } - guard let post = LocalStorageManager.persistentContainer.viewContext.object( - with: postManagedObjectID - ) as? WFAPost else { return nil } - + guard let post = fetchManagedObject(from: postURL) as? WFAPost else { return nil } return post } + + func generateNewLocalPost(withFont appearance: Int) -> WFAPost { + let managedPost = WFAPost(context: LocalStorageManager.persistentContainer.viewContext) + managedPost.createdDate = Date() + managedPost.title = "" + managedPost.body = "" + managedPost.status = PostStatus.local.rawValue + managedPost.collectionAlias = nil + switch appearance { + case 1: + managedPost.appearance = "sans" + case 2: + managedPost.appearance = "wrap" + default: + managedPost.appearance = "serif" + } + if let languageCode = Locale.current.languageCode { + managedPost.language = languageCode + managedPost.rtl = Locale.characterDirection(forLanguage: languageCode) == .rightToLeft + } + return managedPost + } + + func fetchSelectedCollectionFromAppStorage() -> WFACollection? { + guard let collectionURL = selectedCollectionURL else { return nil } + guard let collection = fetchManagedObject(from: collectionURL) as? WFACollection else { return nil } + return collection + } + + private func fetchManagedObject(from objectURL: URL) -> NSManagedObject? { + let coordinator = LocalStorageManager.persistentContainer.persistentStoreCoordinator + guard let managedObjectID = coordinator.managedObjectID(forURIRepresentation: objectURL) else { return nil } + let object = LocalStorageManager.persistentContainer.viewContext.object(with: managedObjectID) + return object + } } diff --git a/Shared/PostList/PostListFilteredView.swift b/Shared/PostList/PostListFilteredView.swift index 3460033..7826be9 100644 --- a/Shared/PostList/PostListFilteredView.swift +++ b/Shared/PostList/PostListFilteredView.swift @@ -6,21 +6,7 @@ struct PostListFilteredView: View { @FetchRequest(entity: WFACollection.entity(), sortDescriptors: []) var collections: FetchedResults var fetchRequest: FetchRequest - var showAllPosts: Bool { - didSet { - model.showAllPosts = showAllPosts - } - } - - var selectedCollection: WFACollection? { - didSet { - model.selectedCollection = selectedCollection - } - } - init(collection: WFACollection?, showAllPosts: Bool, postCount: Binding) { - self.showAllPosts = showAllPosts - self.selectedCollection = collection if showAllPosts { fetchRequest = FetchRequest( entity: WFAPost.entity(), @@ -46,25 +32,25 @@ struct PostListFilteredView: View { var body: some View { #if os(iOS) - List { + List(selection: $model.selectedPost) { ForEach(fetchRequest.wrappedValue, id: \.self) { post in NavigationLink( destination: PostEditorView(post: post), tag: post, - selection: $model.selectedPost - ) { - if showAllPosts { - if let collection = collections.filter { $0.alias == post.collectionAlias }.first { - PostCellView(post: post, collectionName: collection.title) + selection: $model.selectedPost, + label: { + if model.showAllPosts { + if let collection = collections.filter { $0.alias == post.collectionAlias }.first { + PostCellView(post: post, collectionName: collection.title) + } else { + let collectionName = model.account.server == "https://write.as" ? "Anonymous" : "Drafts" + PostCellView(post: post, collectionName: collectionName) + } } else { - let collectionName = model.account.server == "https://write.as" ? "Anonymous" : "Drafts" - PostCellView(post: post, collectionName: collectionName) + PostCellView(post: post) } - } else { - PostCellView(post: post) - } - } - .deleteDisabled(post.status != PostStatus.local.rawValue) + }) + .deleteDisabled(post.status != PostStatus.local.rawValue) } .onDelete(perform: { indexSet in for index in indexSet { @@ -80,25 +66,25 @@ struct PostListFilteredView: View { self.postCount = value }) #else - List { + List(selection: $model.selectedPost) { ForEach(fetchRequest.wrappedValue, id: \.self) { post in NavigationLink( destination: PostEditorView(post: post), tag: post, - selection: $model.selectedPost - ) { - if showAllPosts { - if let collection = collections.filter { $0.alias == post.collectionAlias }.first { - PostCellView(post: post, collectionName: collection.title) + selection: $model.selectedPost, + label: { + if model.showAllPosts { + if let collection = collections.filter { $0.alias == post.collectionAlias }.first { + PostCellView(post: post, collectionName: collection.title) + } else { + let collectionName = model.account.server == "https://write.as" ? "Anonymous" : "Drafts" + PostCellView(post: post, collectionName: collectionName) + } } else { - let collectionName = model.account.server == "https://write.as" ? "Anonymous" : "Drafts" - PostCellView(post: post, collectionName: collectionName) + PostCellView(post: post) } - } else { - PostCellView(post: post) - } - } - .deleteDisabled(post.status != PostStatus.local.rawValue) + }) + .deleteDisabled(post.status != PostStatus.local.rawValue) } .onDelete(perform: { indexSet in for index in indexSet { diff --git a/Shared/PostList/PostListView.swift b/Shared/PostList/PostListView.swift index 1d16962..5f0bdc6 100644 --- a/Shared/PostList/PostListView.swift +++ b/Shared/PostList/PostListView.swift @@ -5,8 +5,6 @@ struct PostListView: View { @EnvironmentObject var model: WriteFreelyModel @Environment(\.managedObjectContext) var managedObjectContext - @State var selectedCollection: WFACollection? - @State var showAllPosts: Bool = false @State private var postCount: Int = 0 #if os(iOS) @@ -21,9 +19,13 @@ struct PostListView: View { var body: some View { #if os(iOS) ZStack(alignment: .bottom) { - PostListFilteredView(collection: selectedCollection, showAllPosts: showAllPosts, postCount: $postCount) + PostListFilteredView( + collection: model.selectedCollection, + showAllPosts: model.showAllPosts, + postCount: $postCount + ) .navigationTitle( - showAllPosts ? "All Posts" : selectedCollection?.title ?? ( + model.showAllPosts ? "All Posts" : model.selectedCollection?.title ?? ( model.account.server == "https://write.as" ? "Anonymous" : "Drafts" ) ) @@ -34,28 +36,10 @@ struct PostListView: View { ZStack { Spacer() Button(action: { - let managedPost = WFAPost(context: self.managedObjectContext) - managedPost.createdDate = Date() - managedPost.title = "" - managedPost.body = "" - managedPost.status = PostStatus.local.rawValue - managedPost.collectionAlias = nil - switch model.preferences.font { - case 1: - managedPost.appearance = "sans" - case 2: - managedPost.appearance = "wrap" - default: - managedPost.appearance = "serif" - } - if let languageCode = Locale.current.languageCode { - managedPost.language = languageCode - //swiftlint:disable:next line_length - managedPost.rtl = Locale.characterDirection(forLanguage: languageCode) == .rightToLeft - } + let managedPost = model.editor.generateNewLocalPost(withFont: model.preferences.font) withAnimation { - self.selectedCollection = nil - self.showAllPosts = false + self.model.showAllPosts = false + self.model.selectedCollection = nil self.model.selectedPost = managedPost } }, label: { @@ -122,38 +106,29 @@ struct PostListView: View { .ignoresSafeArea() #else //if os(macOS) PostListFilteredView( - collection: selectedCollection, - showAllPosts: showAllPosts, + collection: model.selectedCollection, + showAllPosts: model.showAllPosts, postCount: $postCount ) .toolbar { ToolbarItemGroup(placement: .primaryAction) { - if let selectedPost = model.selectedPost { - ActivePostToolbarView(activePost: selectedPost) - .alert(isPresented: $model.isPresentingNetworkErrorAlert, content: { - Alert( - title: Text("Connection Error"), - message: Text(""" + ActivePostToolbarView() + .alert(isPresented: $model.isPresentingNetworkErrorAlert, content: { + Alert( + title: Text("Connection Error"), + message: Text(""" There is no internet connection at the moment. \ Please reconnect or try again later. """), - dismissButton: .default(Text("OK"), action: { - model.isPresentingNetworkErrorAlert = false - }) - ) - }) - } - } - } - .onDisappear { - DispatchQueue.main.async { - self.model.selectedCollection = nil - self.model.showAllPosts = true - self.model.selectedPost = nil + dismissButton: .default(Text("OK"), action: { + model.isPresentingNetworkErrorAlert = false + }) + ) + }) } } .navigationTitle( - showAllPosts ? "All Posts" : selectedCollection?.title ?? ( + model.showAllPosts ? "All Posts" : model.selectedCollection?.title ?? ( model.account.server == "https://write.as" ? "Anonymous" : "Drafts" ) ) diff --git a/Shared/WriteFreely_MultiPlatformApp.swift b/Shared/WriteFreely_MultiPlatformApp.swift index 61a634a..c05344a 100644 --- a/Shared/WriteFreely_MultiPlatformApp.swift +++ b/Shared/WriteFreely_MultiPlatformApp.swift @@ -9,11 +9,12 @@ struct CheckForDebugModifier { static func main() { #if os(macOS) if NSEvent.modifierFlags.contains(.shift) { - print("Debug launch detected") - // Run debug-mode launch code here + // Clear the launch-to-last-draft values to load a new draft. + UserDefaults.standard.setValue(false, forKey: "showAllPostsFlag") + UserDefaults.standard.setValue(nil, forKey: "selectedCollectionURL") + UserDefaults.standard.setValue(nil, forKey: "lastDraftURL") } else { - print("Normal launch detected") - // Don't do anything + // No-op } #endif WriteFreely_MultiPlatformApp.main() @@ -33,10 +34,23 @@ struct WriteFreely_MultiPlatformApp: App { WindowGroup { ContentView() .onAppear(perform: { - if let lastDraft = model.editor.fetchLastDraftFromUserDefaults() { - self.model.selectedPost = lastDraft + if model.editor.showAllPostsFlag { + DispatchQueue.main.async { + self.model.selectedCollection = nil + self.model.showAllPosts = true + } } else { - createNewLocalPost() + DispatchQueue.main.async { + self.model.selectedCollection = model.editor.fetchSelectedCollectionFromAppStorage() + self.model.showAllPosts = false + } + } + DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { + if model.editor.lastDraftURL != nil { + self.model.selectedPost = model.editor.fetchLastDraftFromAppStorage() + } else { + createNewLocalPost() + } } }) .environmentObject(model) @@ -114,28 +128,20 @@ struct WriteFreely_MultiPlatformApp: App { private func createNewLocalPost() { withAnimation { + // Un-set the currently selected post self.model.selectedPost = nil + + // Navigate to the Drafts list + self.model.showAllPosts = false + self.model.selectedCollection = nil } - let managedPost = WFAPost(context: LocalStorageManager.persistentContainer.viewContext) - managedPost.createdDate = Date() - managedPost.title = "" - managedPost.body = "" - managedPost.status = PostStatus.local.rawValue - managedPost.collectionAlias = nil - switch model.preferences.font { - case 1: - managedPost.appearance = "sans" - case 2: - managedPost.appearance = "wrap" - default: - managedPost.appearance = "serif" - } - if let languageCode = Locale.current.languageCode { - managedPost.language = languageCode - managedPost.rtl = Locale.characterDirection(forLanguage: languageCode) == .rightToLeft - } + // Create the new-post managed object + let managedPost = model.editor.generateNewLocalPost(withFont: model.preferences.font) withAnimation { - self.model.selectedPost = managedPost + // Set it as the selectedPost + DispatchQueue.main.asyncAfter(deadline: .now()) { + self.model.selectedPost = managedPost + } } } } diff --git a/WriteFreely-MultiPlatform.xcodeproj/project.pbxproj b/WriteFreely-MultiPlatform.xcodeproj/project.pbxproj index 624441c..9ae74b3 100644 --- a/WriteFreely-MultiPlatform.xcodeproj/project.pbxproj +++ b/WriteFreely-MultiPlatform.xcodeproj/project.pbxproj @@ -48,8 +48,6 @@ 1756DC0224FEE18400207AB8 /* WFACollection+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1756DBFF24FEE18400207AB8 /* WFACollection+CoreDataClass.swift */; }; 1756DC0324FEE18400207AB8 /* WFACollection+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1756DC0024FEE18400207AB8 /* WFACollection+CoreDataProperties.swift */; }; 1756DC0424FEE18400207AB8 /* WFACollection+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1756DC0024FEE18400207AB8 /* WFACollection+CoreDataProperties.swift */; }; - 1765F62A24E18EA200C9EBF0 /* SidebarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1765F62924E18EA200C9EBF0 /* SidebarView.swift */; }; - 1765F62B24E18EA200C9EBF0 /* SidebarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1765F62924E18EA200C9EBF0 /* SidebarView.swift */; }; 17681E412519410E00D394AE /* UINavigationController+Appearance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17681E402519410E00D394AE /* UINavigationController+Appearance.swift */; }; 1780F6EF25895EDB00FE45FF /* PostCommands.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1780F6EE25895EDB00FE45FF /* PostCommands.swift */; }; 17A4FEDA25924AF70037E96B /* Sparkle in Frameworks */ = {isa = PBXBuildFile; productRef = 17A4FED925924AF70037E96B /* Sparkle */; }; @@ -146,7 +144,6 @@ 1756DBB924FED45500207AB8 /* LocalStorageManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalStorageManager.swift; sourceTree = ""; }; 1756DBFF24FEE18400207AB8 /* WFACollection+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WFACollection+CoreDataClass.swift"; sourceTree = SOURCE_ROOT; }; 1756DC0024FEE18400207AB8 /* WFACollection+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WFACollection+CoreDataProperties.swift"; sourceTree = SOURCE_ROOT; }; - 1765F62924E18EA200C9EBF0 /* SidebarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarView.swift; sourceTree = ""; }; 17681E402519410E00D394AE /* UINavigationController+Appearance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UINavigationController+Appearance.swift"; sourceTree = ""; }; 1780F6EE25895EDB00FE45FF /* PostCommands.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostCommands.swift; sourceTree = ""; }; 17A4FEDF25924E810037E96B /* MacSoftwareUpdater.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = MacSoftwareUpdater.md; sourceTree = ""; }; @@ -457,7 +454,6 @@ isa = PBXGroup; children = ( 17DF328224C87D3300BCE2E3 /* ContentView.swift */, - 1765F62924E18EA200C9EBF0 /* SidebarView.swift */, ); path = Navigation; sourceTree = ""; @@ -745,7 +741,6 @@ 1756AE7724CB2EDD00FD7257 /* PostEditorView.swift in Sources */, 17DF32D524C8CA3400BCE2E3 /* PostStatusBadgeView.swift in Sources */, 17D435E824E3128F0036B539 /* PreferencesModel.swift in Sources */, - 1765F62A24E18EA200C9EBF0 /* SidebarView.swift in Sources */, 1756AE7A24CB65DF00FD7257 /* PostListView.swift in Sources */, 17B996D82502D23E0017B536 /* WFAPost+CoreDataClass.swift in Sources */, 1756DC0124FEE18400207AB8 /* WFACollection+CoreDataClass.swift in Sources */, @@ -769,7 +764,6 @@ buildActionMask = 2147483647; files = ( 17DF32AD24C87D3500BCE2E3 /* ContentView.swift in Sources */, - 1765F62B24E18EA200C9EBF0 /* SidebarView.swift in Sources */, 1756DBBB24FED45500207AB8 /* LocalStorageManager.swift in Sources */, 17A4FEED25927E730037E96B /* AppDelegate.swift in Sources */, 174D313324EC2831006CA9EE /* WriteFreelyModel.swift in Sources */, diff --git a/WriteFreely-MultiPlatform.xcodeproj/xcuserdata/angelo.xcuserdatad/xcschemes/xcschememanagement.plist b/WriteFreely-MultiPlatform.xcodeproj/xcuserdata/angelo.xcuserdatad/xcschemes/xcschememanagement.plist index 2723ebe..6cd8075 100644 --- a/WriteFreely-MultiPlatform.xcodeproj/xcuserdata/angelo.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/WriteFreely-MultiPlatform.xcodeproj/xcuserdata/angelo.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ WriteFreely-MultiPlatform (iOS).xcscheme_^#shared#^_ orderHint - 0 + 1 WriteFreely-MultiPlatform (macOS).xcscheme_^#shared#^_ orderHint - 1 + 0 diff --git a/macOS/Navigation/ActivePostToolbarView.swift b/macOS/Navigation/ActivePostToolbarView.swift index 20334f4..bd18ff9 100644 --- a/macOS/Navigation/ActivePostToolbarView.swift +++ b/macOS/Navigation/ActivePostToolbarView.swift @@ -2,9 +2,7 @@ import SwiftUI struct ActivePostToolbarView: View { @EnvironmentObject var model: WriteFreelyModel - @ObservedObject var activePost: WFAPost @State private var isPresentingSharingServicePicker: Bool = false - @State private var selectedCollection: WFACollection? @FetchRequest( @@ -13,102 +11,106 @@ struct ActivePostToolbarView: View { ) var collections: FetchedResults var body: some View { - HStack { - if model.account.isLoggedIn && - activePost.status != PostStatus.local.rawValue && - !(activePost.wasDeletedFromServer || activePost.hasNewerRemoteCopy) { - Section(header: Text("Move To:")) { - Picker(selection: $selectedCollection, label: Text("Move To…"), content: { - Text("\(model.account.server == "https://write.as" ? "Anonymous" : "Drafts")") - .tag(nil as WFACollection?) - Divider() - ForEach(collections) { collection in - Text("\(collection.title)").tag(collection as WFACollection?) - } - }) - } - } - PostEditorStatusToolbarView(post: activePost) - .frame(minWidth: 50, alignment: .center) - .layoutPriority(1) - .padding(.horizontal) - if activePost.status == PostStatus.local.rawValue { - Menu(content: { - Label("Publish To:", systemImage: "paperplane") - Divider() - Button(action: { - if model.account.isLoggedIn { - withAnimation { - activePost.collectionAlias = nil - publishPost(activePost) + if let activePost = model.selectedPost { + HStack { + if model.account.isLoggedIn && + activePost.status != PostStatus.local.rawValue && + !(activePost.wasDeletedFromServer || activePost.hasNewerRemoteCopy) { + Section(header: Text("Move To:")) { + Picker(selection: $selectedCollection, label: Text("Move To…"), content: { + Text("\(model.account.server == "https://write.as" ? "Anonymous" : "Drafts")") + .tag(nil as WFACollection?) + Divider() + ForEach(collections) { collection in + Text("\(collection.title)").tag(collection as WFACollection?) } - } else { - openSettingsWindow() - } - }, label: { - Text("\(model.account.server == "https://write.as" ? "Anonymous" : "Drafts")") - }) - ForEach(collections) { collection in + }) + } + } + PostEditorStatusToolbarView(post: activePost) + .frame(minWidth: 50, alignment: .center) + .layoutPriority(1) + .padding(.horizontal) + if activePost.status == PostStatus.local.rawValue { + Menu(content: { + Label("Publish To:", systemImage: "paperplane") + Divider() Button(action: { if model.account.isLoggedIn { withAnimation { - activePost.collectionAlias = collection.alias + activePost.collectionAlias = nil publishPost(activePost) } } else { openSettingsWindow() } }, label: { - Text("\(collection.title)") + Text("\(model.account.server == "https://write.as" ? "Anonymous" : "Drafts")") }) - } - }, label: { - Label("Publish…", systemImage: "paperplane") - }) - .disabled(activePost.body.isEmpty) - .help("Publish the post to the web.\(model.account.isLoggedIn ? "" : " You must be logged in to do this.")") // swiftlint:disable:this line_length - } else { - HStack(spacing: 4) { - Button( - action: { - self.isPresentingSharingServicePicker = true - }, - label: { Image(systemName: "square.and.arrow.up") } - ) - .disabled(activePost.status == PostStatus.local.rawValue) - .help("Copy the post's URL to your Mac's pasteboard.") - .popover(isPresented: $isPresentingSharingServicePicker) { - PostEditorSharingPicker( - isPresented: $isPresentingSharingServicePicker, - sharingItems: createPostUrl() + ForEach(collections) { collection in + Button(action: { + if model.account.isLoggedIn { + withAnimation { + activePost.collectionAlias = collection.alias + publishPost(activePost) + } + } else { + openSettingsWindow() + } + }, label: { + Text("\(collection.title)") + }) + } + }, label: { + Label("Publish…", systemImage: "paperplane") + }) + .disabled(activePost.body.isEmpty) + .help("Publish the post to the web.\(model.account.isLoggedIn ? "" : " You must be logged in to do this.")") // swiftlint:disable:this line_length + } else { + HStack(spacing: 4) { + Button( + action: { + self.isPresentingSharingServicePicker = true + }, + label: { Image(systemName: "square.and.arrow.up") } ) - .frame(width: .zero, height: .zero) + .disabled(activePost.status == PostStatus.local.rawValue) + .help("Copy the post's URL to your Mac's pasteboard.") + .popover(isPresented: $isPresentingSharingServicePicker) { + PostEditorSharingPicker( + isPresented: $isPresentingSharingServicePicker, + sharingItems: createPostUrl() + ) + .frame(width: .zero, height: .zero) + } + Button(action: { publishPost(activePost) }, label: { Image(systemName: "paperplane") }) + .disabled(activePost.body.isEmpty || activePost.status == PostStatus.published.rawValue) + .help("Publish the post to the web.\(model.account.isLoggedIn ? "" : " You must be logged in to do this.")") // swiftlint:disable:this line_length } - Button(action: { publishPost(activePost) }, label: { Image(systemName: "paperplane") }) - .disabled(activePost.body.isEmpty || activePost.status == PostStatus.published.rawValue) - .help("Publish the post to the web.\(model.account.isLoggedIn ? "" : " You must be logged in to do this.")") // swiftlint:disable:this line_length } } + .onAppear(perform: { + self.selectedCollection = collections.first { $0.alias == activePost.collectionAlias } + }) + .onChange(of: selectedCollection, perform: { [selectedCollection] newCollection in + if activePost.collectionAlias == newCollection?.alias { + return + } else { + withAnimation { + activePost.collectionAlias = newCollection?.alias + model.move(post: activePost, from: selectedCollection, to: newCollection) + } + } + }) + } else { + EmptyView() } - .onAppear(perform: { - self.selectedCollection = collections.first { $0.alias == activePost.collectionAlias } - }) - .onChange(of: selectedCollection, perform: { [selectedCollection] newCollection in - if activePost.collectionAlias == newCollection?.alias { - return - } else { - withAnimation { - activePost.collectionAlias = newCollection?.alias - model.move(post: activePost, from: selectedCollection, to: newCollection) - } - } - }) } private func createPostUrl() -> [Any] { - guard let postId = activePost.postId else { return [] } - guard let urlString = activePost.slug != nil ? - "\(model.account.server)/\((activePost.collectionAlias)!)/\((activePost.slug)!)" : + guard let postId = model.selectedPost?.postId else { return [] } + guard let urlString = model.selectedPost?.slug != nil ? + "\(model.account.server)/\((model.selectedPost?.collectionAlias)!)/\((model.selectedPost?.slug)!)" : "\(model.account.server)/\((postId))" else { return [] } guard let data = URL(string: urlString) else { return [] } return [data as NSURL]