Page MenuHomeMusing Studio

No OneTemporary

diff --git a/Shared/WriteFreely_MultiPlatformApp.swift b/Shared/WriteFreely_MultiPlatformApp.swift
index 76ff61b..d17c965 100644
--- a/Shared/WriteFreely_MultiPlatformApp.swift
+++ b/Shared/WriteFreely_MultiPlatformApp.swift
@@ -1,147 +1,148 @@
import SwiftUI
#if os(macOS)
import Sparkle
#endif
@main
struct CheckForDebugModifier {
static func main() {
#if os(macOS)
if NSEvent.modifierFlags.contains(.shift) {
// Clear the launch-to-last-draft values to load a new draft.
UserDefaults.shared.setValue(false, forKey: WFDefaults.showAllPostsFlag)
UserDefaults.shared.setValue(nil, forKey: WFDefaults.selectedCollectionURL)
UserDefaults.shared.setValue(nil, forKey: WFDefaults.lastDraftURL)
} else {
// No-op
}
#endif
WriteFreely_MultiPlatformApp.main()
}
}
struct WriteFreely_MultiPlatformApp: App {
@StateObject private var model = WriteFreelyModel.shared
#if os(macOS)
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
@StateObject var updaterViewModel = MacUpdatesViewModel()
@State private var selectedTab = 0
#endif
var body: some Scene {
WindowGroup {
ContentView()
.onAppear(perform: {
if model.editor.showAllPostsFlag {
DispatchQueue.main.async {
self.model.selectedCollection = nil
self.model.showAllPosts = true
showLastDraftOrCreateNewLocalPost()
}
} else {
DispatchQueue.main.async {
self.model.selectedCollection = model.editor.fetchSelectedCollectionFromAppStorage()
self.model.showAllPosts = false
showLastDraftOrCreateNewLocalPost()
}
}
})
.withErrorHandling()
.environmentObject(model)
.environment(\.managedObjectContext, LocalStorageManager.standard.container.viewContext)
// .preferredColorScheme(preferences.selectedColorScheme) // See PreferencesModel for info.
}
.commands {
#if os(macOS)
CommandGroup(after: .appInfo) {
CheckForUpdatesView(updaterViewModel: updaterViewModel)
}
#endif
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])
}
SidebarCommands()
#if os(macOS)
PostCommands(model: model)
#endif
CommandGroup(after: .help) {
Button("Visit Support Forum") {
#if os(macOS)
NSWorkspace().open(model.helpURL)
#else
UIApplication.shared.open(model.helpURL)
#endif
}
}
ToolbarCommands()
TextEditingCommands()
}
#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)
MacUpdatesView(updaterViewModel: updaterViewModel)
.tabItem {
Image(systemName: "arrow.down.circle")
Text("Updates")
}
.tag(2)
}
+ .withErrorHandling()
.frame(minWidth: 500, maxWidth: 500, minHeight: 200)
.padding()
// .preferredColorScheme(preferences.selectedColorScheme) // See PreferencesModel for info.
}
#endif
}
private func showLastDraftOrCreateNewLocalPost() {
if model.editor.lastDraftURL != nil {
self.model.selectedPost = model.editor.fetchLastDraftFromAppStorage()
} else {
createNewLocalPost()
}
}
private func createNewLocalPost() {
withAnimation {
// Un-set the currently selected post
self.model.selectedPost = nil
}
// Create the new-post managed object
let managedPost = model.editor.generateNewLocalPost(withFont: model.preferences.font)
withAnimation {
// Set it as the selectedPost
DispatchQueue.main.asyncAfter(deadline: .now()) {
self.model.selectedPost = managedPost
}
}
}
}
diff --git a/macOS/PostEditor/PostEditorView.swift b/macOS/PostEditor/PostEditorView.swift
index 56bedc9..b76e921 100644
--- a/macOS/PostEditor/PostEditorView.swift
+++ b/macOS/PostEditor/PostEditorView.swift
@@ -1,92 +1,103 @@
import SwiftUI
struct PostEditorView: View {
@EnvironmentObject var model: WriteFreelyModel
+ @EnvironmentObject var errorHandling: ErrorHandling
@ObservedObject var post: WFAPost
@State private var isHovering: Bool = false
@State private var updatingFromServer: Bool = false
var body: some View {
PostTextEditingView(
post: post,
updatingFromServer: $updatingFromServer
)
.padding()
.background(Color(NSColor.controlBackgroundColor))
.onAppear(perform: {
if post.status != PostStatus.published.rawValue {
DispatchQueue.main.async {
self.model.editor.saveLastDraft(post)
}
} else {
self.model.editor.clearLastDraft()
}
})
.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.standard.saveContext()
}
})
+ .onChange(of: model.hasError) { value in
+ if value {
+ if let error = model.currentError {
+ self.errorHandling.handle(error: error)
+ } else {
+ self.errorHandling.handle(error: AppError.genericError())
+ }
+ model.hasError = false
+ }
+ }
.onDisappear(perform: {
DispatchQueue.main.async {
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.standard.saveContext()
}
}
})
}
}
struct PostEditorView_EmptyPostPreviews: PreviewProvider {
static var previews: some View {
let context = LocalStorageManager.standard.container.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.standard.container.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"
let model = WriteFreelyModel()
return PostEditorView(post: testPost)
.environment(\.managedObjectContext, context)
.environmentObject(model)
}
}
diff --git a/macOS/Settings/MacAccountView.swift b/macOS/Settings/MacAccountView.swift
index f0d4c30..9939e99 100644
--- a/macOS/Settings/MacAccountView.swift
+++ b/macOS/Settings/MacAccountView.swift
@@ -1,18 +1,29 @@
import SwiftUI
struct MacAccountView: View {
@EnvironmentObject var model: WriteFreelyModel
+ @EnvironmentObject var errorHandling: ErrorHandling
var body: some View {
- Form {
- AccountView()
+ Form {
+ AccountView()
+ }
+ .onChange(of: model.hasError) { value in
+ if value {
+ if let error = model.currentError {
+ self.errorHandling.handle(error: error)
+ } else {
+ self.errorHandling.handle(error: AppError.genericError())
+ }
+ model.hasError = false
}
+ }
}
}
struct MacAccountView_Previews: PreviewProvider {
static var previews: some View {
MacAccountView()
.environmentObject(WriteFreelyModel())
}
}
diff --git a/macOS/Settings/MacPreferencesView.swift b/macOS/Settings/MacPreferencesView.swift
index 85fa829..feb91e5 100644
--- a/macOS/Settings/MacPreferencesView.swift
+++ b/macOS/Settings/MacPreferencesView.swift
@@ -1,18 +1,31 @@
import SwiftUI
struct MacPreferencesView: View {
+ @EnvironmentObject var model: WriteFreelyModel
+ @EnvironmentObject var errorHandling: ErrorHandling
+
@ObservedObject var preferences: PreferencesModel
var body: some View {
VStack {
PreferencesView(preferences: preferences)
Spacer()
}
+ .onChange(of: model.hasError) { value in
+ if value {
+ if let error = model.currentError {
+ self.errorHandling.handle(error: error)
+ } else {
+ self.errorHandling.handle(error: AppError.genericError())
+ }
+ model.hasError = false
+ }
+ }
}
}
struct MacPreferencesView_Previews: PreviewProvider {
static var previews: some View {
MacPreferencesView(preferences: PreferencesModel())
}
}
diff --git a/macOS/Settings/MacUpdatesView.swift b/macOS/Settings/MacUpdatesView.swift
index afb6c48..ba9f6a3 100644
--- a/macOS/Settings/MacUpdatesView.swift
+++ b/macOS/Settings/MacUpdatesView.swift
@@ -1,91 +1,104 @@
import SwiftUI
import Sparkle
struct MacUpdatesView: View {
+ @EnvironmentObject var model: WriteFreelyModel
+ @EnvironmentObject var errorHandling: ErrorHandling
+
@ObservedObject var updaterViewModel: MacUpdatesViewModel
@AppStorage(WFDefaults.automaticallyChecksForUpdates, store: UserDefaults.shared)
var automaticallyChecksForUpdates: Bool = false
@AppStorage(WFDefaults.subscribeToBetaUpdates, store: UserDefaults.shared)
var subscribeToBetaUpdates: Bool = false
@State private var lastUpdateCheck: Date?
private let betaWarningString = """
To get brand new features before each official release, choose "Test versions." Note that test versions may have bugs \
that can cause crashes and data loss.
"""
static let lastUpdateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .short
formatter.timeStyle = .short
formatter.doesRelativeDateFormatting = true
return formatter
}()
var body: some View {
VStack(spacing: 24) {
Toggle(isOn: $automaticallyChecksForUpdates, label: {
Text("Check for updates automatically")
})
VStack {
Button(action: {
updaterViewModel.checkForUpdates()
// There's a delay between requesting an update, and the timestamp for that update request being
// written to user defaults; we therefore delay updating the "Last checked" UI for one second.
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
lastUpdateCheck = updaterViewModel.getLastUpdateCheckDate()
}
}, label: {
Text("Check For Updates")
})
HStack {
Text("Last checked:")
.font(.caption)
if let lastUpdateCheck = lastUpdateCheck {
Text(lastUpdateCheck, formatter: Self.lastUpdateFormatter)
.font(.caption)
} else {
Text("Never")
.font(.caption)
}
}
}
VStack(spacing: 16) {
HStack(alignment: .top) {
Text("Download:")
Picker(selection: $subscribeToBetaUpdates, label: Text("Download:"), content: {
Text("Release versions").tag(false)
Text("Test versions").tag(true)
})
.pickerStyle(RadioGroupPickerStyle())
.labelsHidden()
}
Text(betaWarningString)
.frame(width: 350)
.foregroundColor(.secondary)
}
}
.padding()
.onAppear {
lastUpdateCheck = updaterViewModel.getLastUpdateCheckDate()
}
.onChange(of: automaticallyChecksForUpdates) { value in
updaterViewModel.automaticallyCheckForUpdates = value
}
.onChange(of: subscribeToBetaUpdates) { _ in
updaterViewModel.toggleAllowedChannels()
}
+ .onChange(of: model.hasError) { value in
+ if value {
+ if let error = model.currentError {
+ self.errorHandling.handle(error: error)
+ } else {
+ self.errorHandling.handle(error: AppError.genericError())
+ }
+ model.hasError = false
+ }
+ }
}
}
struct MacUpdatesView_Previews: PreviewProvider {
static var previews: some View {
MacUpdatesView(updaterViewModel: MacUpdatesViewModel())
}
}

File Metadata

Mime Type
text/x-diff
Expires
Mon, Nov 25, 5:41 PM (1 d, 12 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3105206

Event Timeline