From 3c1e04e3bfdcf1594fbc57bd3cdb5bd975dfa349 Mon Sep 17 00:00:00 2001 From: Angelo Stavrow Date: Fri, 24 Sep 2021 14:45:28 -0400 Subject: [PATCH] Use view model for CollectionListView --- Shared/Navigation/ContentView.swift | 56 +-------------- .../PostCollection/CollectionListModel.swift | 40 +++++++++++ .../PostCollection/CollectionListView.swift | 69 +++---------------- Shared/PostList/PostListFilteredView.swift | 2 +- Shared/PostList/PostListView.swift | 36 ++++++++-- Shared/WriteFreely_MultiPlatformApp.swift | 36 +++++----- .../project.pbxproj | 6 ++ 7 files changed, 107 insertions(+), 138 deletions(-) create mode 100644 Shared/PostCollection/CollectionListModel.swift diff --git a/Shared/Navigation/ContentView.swift b/Shared/Navigation/ContentView.swift index 82fc222..86fbbeb 100644 --- a/Shared/Navigation/ContentView.swift +++ b/Shared/Navigation/ContentView.swift @@ -35,22 +35,7 @@ struct ContentView: View { .help("Create a new local draft.") } #else - if #available(iOS 15.0, *) { - CollectionListView() - .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 - }) - ) - }) - } else { - CollectionListView() - } + CollectionListView(selectedCollection: model.selectedCollection) #endif #if os(macOS) @@ -64,50 +49,13 @@ struct ContentView: View { } } #else - if #available(iOS 15.0, *) { - PostListView() - .sheet( - isPresented: $model.isPresentingSettingsView, - onDismiss: { model.isPresentingSettingsView = false }, - content: { - SettingsView() - .environmentObject(model) - } - ) - } else { - PostListView() - } + PostListView(selectedCollection: nil, showAllPosts: false) #endif Text("Select a post, or create a new local draft.") .foregroundColor(.secondary) } .environmentObject(model) - // For iOS 14 - if #available(iOS 15.0, *) { - // Do nothing. - } else { - EmptyView() - .sheet( - isPresented: $model.isPresentingSettingsView, - onDismiss: { model.isPresentingSettingsView = false }, - content: { - SettingsView() - .environmentObject(model) - } - ) - .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 - }) - ) - }) - } } } diff --git a/Shared/PostCollection/CollectionListModel.swift b/Shared/PostCollection/CollectionListModel.swift new file mode 100644 index 0000000..5e107bb --- /dev/null +++ b/Shared/PostCollection/CollectionListModel.swift @@ -0,0 +1,40 @@ +import SwiftUI +import CoreData + +class CollectionListModel: NSObject, ObservableObject { + @Published var list: [WFACollection] = [] + private let collectionsController: NSFetchedResultsController + + init(managedObjectContext: NSManagedObjectContext) { + collectionsController = NSFetchedResultsController(fetchRequest: WFACollection.collectionsFetchRequest, + managedObjectContext: managedObjectContext, + sectionNameKeyPath: nil, + cacheName: nil) + + super.init() + + collectionsController.delegate = self + + do { + try collectionsController.performFetch() + list = collectionsController.fetchedObjects ?? [] + } catch { + print("Failed to fetch collections!") + } + } +} + +extension CollectionListModel: NSFetchedResultsControllerDelegate { + func controllerDidChangeContent(_ controller: NSFetchedResultsController) { + guard let collections = controller.fetchedObjects as? [WFACollection] else { return } + self.list = collections + } +} + +extension WFACollection { + static var collectionsFetchRequest: NSFetchRequest { + let request: NSFetchRequest = WFACollection.createFetchRequest() + request.sortDescriptors = [NSSortDescriptor(keyPath: \WFACollection.title, ascending: true)] + return request + } +} diff --git a/Shared/PostCollection/CollectionListView.swift b/Shared/PostCollection/CollectionListView.swift index c835613..4a4583d 100644 --- a/Shared/PostCollection/CollectionListView.swift +++ b/Shared/PostCollection/CollectionListView.swift @@ -2,71 +2,24 @@ import SwiftUI struct CollectionListView: View { @EnvironmentObject var model: WriteFreelyModel - - @FetchRequest( - entity: WFACollection.entity(), - sortDescriptors: [NSSortDescriptor(keyPath: \WFACollection.title, ascending: true)] - ) var collections: FetchedResults + @ObservedObject var collections = CollectionListModel(managedObjectContext: LocalStorageManager.persistentContainer.viewContext) + @State var selectedCollection: WFACollection? var body: some View { - List(selection: $model.selectedCollection) { + List(selection: $selectedCollection) { if model.account.isLoggedIn { - 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") - }) + NavigationLink("All Posts", destination: PostListView(selectedCollection: nil, showAllPosts: true)) + NavigationLink("Drafts", destination: PostListView(selectedCollection: nil, showAllPosts: false)) 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) } - ) + ForEach(collections.list, id: \.self) { collection in + NavigationLink(destination: PostListView(selectedCollection: collection, showAllPosts: false), + tag: collection, + selection: $selectedCollection, + label: { Text("\(collection.title)") }) } } } else { - NavigationLink(destination: PostListView()) { + NavigationLink(destination: PostListView(selectedCollection: nil, showAllPosts: false)) { Text("Drafts") } } diff --git a/Shared/PostList/PostListFilteredView.swift b/Shared/PostList/PostListFilteredView.swift index 7826be9..1af7fe1 100644 --- a/Shared/PostList/PostListFilteredView.swift +++ b/Shared/PostList/PostListFilteredView.swift @@ -97,7 +97,7 @@ struct PostListFilteredView: View { Alert( title: Text("Delete Post?"), message: Text("This action cannot be undone."), - primaryButton: .cancel() { + primaryButton: .cancel { model.postToDelete = nil }, secondaryButton: .destructive(Text("Delete"), action: { diff --git a/Shared/PostList/PostListView.swift b/Shared/PostList/PostListView.swift index c7e184a..1220014 100644 --- a/Shared/PostList/PostListView.swift +++ b/Shared/PostList/PostListView.swift @@ -7,6 +7,9 @@ struct PostListView: View { @State private var postCount: Int = 0 + var selectedCollection: WFACollection? + var showAllPosts: Bool + #if os(iOS) private var frameHeight: CGFloat { var height: CGFloat = 50 @@ -20,12 +23,12 @@ struct PostListView: View { #if os(iOS) ZStack(alignment: .bottom) { PostListFilteredView( - collection: model.selectedCollection, - showAllPosts: model.showAllPosts, + collection: selectedCollection, + showAllPosts: showAllPosts, postCount: $postCount ) .navigationTitle( - model.showAllPosts ? "All Posts" : model.selectedCollection?.title ?? ( + showAllPosts ? "All Posts" : selectedCollection?.title ?? ( model.account.server == "https://write.as" ? "Anonymous" : "Drafts" ) ) @@ -70,9 +73,28 @@ struct PostListView: View { }) .accessibilityLabel(Text("Settings")) .accessibilityHint(Text("Open the Settings sheet")) + .sheet( + isPresented: $model.isPresentingSettingsView, + onDismiss: { model.isPresentingSettingsView = false }, + content: { + SettingsView() + .environmentObject(model) + } + ) Spacer() Text(postCount == 1 ? "\(postCount) post" : "\(postCount) posts") .foregroundColor(.secondary) + .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 + }) + ) + }) Spacer() if model.isProcessingRequest { ProgressView() @@ -105,8 +127,8 @@ struct PostListView: View { .ignoresSafeArea() #else PostListFilteredView( - collection: model.selectedCollection, - showAllPosts: model.showAllPosts, + collection: selectedCollection, + showAllPosts: showAllPosts, postCount: $postCount ) .toolbar { @@ -129,7 +151,7 @@ struct PostListView: View { } } .navigationTitle( - model.showAllPosts ? "All Posts" : model.selectedCollection?.title ?? ( + showAllPosts ? "All Posts" : selectedCollection?.title ?? ( model.account.server == "https://write.as" ? "Anonymous" : "Drafts" ) ) @@ -142,7 +164,7 @@ struct PostListView_Previews: PreviewProvider { let context = LocalStorageManager.persistentContainer.viewContext let model = WriteFreelyModel() - return PostListView() + return PostListView(showAllPosts: true) .environment(\.managedObjectContext, context) .environmentObject(model) } diff --git a/Shared/WriteFreely_MultiPlatformApp.swift b/Shared/WriteFreely_MultiPlatformApp.swift index 900a267..79f7320 100644 --- a/Shared/WriteFreely_MultiPlatformApp.swift +++ b/Shared/WriteFreely_MultiPlatformApp.swift @@ -34,24 +34,24 @@ struct WriteFreely_MultiPlatformApp: App { WindowGroup { ContentView() .onAppear(perform: { - if model.editor.showAllPostsFlag { - DispatchQueue.main.async { - self.model.selectedCollection = nil - self.model.showAllPosts = true - } - } else { - 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() - } - } +// if model.editor.showAllPostsFlag { +// DispatchQueue.main.async { +// self.model.selectedCollection = nil +// self.model.showAllPosts = true +// } +// } else { +// 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) .environment(\.managedObjectContext, LocalStorageManager.persistentContainer.viewContext) diff --git a/WriteFreely-MultiPlatform.xcodeproj/project.pbxproj b/WriteFreely-MultiPlatform.xcodeproj/project.pbxproj index 01b4ccc..525f5ee 100644 --- a/WriteFreely-MultiPlatform.xcodeproj/project.pbxproj +++ b/WriteFreely-MultiPlatform.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + 170A7EC126F5186A00F1CBD4 /* CollectionListModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 170A7EC026F5186A00F1CBD4 /* CollectionListModel.swift */; }; + 170A7EC226F5186A00F1CBD4 /* CollectionListModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 170A7EC026F5186A00F1CBD4 /* CollectionListModel.swift */; }; 170DFA34251BBC44001D82A0 /* PostEditorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 170DFA33251BBC44001D82A0 /* PostEditorModel.swift */; }; 170DFA35251BBC44001D82A0 /* PostEditorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 170DFA33251BBC44001D82A0 /* PostEditorModel.swift */; }; 17120DA124E19839002B9F6C /* AccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17A5388D24DDEC7400DEFF9A /* AccountView.swift */; }; @@ -126,6 +128,7 @@ /* Begin PBXFileReference section */ 1709ADDF251B9A110053AF79 /* EditorLaunchingPolicy.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = EditorLaunchingPolicy.md; sourceTree = ""; }; + 170A7EC026F5186A00F1CBD4 /* CollectionListModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionListModel.swift; sourceTree = ""; }; 170DFA33251BBC44001D82A0 /* PostEditorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostEditorModel.swift; sourceTree = ""; }; 17120DA424E19CBF002B9F6C /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; 17120DA824E1B2F5002B9F6C /* AccountLogoutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountLogoutView.swift; sourceTree = ""; }; @@ -496,6 +499,7 @@ 17DF32D224C8B78D00BCE2E3 /* PostCollection */ = { isa = PBXGroup; children = ( + 170A7EC026F5186A00F1CBD4 /* CollectionListModel.swift */, 171BFDF924D4AF8300888236 /* CollectionListView.swift */, ); path = PostCollection; @@ -755,6 +759,7 @@ 17B996DA2502D23E0017B536 /* WFAPost+CoreDataProperties.swift in Sources */, 1756AE7724CB2EDD00FD7257 /* PostEditorView.swift in Sources */, 17DF32D524C8CA3400BCE2E3 /* PostStatusBadgeView.swift in Sources */, + 170A7EC126F5186A00F1CBD4 /* CollectionListModel.swift in Sources */, 17D435E824E3128F0036B539 /* PreferencesModel.swift in Sources */, 1756AE7A24CB65DF00FD7257 /* PostListView.swift in Sources */, 17B996D82502D23E0017B536 /* WFAPost+CoreDataClass.swift in Sources */, @@ -791,6 +796,7 @@ 17C42E662509237800072984 /* PostListFilteredView.swift in Sources */, 17120DAD24E1B99F002B9F6C /* AccountLoginView.swift in Sources */, 17466626256C0D0600629997 /* MacEditorTextView.swift in Sources */, + 170A7EC226F5186A00F1CBD4 /* CollectionListModel.swift in Sources */, 17E5DF8A2543610700DCDC9B /* PostTextEditingView.swift in Sources */, 17C42E71250AAFD500072984 /* NSManagedObjectContext+ExecuteAndMergeChanges.swift in Sources */, 1756AE7B24CB65DF00FD7257 /* PostListView.swift in Sources */,