Page Menu
Home
Musing Studio
Search
Configure Global Search
Log In
Files
F10455404
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
24 KB
Subscribers
None
View Options
diff --git a/Shared/Navigation/ContentView.swift b/Shared/Navigation/ContentView.swift
index 1b599c0..2f79f4c 100644
--- a/Shared/Navigation/ContentView.swift
+++ b/Shared/Navigation/ContentView.swift
@@ -1,108 +1,110 @@
import SwiftUI
struct ContentView: View {
@EnvironmentObject var model: WriteFreelyModel
var body: some View {
NavigationView {
#if os(macOS)
CollectionListView()
.toolbar {
Button(
action: {
NSApp.keyWindow?.contentViewController?.tryToPerform(
#selector(NSSplitViewController.toggleSidebar(_:)), with: nil
)
},
label: { Image(systemName: "sidebar.left") }
)
.help("Toggle the sidebar's visibility.")
Spacer()
Button(action: {
withAnimation {
self.model.selectedPost = 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
}
withAnimation {
DispatchQueue.main.async {
+ self.model.showAllPosts = false
+ self.model.selectedCollection = nil
self.model.selectedPost = managedPost
}
}
}, label: { Image(systemName: "square.and.pencil") })
.help("Create a new local draft.")
}
#else
CollectionListView()
#endif
#if os(macOS)
ZStack {
- PostListView(selectedCollection: nil, showAllPosts: false) //model.account.isLoggedIn)
+ PostListView()
if model.isProcessingRequest {
ZStack {
Color(NSColor.controlBackgroundColor).opacity(0.75)
ProgressView()
}
}
}
#else
- PostListView(selectedCollection: nil, showAllPosts: model.account.isLoggedIn)
+ PostListView()
#endif
Text("Select a post, or create a new local draft.")
.foregroundColor(.secondary)
}
.environmentObject(model)
#if os(iOS)
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
})
)
})
#endif
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
let context = LocalStorageManager.persistentContainer.viewContext
let model = WriteFreelyModel()
return ContentView()
.environment(\.managedObjectContext, context)
.environmentObject(model)
}
}
diff --git a/Shared/PostCollection/CollectionListView.swift b/Shared/PostCollection/CollectionListView.swift
index 23a4aa5..a084f82 100644
--- a/Shared/PostCollection/CollectionListView.swift
+++ b/Shared/PostCollection/CollectionListView.swift
@@ -1,51 +1,78 @@
import SwiftUI
struct CollectionListView: View {
@EnvironmentObject var model: WriteFreelyModel
@FetchRequest(
entity: WFACollection.entity(),
sortDescriptors: [NSSortDescriptor(keyPath: \WFACollection.title, ascending: true)]
) var collections: FetchedResults<WFACollection>
var body: some View {
- List {
+ List(selection: $model.selectedCollection) {
if model.account.isLoggedIn {
- NavigationLink(destination: PostListView(selectedCollection: nil, showAllPosts: true)) {
+ NavigationLink(
+ destination: PostListView(),
+ isActive: Binding<Bool>(
+ get: { () -> Bool in
+ model.selectedCollection == nil && model.showAllPosts
+ }, set: { newValue in
+ if newValue {
+ self.model.selectedCollection = nil
+ self.model.showAllPosts = true
+ } else {
+ // No-op
+ }
+ }
+ )) {
Text("All Posts")
}
- NavigationLink(destination: PostListView(selectedCollection: nil, showAllPosts: false)) {
+ NavigationLink(
+ destination: PostListView(),
+ isActive: Binding<Bool>(
+ get: { () -> Bool in
+ model.selectedCollection == nil && !model.showAllPosts
+ }, set: { newValue in
+ if newValue {
+ self.model.selectedCollection = nil
+ self.model.showAllPosts = false
+ } else {
+ // No-op
+ }
+ }
+ )) {
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)
- }
+ collection.title,
+ destination: PostListView(),
+ tag: collection,
+ selection: $model.selectedCollection
+ )
}
}
} else {
NavigationLink(destination: PostListView(selectedCollection: nil, showAllPosts: false)) {
Text("Drafts")
}
}
}
.navigationTitle(
model.account.isLoggedIn ? "\(URL(string: model.account.server)?.host ?? "WriteFreely")" : "WriteFreely"
)
.listStyle(SidebarListStyle())
}
}
struct CollectionListView_LoggedOutPreviews: PreviewProvider {
static var previews: some View {
let context = LocalStorageManager.persistentContainer.viewContext
let model = WriteFreelyModel()
return CollectionListView()
.environment(\.managedObjectContext, context)
.environmentObject(model)
}
}
diff --git a/Shared/PostList/PostListFilteredView.swift b/Shared/PostList/PostListFilteredView.swift
index 3460033..29601d6 100644
--- a/Shared/PostList/PostListFilteredView.swift
+++ b/Shared/PostList/PostListFilteredView.swift
@@ -1,154 +1,140 @@
import SwiftUI
struct PostListFilteredView: View {
@EnvironmentObject var model: WriteFreelyModel
@Binding var postCount: Int
@FetchRequest(entity: WFACollection.entity(), sortDescriptors: []) var collections: FetchedResults<WFACollection>
var fetchRequest: FetchRequest<WFAPost>
- var showAllPosts: Bool {
- didSet {
- model.showAllPosts = showAllPosts
- }
- }
-
- var selectedCollection: WFACollection? {
- didSet {
- model.selectedCollection = selectedCollection
- }
- }
-
init(collection: WFACollection?, showAllPosts: Bool, postCount: Binding<Int>) {
- self.showAllPosts = showAllPosts
- self.selectedCollection = collection
if showAllPosts {
fetchRequest = FetchRequest<WFAPost>(
entity: WFAPost.entity(),
sortDescriptors: [NSSortDescriptor(key: "createdDate", ascending: false)]
)
} else {
if let collectionAlias = collection?.alias {
fetchRequest = FetchRequest<WFAPost>(
entity: WFAPost.entity(),
sortDescriptors: [NSSortDescriptor(key: "createdDate", ascending: false)],
predicate: NSPredicate(format: "collectionAlias == %@", collectionAlias)
)
} else {
fetchRequest = FetchRequest<WFAPost>(
entity: WFAPost.entity(),
sortDescriptors: [NSSortDescriptor(key: "createdDate", ascending: false)],
predicate: NSPredicate(format: "collectionAlias == nil")
)
}
}
_postCount = postCount
}
var body: some View {
#if os(iOS)
List {
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 {
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
List {
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 {
let post = fetchRequest.wrappedValue[index]
delete(post)
}
})
}
.alert(isPresented: $model.isPresentingDeleteAlert) {
Alert(
title: Text("Delete Post?"),
message: Text("This action cannot be undone."),
primaryButton: .cancel() {
model.postToDelete = nil
},
secondaryButton: .destructive(Text("Delete"), action: {
if let postToDelete = model.postToDelete {
model.selectedPost = nil
DispatchQueue.main.async {
model.editor.clearLastDraft()
model.posts.remove(postToDelete)
}
model.postToDelete = nil
}
})
)
}
.onDeleteCommand(perform: {
guard let selectedPost = model.selectedPost else { return }
if selectedPost.status == PostStatus.local.rawValue {
model.postToDelete = selectedPost
model.isPresentingDeleteAlert = true
}
})
#endif
}
func delete(_ post: WFAPost) {
DispatchQueue.main.async {
if post == model.selectedPost {
model.selectedPost = nil
model.editor.clearLastDraft()
}
model.posts.remove(post)
}
}
}
struct PostListFilteredView_Previews: PreviewProvider {
static var previews: some View {
return PostListFilteredView(collection: nil, showAllPosts: false, postCount: .constant(999))
}
}
diff --git a/Shared/PostList/PostListView.swift b/Shared/PostList/PostListView.swift
index 1d16962..271e4e8 100644
--- a/Shared/PostList/PostListView.swift
+++ b/Shared/PostList/PostListView.swift
@@ -1,173 +1,168 @@
import SwiftUI
import Combine
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)
private var frameHeight: CGFloat {
var height: CGFloat = 50
let bottom = UIApplication.shared.windows.first?.safeAreaInsets.bottom ?? 0
height += bottom
return height
}
#endif
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"
)
)
.toolbar {
ToolbarItem(placement: .primaryAction) {
// We have to add a Spacer as a sibling view to the Button in some kind of Stack, so that any
// a11y modifiers are applied as expected: bug report filed as FB8956392.
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
}
withAnimation {
- self.selectedCollection = nil
- self.showAllPosts = false
+ self.model.showAllPosts = false
+ self.model.selectedCollection = nil
self.model.selectedPost = managedPost
}
}, label: {
ZStack {
Image("does.not.exist")
.accessibilityHidden(true)
Image(systemName: "square.and.pencil")
.accessibilityHidden(true)
.imageScale(.large) // These modifiers compensate for the resizing
.padding(.vertical, 12) // done to the Image (and the button tap target)
.padding(.leading, 12) // by the SwiftUI layout system from adding a
.padding(.trailing, 8) // Spacer in this ZStack (FB8956392).
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
})
.accessibilityLabel(Text("Compose"))
.accessibilityHint(Text("Compose a new local draft"))
}
}
}
VStack {
HStack(spacing: 0) {
Button(action: {
model.isPresentingSettingsView = true
}, label: {
Image(systemName: "gear")
.padding(.vertical, 4)
.padding(.horizontal, 8)
})
.accessibilityLabel(Text("Settings"))
.accessibilityHint(Text("Open the Settings sheet"))
Spacer()
Text(postCount == 1 ? "\(postCount) post" : "\(postCount) posts")
.foregroundColor(.secondary)
Spacer()
if model.isProcessingRequest {
ProgressView()
.padding(.vertical, 4)
.padding(.horizontal, 8)
} else {
Button(action: {
DispatchQueue.main.async {
model.fetchUserCollections()
model.fetchUserPosts()
}
}, label: {
Image(systemName: "arrow.clockwise")
.padding(.vertical, 4)
.padding(.horizontal, 8)
})
.accessibilityLabel(Text("Refresh Posts"))
.accessibilityHint(Text("Fetch changes from the server"))
.disabled(!model.account.isLoggedIn)
}
}
.padding(.top, 8)
.padding(.horizontal, 8)
Spacer()
}
.frame(height: frameHeight)
.background(Color(UIColor.systemGray5))
.overlay(Divider(), alignment: .top)
}
.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("""
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
- }
- }
.navigationTitle(
- showAllPosts ? "All Posts" : selectedCollection?.title ?? (
+ model.showAllPosts ? "All Posts" : model.selectedCollection?.title ?? (
model.account.server == "https://write.as" ? "Anonymous" : "Drafts"
)
)
#endif
}
}
struct PostListView_Previews: PreviewProvider {
static var previews: some View {
let context = LocalStorageManager.persistentContainer.viewContext
let model = WriteFreelyModel()
return PostListView()
.environment(\.managedObjectContext, context)
.environmentObject(model)
}
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Fri, Jan 31, 9:45 AM (4 h, 38 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3145675
Attached To
rWFSUI WriteFreely SwiftUI
Event Timeline
Log In to Comment