Page MenuHomeMusing Studio

No OneTemporary

diff --git a/Shared/PostEditor/PostEditorModel.swift b/Shared/PostEditor/PostEditorModel.swift
index 8d83713..7580271 100644
--- a/Shared/PostEditor/PostEditorModel.swift
+++ b/Shared/PostEditor/PostEditorModel.swift
@@ -1,32 +1,32 @@
import SwiftUI
import CoreData
enum PostAppearance: String {
case sans = "OpenSans-Regular"
case mono = "Hack-Regular"
case serif = "Lora-Regular"
}
struct PostEditorModel {
@AppStorage("lastDraftURL") private var lastDraftURL: URL?
func saveLastDraft(_ post: WFAPost) {
self.lastDraftURL = post.status != PostStatus.published.rawValue ? post.objectID.uriRepresentation() : nil
}
func clearLastDraft() {
self.lastDraftURL = nil
}
func fetchLastDraftFromUserDefaults() -> WFAPost? {
guard let postURL = lastDraftURL else { return nil }
let coordinator = LocalStorageManager.persistentContainer.persistentStoreCoordinator
guard let postManagedObjectID = coordinator.managedObjectID(forURIRepresentation: postURL) else { return nil }
guard let post = LocalStorageManager.persistentContainer.viewContext.object(
- with: postManagedObjectID
+ with: postManagedObjectID
) as? WFAPost else { return nil }
return post
}
}
diff --git a/Shared/WriteFreely_MultiPlatformApp.swift b/Shared/WriteFreely_MultiPlatformApp.swift
index 287ccb7..ef3a31f 100644
--- a/Shared/WriteFreely_MultiPlatformApp.swift
+++ b/Shared/WriteFreely_MultiPlatformApp.swift
@@ -1,42 +1,71 @@
import SwiftUI
@main
struct WriteFreely_MultiPlatformApp: App {
@StateObject private var model = WriteFreelyModel()
#if os(macOS)
@State private var selectedTab = 0
#endif
var body: some Scene {
WindowGroup {
ContentView()
+ .onAppear(perform: {
+ if let lastDraft = model.editor.fetchLastDraftFromUserDefaults() {
+ self.model.selectedPost = lastDraft
+ } else {
+ createNewLocalPost()
+ }
+ })
.environmentObject(model)
.environment(\.managedObjectContext, LocalStorageManager.persistentContainer.viewContext)
// .preferredColorScheme(preferences.selectedColorScheme) // See PreferencesModel for info.
}
#if os(macOS)
Settings {
TabView(selection: $selectedTab) {
MacAccountView()
.environmentObject(model)
.tabItem {
Image(systemName: "person.crop.circle")
Text("Account")
}
.tag(0)
MacPreferencesView(preferences: model.preferences)
.tabItem {
Image(systemName: "gear")
Text("Preferences")
}
.tag(1)
}
.frame(minWidth: 300, maxWidth: 300, minHeight: 200, maxHeight: 200)
.padding()
// .preferredColorScheme(preferences.selectedColorScheme) // See PreferencesModel for info.
}
#endif
}
+
+ private func createNewLocalPost() {
+ 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
+ }
+ self.model.selectedPost = managedPost
+ }
}
diff --git a/iOS/PostEditor/PostEditorView.swift b/iOS/PostEditor/PostEditorView.swift
index a5699f4..e5dfbd7 100644
--- a/iOS/PostEditor/PostEditorView.swift
+++ b/iOS/PostEditor/PostEditorView.swift
@@ -1,238 +1,251 @@
import SwiftUI
struct PostEditorView: View {
@EnvironmentObject var model: WriteFreelyModel
@Environment(\.horizontalSizeClass) var horizontalSizeClass
@Environment(\.managedObjectContext) var moc
@Environment(\.presentationMode) var presentationMode
@ObservedObject var post: WFAPost
@State private var updatingTitleFromServer: Bool = false
@State private var updatingBodyFromServer: Bool = false
@State private var selectedCollection: WFACollection?
@FetchRequest(
entity: WFACollection.entity(),
sortDescriptors: [NSSortDescriptor(keyPath: \WFACollection.title, ascending: true)]
) var collections: FetchedResults<WFACollection>
var body: some View {
VStack {
if post.hasNewerRemoteCopy {
RemoteChangePromptView(
remoteChangeType: .remoteCopyUpdated,
buttonHandler: { model.updateFromServer(post: post) }
)
} else if post.wasDeletedFromServer {
RemoteChangePromptView(
remoteChangeType: .remoteCopyDeleted,
buttonHandler: {
self.presentationMode.wrappedValue.dismiss()
DispatchQueue.main.async {
model.posts.remove(post)
}
}
)
}
PostTextEditingView(
post: _post,
updatingTitleFromServer: $updatingTitleFromServer,
updatingBodyFromServer: $updatingBodyFromServer
)
}
.navigationBarTitleDisplayMode(.inline)
.padding()
.toolbar {
ToolbarItem(placement: .principal) {
PostEditorStatusToolbarView(post: post)
}
ToolbarItem(placement: .primaryAction) {
if model.isProcessingRequest {
ProgressView()
} else {
Menu(content: {
if post.status == PostStatus.local.rawValue {
Menu(content: {
Label("Publish to…", systemImage: "paperplane")
Button(action: {
if model.account.isLoggedIn {
post.collectionAlias = nil
publishPost()
} else {
self.model.isPresentingSettingsView = true
}
}, label: {
Text(" \(model.account.server == "https://write.as" ? "Anonymous" : "Drafts")")
})
ForEach(collections) { collection in
Button(action: {
if model.account.isLoggedIn {
post.collectionAlias = collection.alias
publishPost()
} else {
self.model.isPresentingSettingsView = true
}
}, label: {
Text(" \(collection.title)")
})
}
}, label: {
Label("Publish…", systemImage: "paperplane")
})
} else {
Button(action: {
if model.account.isLoggedIn {
publishPost()
} else {
self.model.isPresentingSettingsView = true
}
}, label: {
Label("Publish", systemImage: "paperplane")
})
.disabled(post.status == PostStatus.published.rawValue || post.body.count == 0)
}
Button(action: {
sharePost()
}, label: {
Label("Share", systemImage: "square.and.arrow.up")
})
.disabled(post.postId == nil)
// Button(action: {
// print("Tapped 'Delete...' button")
// }, label: {
// Label("Delete…", systemImage: "trash")
// })
if model.account.isLoggedIn && post.status != PostStatus.local.rawValue {
Section(header: Text("Move To Collection")) {
Label("Move to:", systemImage: "arrowshape.zigzag.right")
Picker(selection: $selectedCollection, label: Text("Move to…")) {
Text(
" \(model.account.server == "https://write.as" ? "Anonymous" : "Drafts")"
).tag(nil as WFACollection?)
ForEach(collections) { collection in
Text(" \(collection.title)").tag(collection as WFACollection?)
}
}
}
}
}, label: {
Image(systemName: "ellipsis.circle")
})
}
}
}
.onChange(of: post.hasNewerRemoteCopy, perform: { _ in
if !post.hasNewerRemoteCopy {
updatingTitleFromServer = true
updatingBodyFromServer = true
}
})
.onChange(of: selectedCollection, perform: { [selectedCollection] newCollection in
if post.collectionAlias == newCollection?.alias {
return
} else {
post.collectionAlias = newCollection?.alias
model.move(post: post, from: selectedCollection, to: newCollection)
}
})
+ .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()
+ }
+ })
.onAppear(perform: {
self.selectedCollection = collections.first { $0.alias == post.collectionAlias }
if post.status != PostStatus.published.rawValue {
- self.model.editor.saveLastDraft(post)
+ DispatchQueue.main.async {
+ self.model.editor.saveLastDraft(post)
+ }
} else {
self.model.editor.clearLastDraft()
}
})
.onDisappear(perform: {
+ self.model.editor.clearLastDraft()
if post.title.count == 0
&& post.body.count == 0
&& post.status == PostStatus.local.rawValue
&& post.updatedDate == nil
&& post.postId == nil {
DispatchQueue.main.async {
model.posts.remove(post)
}
} else if post.status != PostStatus.published.rawValue {
DispatchQueue.main.async {
LocalStorageManager().saveContext()
}
}
})
}
private func publishPost() {
DispatchQueue.main.async {
LocalStorageManager().saveContext()
model.publish(post: post)
}
#if os(iOS)
self.hideKeyboard()
#endif
}
private func sharePost() {
// If the post doesn't have a post ID, it isn't published, and therefore can't be shared, so return early.
guard let postId = post.postId else { return }
var urlString: String
if let postSlug = post.slug,
let postCollectionAlias = post.collectionAlias {
// This post is in a collection, so share the URL as server/collectionAlias/postSlug.
urlString = "\(model.account.server)/\((postCollectionAlias))/\((postSlug))"
} else {
// This is a draft post, so share the URL as server/postID
urlString = "\(model.account.server)/\((postId))"
}
guard let data = URL(string: urlString) else { return }
let activityView = UIActivityViewController(activityItems: [data], applicationActivities: nil)
UIApplication.shared.windows.first?.rootViewController?.present(activityView, animated: true, completion: nil)
if UIDevice.current.userInterfaceIdiom == .pad {
activityView.popoverPresentationController?.permittedArrowDirections = .up
activityView.popoverPresentationController?.sourceView = UIApplication.shared.windows.first
activityView.popoverPresentationController?.sourceRect = CGRect(
x: UIScreen.main.bounds.width,
y: -125,
width: 200,
height: 200
)
}
}
}
struct PostEditorView_EmptyPostPreviews: PreviewProvider {
static var previews: some View {
let context = LocalStorageManager.persistentContainer.viewContext
let testPost = WFAPost(context: context)
testPost.createdDate = Date()
testPost.appearance = "norm"
let model = WriteFreelyModel()
return PostEditorView(post: testPost)
.environment(\.managedObjectContext, context)
.environmentObject(model)
}
}
struct PostEditorView_ExistingPostPreviews: PreviewProvider {
static var previews: some View {
let context = LocalStorageManager.persistentContainer.viewContext
let testPost = WFAPost(context: context)
testPost.title = "Test Post Title"
testPost.body = "Here's some cool sample body text."
testPost.createdDate = Date()
testPost.appearance = "code"
testPost.hasNewerRemoteCopy = true
let model = WriteFreelyModel()
return PostEditorView(post: testPost)
.environment(\.managedObjectContext, context)
.environmentObject(model)
}
}

File Metadata

Mime Type
text/x-diff
Expires
Thu, Nov 20, 8:26 AM (1 d, 11 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3496612

Event Timeline