Ver a proveniência

Add a "search posts" feature to the post list (#245)

pull/253/head
Angelo Stavrow há 11 meses
committed by GitHub
ascendente
cometimento
6bb8be4d46
Não foi encontrada uma chave conhecida para esta assinatura, na base de dados ID da chave GPG: 4AEE18F83AFDEB23
5 ficheiros alterados com 131 adições e 55 eliminações
  1. +1
    -0
      CHANGELOG.md
  2. +52
    -54
      Shared/PostList/PostListFilteredView.swift
  3. +58
    -0
      Shared/PostList/SearchablePostListFilteredView.swift
  4. +10
    -1
      WriteFreely-MultiPlatform.xcodeproj/project.pbxproj
  5. +10
    -0
      macOS/Navigation/PostCommands.swift

+ 1
- 0
CHANGELOG.md Ver ficheiro

@@ -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



+ 52
- 54
Shared/PostList/PostListFilteredView.swift Ver ficheiro

@@ -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)
} 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)
}
if #available(iOS 15, *) {
SearchablePostListFilteredView(
postCount: $postCount,
collections: collections,
fetchRequest: fetchRequest,
onDelete: delete(_:)
)
.environmentObject(model)
.onAppear(perform: {
self.postCount = fetchRequest.wrappedValue.count
})
}
.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)
.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
})
}
#else
SearchablePostListFilteredView(
postCount: $postCount,
collections: collections,
fetchRequest: fetchRequest,
onDelete: delete(_:)
)
.environmentObject(model)
.alert(isPresented: $model.isPresentingDeleteAlert) {
Alert(
title: Text("Delete Post?"),


+ 58
- 0
Shared/PostList/SearchablePostListFilteredView.swift Ver ficheiro

@@ -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)
}
}

+ 10
- 1
WriteFreely-MultiPlatform.xcodeproj/project.pbxproj Ver ficheiro

@@ -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" */ = {


+ 10
- 0
macOS/Navigation/PostCommands.swift Ver ficheiro

@@ -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)


Carregando…
Cancelar
Guardar