mirror of
https://github.com/writeas/writefreely-swiftui-multiplatform.git
synced 2024-11-15 01:11:02 +00:00
Merge pull request #144 from writeas/overhaul-toolbar-on-mac
Overhaul toolbar on Mac app
This commit is contained in:
commit
b987ab703f
@ -1,4 +1,4 @@
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
import WriteFreely
|
||||
|
||||
enum AccountError: Error {
|
||||
@ -30,8 +30,8 @@ extension AccountError: LocalizedError {
|
||||
}
|
||||
|
||||
struct AccountModel {
|
||||
@AppStorage("isLoggedIn") var isLoggedIn: Bool = false
|
||||
private let defaults = UserDefaults.standard
|
||||
let isLoggedInFlag = "isLoggedInFlag"
|
||||
let usernameStringKey = "usernameStringKey"
|
||||
let serverStringKey = "serverStringKey"
|
||||
|
||||
@ -39,13 +39,11 @@ struct AccountModel {
|
||||
var username: String = ""
|
||||
|
||||
private(set) var user: WFUser?
|
||||
private(set) var isLoggedIn: Bool = false
|
||||
|
||||
mutating func login(_ user: WFUser) {
|
||||
self.user = user
|
||||
self.username = user.username ?? ""
|
||||
self.isLoggedIn = true
|
||||
defaults.set(true, forKey: isLoggedInFlag)
|
||||
defaults.set(user.username, forKey: usernameStringKey)
|
||||
defaults.set(server, forKey: serverStringKey)
|
||||
}
|
||||
@ -53,13 +51,11 @@ struct AccountModel {
|
||||
mutating func logout() {
|
||||
self.user = nil
|
||||
self.isLoggedIn = false
|
||||
defaults.set(false, forKey: isLoggedInFlag)
|
||||
defaults.removeObject(forKey: usernameStringKey)
|
||||
defaults.removeObject(forKey: serverStringKey)
|
||||
}
|
||||
|
||||
mutating func restoreState() {
|
||||
isLoggedIn = defaults.bool(forKey: isLoggedInFlag)
|
||||
server = defaults.string(forKey: serverStringKey) ?? ""
|
||||
username = defaults.string(forKey: usernameStringKey) ?? ""
|
||||
}
|
||||
|
@ -5,41 +5,79 @@ struct ContentView: View {
|
||||
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
#if os(macOS)
|
||||
SidebarView()
|
||||
.toolbar {
|
||||
Button(
|
||||
action: {
|
||||
NSApp.keyWindow?.contentViewController?.tryToPerform(
|
||||
#selector(NSSplitViewController.toggleSidebar(_:)), with: nil
|
||||
)
|
||||
},
|
||||
label: { Image(systemName: "sidebar.left") }
|
||||
)
|
||||
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.selectedPost = managedPost
|
||||
}
|
||||
}
|
||||
}, label: { Image(systemName: "square.and.pencil") })
|
||||
}
|
||||
#else
|
||||
SidebarView()
|
||||
#endif
|
||||
|
||||
#if os(macOS)
|
||||
PostListView(selectedCollection: nil, showAllPosts: model.account.isLoggedIn)
|
||||
.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
|
||||
})
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
PostListView(selectedCollection: nil, showAllPosts: model.account.isLoggedIn)
|
||||
#endif
|
||||
|
||||
Text("Select a post, or create a new local draft.")
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
.environmentObject(model)
|
||||
.alert(isPresented: $model.isPresentingDeleteAlert) {
|
||||
Alert(
|
||||
title: Text("Delete Post?"),
|
||||
message: Text("This action cannot be undone."),
|
||||
primaryButton: .destructive(Text("Delete"), action: {
|
||||
if let postToDelete = model.postToDelete {
|
||||
model.selectedPost = nil
|
||||
DispatchQueue.main.async {
|
||||
model.posts.remove(postToDelete)
|
||||
}
|
||||
model.postToDelete = nil
|
||||
}
|
||||
}),
|
||||
secondaryButton: .cancel() {
|
||||
model.postToDelete = nil
|
||||
}
|
||||
)
|
||||
}
|
||||
.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
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
#if os(iOS)
|
||||
EmptyView()
|
||||
@ -51,6 +89,17 @@ struct ContentView: View {
|
||||
.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
|
||||
}
|
||||
}
|
||||
|
@ -11,16 +11,21 @@ struct PostEditorStatusToolbarView: View {
|
||||
PostStatusBadgeView(post: post)
|
||||
#else
|
||||
HStack {
|
||||
HStack {
|
||||
Text("⚠️ Newer copy on server. Replace local copy?")
|
||||
.font(.callout)
|
||||
.foregroundColor(.secondary)
|
||||
Button(action: {
|
||||
model.updateFromServer(post: post)
|
||||
}, label: {
|
||||
Image(systemName: "square.and.arrow.down")
|
||||
})
|
||||
}
|
||||
.padding(.horizontal)
|
||||
.background(Color.primary.opacity(0.1))
|
||||
.clipShape(Capsule())
|
||||
.padding(.trailing)
|
||||
PostStatusBadgeView(post: post)
|
||||
.padding(.trailing)
|
||||
Text("⚠️ Newer copy on server. Replace local copy?")
|
||||
.font(.callout)
|
||||
.foregroundColor(.secondary)
|
||||
Button(action: {
|
||||
model.updateFromServer(post: post)
|
||||
}, label: {
|
||||
Image(systemName: "square.and.arrow.down")
|
||||
})
|
||||
}
|
||||
#endif
|
||||
} else if post.wasDeletedFromServer && post.status != PostStatus.local.rawValue {
|
||||
@ -28,19 +33,24 @@ struct PostEditorStatusToolbarView: View {
|
||||
PostStatusBadgeView(post: post)
|
||||
#else
|
||||
HStack {
|
||||
HStack {
|
||||
Text("⚠️ Post deleted from server. Delete local copy?")
|
||||
.font(.callout)
|
||||
.foregroundColor(.secondary)
|
||||
Button(action: {
|
||||
model.selectedPost = nil
|
||||
DispatchQueue.main.async {
|
||||
model.posts.remove(post)
|
||||
}
|
||||
}, label: {
|
||||
Image(systemName: "trash")
|
||||
})
|
||||
}
|
||||
.padding(.horizontal)
|
||||
.background(Color.primary.opacity(0.1))
|
||||
.clipShape(Capsule())
|
||||
.padding(.trailing)
|
||||
PostStatusBadgeView(post: post)
|
||||
.padding(.trailing)
|
||||
Text("⚠️ Post deleted from server. Delete local copy?")
|
||||
.font(.callout)
|
||||
.foregroundColor(.secondary)
|
||||
Button(action: {
|
||||
model.selectedPost = nil
|
||||
DispatchQueue.main.async {
|
||||
model.posts.remove(post)
|
||||
}
|
||||
}, label: {
|
||||
Image(systemName: "trash")
|
||||
})
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
|
@ -86,6 +86,25 @@ struct PostListFilteredView: View {
|
||||
}
|
||||
})
|
||||
}
|
||||
.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
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
.onAppear(perform: {
|
||||
self.postCount = fetchRequest.wrappedValue.count
|
||||
})
|
||||
@ -103,7 +122,13 @@ struct PostListFilteredView: View {
|
||||
}
|
||||
|
||||
func delete(_ post: WFAPost) {
|
||||
model.posts.remove(post)
|
||||
DispatchQueue.main.async {
|
||||
if post == model.selectedPost {
|
||||
model.selectedPost = nil
|
||||
model.editor.clearLastDraft()
|
||||
}
|
||||
model.posts.remove(post)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,8 +3,10 @@ import CoreData
|
||||
|
||||
class PostListModel: ObservableObject {
|
||||
func remove(_ post: WFAPost) {
|
||||
LocalStorageManager.persistentContainer.viewContext.delete(post)
|
||||
LocalStorageManager().saveContext()
|
||||
withAnimation {
|
||||
LocalStorageManager.persistentContainer.viewContext.delete(post)
|
||||
LocalStorageManager().saveContext()
|
||||
}
|
||||
}
|
||||
|
||||
func purgePublishedPosts() {
|
||||
|
@ -21,7 +21,29 @@ struct PostListView: View {
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .primaryAction) {
|
||||
Button(action: {
|
||||
createNewLocalDraft()
|
||||
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
|
||||
managedPost.rtl = Locale.characterDirection(forLanguage: languageCode) == .rightToLeft
|
||||
}
|
||||
withAnimation {
|
||||
self.selectedCollection = nil
|
||||
self.showAllPosts = false
|
||||
self.model.selectedPost = managedPost
|
||||
}
|
||||
}, label: {
|
||||
Image(systemName: "square.and.pencil")
|
||||
})
|
||||
@ -41,7 +63,10 @@ struct PostListView: View {
|
||||
ProgressView()
|
||||
} else {
|
||||
Button(action: {
|
||||
reloadFromServer()
|
||||
DispatchQueue.main.async {
|
||||
model.fetchUserCollections()
|
||||
model.fetchUserPosts()
|
||||
}
|
||||
}, label: {
|
||||
Image(systemName: "arrow.clockwise")
|
||||
})
|
||||
@ -61,56 +86,8 @@ struct PostListView: View {
|
||||
)
|
||||
)
|
||||
.navigationSubtitle(postCount == 1 ? "\(postCount) post" : "\(postCount) posts")
|
||||
.toolbar {
|
||||
Button(action: {
|
||||
createNewLocalDraft()
|
||||
}, label: {
|
||||
Image(systemName: "square.and.pencil")
|
||||
})
|
||||
Button(action: {
|
||||
reloadFromServer()
|
||||
}, label: {
|
||||
Image(systemName: "arrow.clockwise")
|
||||
})
|
||||
.disabled(!model.account.isLoggedIn)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private func reloadFromServer() {
|
||||
DispatchQueue.main.async {
|
||||
model.fetchUserCollections()
|
||||
model.fetchUserPosts()
|
||||
}
|
||||
}
|
||||
|
||||
private func createNewLocalDraft() {
|
||||
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
|
||||
managedPost.rtl = Locale.characterDirection(forLanguage: languageCode) == .rightToLeft
|
||||
}
|
||||
DispatchQueue.main.async {
|
||||
self.selectedCollection = nil
|
||||
self.showAllPosts = false
|
||||
withAnimation {
|
||||
self.model.selectedPost = managedPost
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct PostListView_Previews: PreviewProvider {
|
||||
|
@ -22,6 +22,27 @@ struct WriteFreely_MultiPlatformApp: App {
|
||||
.environment(\.managedObjectContext, LocalStorageManager.persistentContainer.viewContext)
|
||||
// .preferredColorScheme(preferences.selectedColorScheme) // See PreferencesModel for info.
|
||||
}
|
||||
.commands {
|
||||
CommandGroup(replacing: .newItem, addition: {
|
||||
Button("New Post") {
|
||||
createNewLocalPost()
|
||||
}
|
||||
.keyboardShortcut("n", modifiers: [.command])
|
||||
})
|
||||
CommandGroup(after: .newItem) {
|
||||
Button("Refresh Posts") {
|
||||
DispatchQueue.main.async {
|
||||
model.fetchUserCollections()
|
||||
model.fetchUserPosts()
|
||||
}
|
||||
}
|
||||
.disabled(!model.account.isLoggedIn)
|
||||
.keyboardShortcut("r", modifiers: [.command])
|
||||
}
|
||||
#if os(macOS)
|
||||
SidebarCommands()
|
||||
#endif
|
||||
}
|
||||
|
||||
#if os(macOS)
|
||||
Settings {
|
||||
@ -48,6 +69,9 @@ struct WriteFreely_MultiPlatformApp: App {
|
||||
}
|
||||
|
||||
private func createNewLocalPost() {
|
||||
withAnimation {
|
||||
self.model.selectedPost = nil
|
||||
}
|
||||
let managedPost = WFAPost(context: LocalStorageManager.persistentContainer.viewContext)
|
||||
managedPost.createdDate = Date()
|
||||
managedPost.title = ""
|
||||
@ -66,6 +90,8 @@ struct WriteFreely_MultiPlatformApp: App {
|
||||
managedPost.language = languageCode
|
||||
managedPost.rtl = Locale.characterDirection(forLanguage: languageCode) == .rightToLeft
|
||||
}
|
||||
self.model.selectedPost = managedPost
|
||||
withAnimation {
|
||||
self.model.selectedPost = managedPost
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -62,6 +62,7 @@
|
||||
17B996D92502D23E0017B536 /* WFAPost+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17B996D62502D23E0017B536 /* WFAPost+CoreDataClass.swift */; };
|
||||
17B996DA2502D23E0017B536 /* WFAPost+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17B996D72502D23E0017B536 /* WFAPost+CoreDataProperties.swift */; };
|
||||
17B996DB2502D23E0017B536 /* WFAPost+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17B996D72502D23E0017B536 /* WFAPost+CoreDataProperties.swift */; };
|
||||
17BC618A25715318003363CA /* ActivePostToolbarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17BC617825715068003363CA /* ActivePostToolbarView.swift */; };
|
||||
17C42E622507D8E600072984 /* PostStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17C42E612507D8E600072984 /* PostStatus.swift */; };
|
||||
17C42E632507D8E600072984 /* PostStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17C42E612507D8E600072984 /* PostStatus.swift */; };
|
||||
17C42E652509237800072984 /* PostListFilteredView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17C42E642509237800072984 /* PostListFilteredView.swift */; };
|
||||
@ -151,6 +152,7 @@
|
||||
17B5103A2515448D00E9631F /* Credits.rtf */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; path = Credits.rtf; sourceTree = "<group>"; };
|
||||
17B996D62502D23E0017B536 /* WFAPost+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WFAPost+CoreDataClass.swift"; sourceTree = SOURCE_ROOT; };
|
||||
17B996D72502D23E0017B536 /* WFAPost+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WFAPost+CoreDataProperties.swift"; sourceTree = SOURCE_ROOT; };
|
||||
17BC617825715068003363CA /* ActivePostToolbarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivePostToolbarView.swift; sourceTree = "<group>"; };
|
||||
17C42E612507D8E600072984 /* PostStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostStatus.swift; sourceTree = "<group>"; };
|
||||
17C42E642509237800072984 /* PostListFilteredView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostListFilteredView.swift; sourceTree = "<group>"; };
|
||||
17C42E6F250AA12200072984 /* NSManagedObjectContext+ExecuteAndMergeChanges.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSManagedObjectContext+ExecuteAndMergeChanges.swift"; sourceTree = "<group>"; };
|
||||
@ -316,6 +318,14 @@
|
||||
path = PostEditor;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
17BC617725715042003363CA /* Navigation */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
17BC617825715068003363CA /* ActivePostToolbarView.swift */,
|
||||
);
|
||||
path = Navigation;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
17D4F3722514EE4400517CE6 /* Resources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -393,6 +403,7 @@
|
||||
children = (
|
||||
17DF329224C87D3500BCE2E3 /* Info.plist */,
|
||||
17DF329324C87D3500BCE2E3 /* macOS.entitlements */,
|
||||
17BC617725715042003363CA /* Navigation */,
|
||||
17A67CAC251A5D8D002F163D /* PostEditor */,
|
||||
17A5388924DDA50500DEFF9A /* Settings */,
|
||||
17B5103A2515448D00E9631F /* Credits.rtf */,
|
||||
@ -754,6 +765,7 @@
|
||||
1753F6AC24E431CC00309365 /* MacPreferencesView.swift in Sources */,
|
||||
1756DC0424FEE18400207AB8 /* WFACollection+CoreDataProperties.swift in Sources */,
|
||||
17B996DB2502D23E0017B536 /* WFAPost+CoreDataProperties.swift in Sources */,
|
||||
17BC618A25715318003363CA /* ActivePostToolbarView.swift in Sources */,
|
||||
171BFDFB24D4AF8300888236 /* CollectionListView.swift in Sources */,
|
||||
17A67CAF251A5DD7002F163D /* PostEditorView.swift in Sources */,
|
||||
17DF32AB24C87D3500BCE2E3 /* WriteFreely_MultiPlatformApp.swift in Sources */,
|
||||
|
@ -7,12 +7,12 @@
|
||||
<key>WriteFreely-MultiPlatform (iOS).xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>0</integer>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
<key>WriteFreely-MultiPlatform (macOS).xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>1</integer>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
|
25
macOS/Navigation/ActivePostToolbarView.swift
Normal file
25
macOS/Navigation/ActivePostToolbarView.swift
Normal file
@ -0,0 +1,25 @@
|
||||
import SwiftUI
|
||||
|
||||
struct ActivePostToolbarView: View {
|
||||
@EnvironmentObject var model: WriteFreelyModel
|
||||
@ObservedObject var activePost: WFAPost
|
||||
|
||||
var body: some View {
|
||||
HStack(spacing: 16) {
|
||||
PostEditorStatusToolbarView(post: activePost)
|
||||
HStack(spacing: 4) {
|
||||
Button(action: {}, label: { Image(systemName: "square.and.arrow.up") })
|
||||
.disabled(activePost.status == PostStatus.local.rawValue)
|
||||
Button(action: { publishPost(activePost) }, label: { Image(systemName: "paperplane") })
|
||||
.disabled(activePost.body.isEmpty || activePost.status == PostStatus.published.rawValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func publishPost(_ post: WFAPost) {
|
||||
DispatchQueue.main.async {
|
||||
LocalStorageManager().saveContext()
|
||||
model.publish(post: post)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
import SwiftUI
|
||||
|
||||
struct PostEditorView: View {
|
||||
private let bodyLineSpacing: CGFloat = 17 * 0.5
|
||||
@EnvironmentObject var model: WriteFreelyModel
|
||||
|
||||
@ObservedObject var post: WFAPost
|
||||
@ -15,32 +14,34 @@ struct PostEditorView: View {
|
||||
)
|
||||
.padding()
|
||||
.background(Color(NSColor.controlBackgroundColor))
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .status) {
|
||||
PostEditorStatusToolbarView(post: post)
|
||||
.onAppear(perform: {
|
||||
if post.status != PostStatus.published.rawValue {
|
||||
DispatchQueue.main.async {
|
||||
self.model.editor.saveLastDraft(post)
|
||||
}
|
||||
} else {
|
||||
self.model.editor.clearLastDraft()
|
||||
}
|
||||
ToolbarItem(placement: .primaryAction) {
|
||||
Button(action: {
|
||||
if model.account.isLoggedIn {
|
||||
publishPost()
|
||||
} else {
|
||||
let mainMenu = NSApplication.shared.mainMenu
|
||||
let appMenuItem = mainMenu?.item(withTitle: "WriteFreely")
|
||||
let prefsItem = appMenuItem?.submenu?.item(withTitle: "Preferences…")
|
||||
NSApplication.shared.sendAction(prefsItem!.action!, to: prefsItem?.target, from: nil)
|
||||
}
|
||||
}, label: {
|
||||
Image(systemName: "paperplane")
|
||||
})
|
||||
.disabled(post.status == PostStatus.published.rawValue || post.body.count == 0)
|
||||
}
|
||||
}
|
||||
})
|
||||
.onChange(of: post.hasNewerRemoteCopy, perform: { _ in
|
||||
if !post.hasNewerRemoteCopy {
|
||||
self.updatingFromServer = true
|
||||
}
|
||||
})
|
||||
.onChange(of: post.status, perform: { value in
|
||||
if value != PostStatus.published.rawValue {
|
||||
self.model.editor.saveLastDraft(post)
|
||||
} else {
|
||||
self.model.editor.clearLastDraft()
|
||||
}
|
||||
DispatchQueue.main.async {
|
||||
LocalStorageManager().saveContext()
|
||||
}
|
||||
})
|
||||
.onDisappear(perform: {
|
||||
DispatchQueue.main.async {
|
||||
model.editor.clearLastDraft()
|
||||
}
|
||||
if post.title.count == 0
|
||||
&& post.body.count == 0
|
||||
&& post.status == PostStatus.local.rawValue
|
||||
@ -56,13 +57,6 @@ struct PostEditorView: View {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private func publishPost() {
|
||||
DispatchQueue.main.async {
|
||||
LocalStorageManager().saveContext()
|
||||
model.publish(post: post)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct PostEditorView_EmptyPostPreviews: PreviewProvider {
|
||||
|
Loading…
Reference in New Issue
Block a user