mirror of
https://github.com/writeas/writefreely-swiftui-multiplatform.git
synced 2024-11-15 01:11:02 +00:00
Add a "search posts" feature to the post list (#245)
This commit is contained in:
parent
579db0c889
commit
6bb8be4d46
@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- [Mac] In a post with unpublished changes (i.e., with "local" or "edited" status), the post is autosaved after a one-second pause in typing.
|
||||
- [Mac] Added a context-menu item to delete local posts from the post list.
|
||||
- [Mac] Added methods to fetch device logs.
|
||||
- [iOS, Mac] Added a way to search for text across all posts.
|
||||
|
||||
### Changed
|
||||
|
||||
|
@ -4,6 +4,7 @@ struct PostListFilteredView: View {
|
||||
@EnvironmentObject var model: WriteFreelyModel
|
||||
@Binding var postCount: Int
|
||||
@FetchRequest(entity: WFACollection.entity(), sortDescriptors: []) var collections: FetchedResults<WFACollection>
|
||||
|
||||
var fetchRequest: FetchRequest<WFAPost>
|
||||
|
||||
init(collection: WFACollection?, showAllPosts: Bool, postCount: Binding<Int>) {
|
||||
@ -32,67 +33,64 @@ struct PostListFilteredView: View {
|
||||
|
||||
var body: some View {
|
||||
#if os(iOS)
|
||||
List(selection: $model.selectedPost) {
|
||||
ForEach(fetchRequest.wrappedValue, id: \.self) { post in
|
||||
NavigationLink(
|
||||
destination: PostEditorView(post: post),
|
||||
tag: post,
|
||||
selection: $model.selectedPost,
|
||||
label: {
|
||||
if model.showAllPosts {
|
||||
if let collection = collections.filter { $0.alias == post.collectionAlias }.first {
|
||||
PostCellView(post: post, collectionName: collection.title)
|
||||
if #available(iOS 15, *) {
|
||||
SearchablePostListFilteredView(
|
||||
postCount: $postCount,
|
||||
collections: collections,
|
||||
fetchRequest: fetchRequest,
|
||||
onDelete: delete(_:)
|
||||
)
|
||||
.environmentObject(model)
|
||||
.onAppear(perform: {
|
||||
self.postCount = fetchRequest.wrappedValue.count
|
||||
})
|
||||
.onChange(of: fetchRequest.wrappedValue.count, perform: { value in
|
||||
self.postCount = value
|
||||
})
|
||||
} else {
|
||||
List(selection: $model.selectedPost) {
|
||||
ForEach(fetchRequest.wrappedValue, id: \.self) { post in
|
||||
NavigationLink(
|
||||
destination: PostEditorView(post: post),
|
||||
tag: post,
|
||||
selection: $model.selectedPost,
|
||||
label: {
|
||||
if model.showAllPosts {
|
||||
if let collection = collections.filter({ $0.alias == post.collectionAlias }).first {
|
||||
PostCellView(post: post, collectionName: collection.title)
|
||||
} else {
|
||||
// swiftlint:disable:next line_length
|
||||
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)
|
||||
}
|
||||
.onDelete(perform: { indexSet in
|
||||
for index in indexSet {
|
||||
let post = fetchRequest.wrappedValue[index]
|
||||
delete(post)
|
||||
}
|
||||
.onDelete(perform: { indexSet in
|
||||
for index in indexSet {
|
||||
let post = fetchRequest.wrappedValue[index]
|
||||
delete(post)
|
||||
}
|
||||
})
|
||||
}
|
||||
.onAppear(perform: {
|
||||
self.postCount = fetchRequest.wrappedValue.count
|
||||
})
|
||||
.onChange(of: fetchRequest.wrappedValue.count, perform: { value in
|
||||
self.postCount = value
|
||||
})
|
||||
}
|
||||
.onAppear(perform: {
|
||||
self.postCount = fetchRequest.wrappedValue.count
|
||||
})
|
||||
.onChange(of: fetchRequest.wrappedValue.count, perform: { value in
|
||||
self.postCount = value
|
||||
})
|
||||
#else
|
||||
List(selection: $model.selectedPost) {
|
||||
ForEach(fetchRequest.wrappedValue, id: \.self) { post in
|
||||
NavigationLink(
|
||||
destination: PostEditorView(post: post),
|
||||
tag: post,
|
||||
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 {
|
||||
PostCellView(post: post)
|
||||
}
|
||||
})
|
||||
.deleteDisabled(post.status != PostStatus.local.rawValue)
|
||||
}
|
||||
.onDelete(perform: { indexSet in
|
||||
for index in indexSet {
|
||||
let post = fetchRequest.wrappedValue[index]
|
||||
delete(post)
|
||||
}
|
||||
})
|
||||
}
|
||||
SearchablePostListFilteredView(
|
||||
postCount: $postCount,
|
||||
collections: collections,
|
||||
fetchRequest: fetchRequest,
|
||||
onDelete: delete(_:)
|
||||
)
|
||||
.environmentObject(model)
|
||||
.alert(isPresented: $model.isPresentingDeleteAlert) {
|
||||
Alert(
|
||||
title: Text("Delete Post?"),
|
||||
|
58
Shared/PostList/SearchablePostListFilteredView.swift
Normal file
58
Shared/PostList/SearchablePostListFilteredView.swift
Normal file
@ -0,0 +1,58 @@
|
||||
import SwiftUI
|
||||
|
||||
@available(iOS 15, macOS 12.0, *)
|
||||
struct SearchablePostListFilteredView: View {
|
||||
@EnvironmentObject var model: WriteFreelyModel
|
||||
@Binding var postCount: Int
|
||||
@State private var searchString = ""
|
||||
|
||||
var collections: FetchedResults<WFACollection>
|
||||
var fetchRequest: FetchRequest<WFAPost>
|
||||
var onDelete: (WFAPost) -> Void
|
||||
|
||||
var body: some View {
|
||||
List(selection: $model.selectedPost) {
|
||||
ForEach(fetchRequest.wrappedValue, id: \.self) { post in
|
||||
if !searchString.isEmpty &&
|
||||
!post.title.localizedCaseInsensitiveContains(searchString) &&
|
||||
!post.body.localizedCaseInsensitiveContains(searchString) {
|
||||
EmptyView()
|
||||
} else {
|
||||
NavigationLink(
|
||||
destination: PostEditorView(post: post),
|
||||
tag: post,
|
||||
selection: $model.selectedPost,
|
||||
label: {
|
||||
if model.showAllPosts {
|
||||
if let collection = collections.filter({ $0.alias == post.collectionAlias }).first {
|
||||
PostCellView(post: post, collectionName: collection.title)
|
||||
} else {
|
||||
// swiftlint:disable:next line_length
|
||||
let collectionName = model.account.server == "https://write.as" ? "Anonymous" : "Drafts"
|
||||
PostCellView(post: post, collectionName: collectionName)
|
||||
}
|
||||
} else {
|
||||
PostCellView(post: post)
|
||||
}
|
||||
})
|
||||
.deleteDisabled(post.status != PostStatus.local.rawValue)
|
||||
}
|
||||
}
|
||||
.onDelete(perform: { indexSet in
|
||||
for index in indexSet {
|
||||
let post = fetchRequest.wrappedValue[index]
|
||||
delete(post)
|
||||
}
|
||||
})
|
||||
}
|
||||
#if os(iOS)
|
||||
.searchable(text: $searchString, prompt: "Search across posts")
|
||||
#else
|
||||
.searchable(text: $searchString, placement: .toolbar, prompt: "Search across posts")
|
||||
#endif
|
||||
}
|
||||
|
||||
func delete(_ post: WFAPost) {
|
||||
onDelete(post)
|
||||
}
|
||||
}
|
@ -137,7 +137,11 @@
|
||||
17DFDE8C251D309400A25F31 /* OpenSans-License.txt in Resources */ = {isa = PBXBuildFile; fileRef = 17DFDE86251D309400A25F31 /* OpenSans-License.txt */; };
|
||||
17E5DF8A2543610700DCDC9B /* PostTextEditingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17E5DF892543610700DCDC9B /* PostTextEditingView.swift */; };
|
||||
375A67E828FC555C007A1AC0 /* MultilineTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 375A67E728FC555C007A1AC0 /* MultilineTextView.swift */; };
|
||||
37F749D129B4D3090087F0BF /* SearchablePostListFilteredView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37F749D029B4D3090087F0BF /* SearchablePostListFilteredView.swift */; };
|
||||
37F749D229B4D3090087F0BF /* SearchablePostListFilteredView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37F749D029B4D3090087F0BF /* SearchablePostListFilteredView.swift */; };
|
||||
3779389729EC0C880032D6C1 /* HelpCommands.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3779389629EC0C880032D6C1 /* HelpCommands.swift */; };
|
||||
37F749D129B4D3090087F0BF /* SearchablePostListFilteredView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37F749D029B4D3090087F0BF /* SearchablePostListFilteredView.swift */; };
|
||||
37F749D229B4D3090087F0BF /* SearchablePostListFilteredView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37F749D029B4D3090087F0BF /* SearchablePostListFilteredView.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@ -269,7 +273,9 @@
|
||||
17DFDE86251D309400A25F31 /* OpenSans-License.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "OpenSans-License.txt"; sourceTree = "<group>"; };
|
||||
17E5DF892543610700DCDC9B /* PostTextEditingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostTextEditingView.swift; sourceTree = "<group>"; };
|
||||
375A67E728FC555C007A1AC0 /* MultilineTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultilineTextView.swift; sourceTree = "<group>"; };
|
||||
37F749D029B4D3090087F0BF /* SearchablePostListFilteredView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchablePostListFilteredView.swift; sourceTree = "<group>"; };
|
||||
3779389629EC0C880032D6C1 /* HelpCommands.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HelpCommands.swift; sourceTree = "<group>"; };
|
||||
37F749D029B4D3090087F0BF /* SearchablePostListFilteredView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchablePostListFilteredView.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@ -606,6 +612,7 @@
|
||||
1756AE7924CB65DF00FD7257 /* PostListView.swift */,
|
||||
17DF32D424C8CA3400BCE2E3 /* PostStatusBadgeView.swift */,
|
||||
17C42E642509237800072984 /* PostListFilteredView.swift */,
|
||||
37F749D029B4D3090087F0BF /* SearchablePostListFilteredView.swift */,
|
||||
);
|
||||
path = PostList;
|
||||
sourceTree = "<group>";
|
||||
@ -937,6 +944,7 @@
|
||||
17B996DA2502D23E0017B536 /* WFAPost+CoreDataProperties.swift in Sources */,
|
||||
1756AE7724CB2EDD00FD7257 /* PostEditorView.swift in Sources */,
|
||||
17DF32D524C8CA3400BCE2E3 /* PostStatusBadgeView.swift in Sources */,
|
||||
37F749D129B4D3090087F0BF /* SearchablePostListFilteredView.swift in Sources */,
|
||||
17D435E824E3128F0036B539 /* PreferencesModel.swift in Sources */,
|
||||
1756AE7A24CB65DF00FD7257 /* PostListView.swift in Sources */,
|
||||
17B996D82502D23E0017B536 /* WFAPost+CoreDataClass.swift in Sources */,
|
||||
@ -981,6 +989,7 @@
|
||||
17027E26286741B90062EB29 /* Logging.swift in Sources */,
|
||||
1727526B2809991A003D0A6A /* ErrorHandling.swift in Sources */,
|
||||
17E5DF8A2543610700DCDC9B /* PostTextEditingView.swift in Sources */,
|
||||
37F749D229B4D3090087F0BF /* SearchablePostListFilteredView.swift in Sources */,
|
||||
17C42E71250AAFD500072984 /* NSManagedObjectContext+ExecuteAndMergeChanges.swift in Sources */,
|
||||
1756AE7B24CB65DF00FD7257 /* PostListView.swift in Sources */,
|
||||
1753F6AC24E431CC00309365 /* MacPreferencesView.swift in Sources */,
|
||||
@ -1483,7 +1492,7 @@
|
||||
repositoryURL = "https://github.com/writefreely/writefreely-swift";
|
||||
requirement = {
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 0.3.6;
|
||||
minimumVersion = 0.3.7;
|
||||
};
|
||||
};
|
||||
17D4926327947B4D0035BD7E /* XCRemoteSwiftPackageReference "Sparkle" */ = {
|
||||
|
@ -5,6 +5,16 @@ struct PostCommands: Commands {
|
||||
|
||||
var body: some Commands {
|
||||
CommandMenu("Post") {
|
||||
Button("Find In Posts") {
|
||||
if let toolbar = NSApp.keyWindow?.toolbar,
|
||||
let search = toolbar.items.first(where: {
|
||||
$0.itemIdentifier.rawValue == "com.apple.SwiftUI.search"
|
||||
}) as? NSSearchToolbarItem {
|
||||
search.beginSearchInteraction()
|
||||
}
|
||||
}
|
||||
.keyboardShortcut("f", modifiers: [.command, .shift])
|
||||
|
||||
Group {
|
||||
Button(action: sendPostUrlToPasteboard, label: { Text("Copy Link To Published Post") })
|
||||
.disabled(model.selectedPost?.status == PostStatus.local.rawValue)
|
||||
|
Loading…
Reference in New Issue
Block a user