@@ -17,6 +17,14 @@ final class WriteFreelyModel: ObservableObject { | |||
@Published var hasError: Bool = false | |||
var currentError: Error? { | |||
didSet { | |||
if let localizedErrorDescription = currentError?.localizedDescription, | |||
localizedErrorDescription == "The operation couldn’t be completed. (WriteFreely.WFError error -2.)", | |||
!hasNetworkConnection { | |||
#if DEBUG | |||
print("⚠️ currentError is WriteFreely.WFError -2 and there is no network connection.") | |||
#endif | |||
currentError = NetworkError.noConnectionError | |||
} | |||
#if DEBUG | |||
print("⚠️ currentError -> didSet \(currentError?.localizedDescription ?? "nil")") | |||
print(" > hasError was: \(self.hasError)") | |||
@@ -66,6 +74,10 @@ final class WriteFreelyModel: ObservableObject { | |||
self.preferences.appearance = self.defaults.integer(forKey: WFDefaults.colorSchemeIntegerKey) | |||
self.preferences.font = self.defaults.integer(forKey: WFDefaults.defaultFontIntegerKey) | |||
self.account.restoreState() | |||
// Set the appearance | |||
self.preferences.updateAppearance(to: Appearance(rawValue: self.preferences.appearance) ?? .system) | |||
if self.account.isLoggedIn { | |||
guard let serverURL = URL(string: self.account.server) else { | |||
self.currentError = AccountError.invalidServerURL | |||
@@ -59,14 +59,7 @@ struct ContentView: View { | |||
.withErrorHandling() | |||
#endif | |||
#if os(macOS) | |||
Text("Select a post, or create a new local draft.") | |||
.foregroundColor(.secondary) | |||
.frame(width: 500, height: 500) | |||
#else | |||
Text("Select a post, or create a new local draft.") | |||
.foregroundColor(.secondary) | |||
#endif | |||
NoSelectedPostView(isConnected: $model.hasNetworkConnection) | |||
} | |||
.environmentObject(model) | |||
.onChange(of: model.hasError) { value in | |||
@@ -0,0 +1,29 @@ | |||
import SwiftUI | |||
struct NoSelectedPostView: View { | |||
@Binding var isConnected: Bool | |||
var body: some View { | |||
VStack(spacing: 8) { | |||
Text("Select a post, or create a new local draft.") | |||
if !isConnected { | |||
Label("You are not connected to the internet", systemImage: "wifi.exclamationmark") | |||
.font(.caption) | |||
.foregroundColor(.secondary) | |||
} | |||
} | |||
.frame(width: 500, height: 500) | |||
} | |||
} | |||
struct NoSelectedPostViewIsDisconnected_Previews: PreviewProvider { | |||
static var previews: some View { | |||
NoSelectedPostView(isConnected: Binding.constant(true)) | |||
} | |||
} | |||
struct NoSelectedPostViewIsConnected_Previews: PreviewProvider { | |||
static var previews: some View { | |||
NoSelectedPostView(isConnected: Binding.constant(false)) | |||
} | |||
} |
@@ -97,19 +97,26 @@ struct PostListView: View { | |||
.padding(.vertical, 4) | |||
.padding(.horizontal, 8) | |||
} else { | |||
Button(action: { | |||
DispatchQueue.main.async { | |||
model.fetchUserCollections() | |||
model.fetchUserPosts() | |||
} | |||
}, label: { | |||
Image(systemName: "arrow.clockwise") | |||
if model.hasNetworkConnection { | |||
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) | |||
} else { | |||
Image(systemName: "wifi.exclamationmark") | |||
.padding(.vertical, 4) | |||
.padding(.horizontal, 8) | |||
}) | |||
.accessibilityLabel(Text("Refresh Posts")) | |||
.accessibilityHint(Text("Fetch changes from the server")) | |||
.disabled(!model.account.isLoggedIn) | |||
.foregroundColor(.secondary) | |||
} | |||
} | |||
} | |||
.padding(.top, 8) | |||
@@ -1,67 +1,54 @@ | |||
import SwiftUI | |||
enum Appearance: Int { | |||
case system = 0 | |||
case light = 1 | |||
case dark = 2 | |||
} | |||
class PreferencesModel: ObservableObject { | |||
private let defaults = UserDefaults.shared | |||
/* We're stuck dropping into AppKit/UIKit to set light/dark schemes for now, | |||
* because setting the .preferredColorScheme modifier on views in SwiftUI is | |||
* currently unreliable. | |||
* | |||
* Feedback submitted to Apple: | |||
* | |||
* FB8382883: "On macOS 11β4, preferredColorScheme modifier does not respect .light ColorScheme" | |||
* FB8383053: "On iOS 14β4/macOS 11β4, it is not possible to unset preferredColorScheme after setting | |||
* it to either .light or .dark" | |||
*/ | |||
#if os(iOS) | |||
@available(iOSApplicationExtension, unavailable) | |||
var window: UIWindow? { | |||
guard let scene = UIApplication.shared.connectedScenes.first, | |||
let windowSceneDelegate = scene.delegate as? UIWindowSceneDelegate, | |||
let window = windowSceneDelegate.window else { | |||
return nil | |||
@Published var selectedColorScheme: ColorScheme? | |||
@Published var appearance: Int = 0 | |||
@Published var font: Int = 0 { | |||
didSet { | |||
defaults.set(font, forKey: WFDefaults.defaultFontIntegerKey) | |||
} | |||
return window | |||
} | |||
#endif | |||
@available(iOSApplicationExtension, unavailable) | |||
@Published var selectedColorScheme: ColorScheme? | |||
@available(iOSApplicationExtension, unavailable) | |||
@Published var appearance: Int = 0 { | |||
didSet { | |||
switch appearance { | |||
case 1: | |||
// selectedColorScheme = .light | |||
#if os(macOS) | |||
NSApp.appearance = NSAppearance(named: .aqua) | |||
#else | |||
window?.overrideUserInterfaceStyle = .light | |||
#endif | |||
case 2: | |||
// selectedColorScheme = .dark | |||
#if os(macOS) | |||
NSApp.appearance = NSAppearance(named: .darkAqua) | |||
#else | |||
window?.overrideUserInterfaceStyle = .dark | |||
#endif | |||
default: | |||
// selectedColorScheme = .none | |||
#if os(macOS) | |||
NSApp.appearance = nil | |||
#else | |||
window?.overrideUserInterfaceStyle = .unspecified | |||
#endif | |||
func updateAppearance(to appearance: Appearance) { | |||
#if os(iOS) | |||
var window: UIWindow? { | |||
guard let scene = UIApplication.shared.connectedScenes.first, | |||
let windowSceneDelegate = scene.delegate as? UIWindowSceneDelegate, | |||
let window = windowSceneDelegate.window else { | |||
return nil | |||
} | |||
defaults.set(appearance, forKey: WFDefaults.colorSchemeIntegerKey) | |||
return window | |||
} | |||
} | |||
@Published var font: Int = 0 { | |||
didSet { | |||
defaults.set(font, forKey: WFDefaults.defaultFontIntegerKey) | |||
#endif | |||
switch appearance { | |||
case .light: | |||
#if os(macOS) | |||
NSApp.appearance = NSAppearance(named: .aqua) | |||
#else | |||
window?.overrideUserInterfaceStyle = .light | |||
#endif | |||
case .dark: | |||
#if os(macOS) | |||
NSApp.appearance = NSAppearance(named: .darkAqua) | |||
#else | |||
window?.overrideUserInterfaceStyle = .dark | |||
#endif | |||
default: | |||
#if os(macOS) | |||
NSApp.appearance = nil | |||
#else | |||
window?.overrideUserInterfaceStyle = .unspecified | |||
#endif | |||
} | |||
} | |||
} |
@@ -3,6 +3,28 @@ import SwiftUI | |||
struct PreferencesView: View { | |||
@ObservedObject var preferences: PreferencesModel | |||
/* We're stuck dropping into AppKit/UIKit to set light/dark schemes for now, | |||
* because setting the .preferredColorScheme modifier on views in SwiftUI is | |||
* currently unreliable. | |||
* | |||
* Feedback submitted to Apple: | |||
* | |||
* FB8382883: "On macOS 11β4, preferredColorScheme modifier does not respect .light ColorScheme" | |||
* FB8383053: "On iOS 14β4/macOS 11β4, it is not possible to unset preferredColorScheme after setting | |||
* it to either .light or .dark" | |||
*/ | |||
#if os(iOS) | |||
var window: UIWindow? { | |||
guard let scene = UIApplication.shared.connectedScenes.first, | |||
let windowSceneDelegate = scene.delegate as? UIWindowSceneDelegate, | |||
let window = windowSceneDelegate.window else { | |||
return nil | |||
} | |||
return window | |||
} | |||
#endif | |||
var body: some View { | |||
VStack { | |||
VStack { | |||
@@ -46,6 +68,10 @@ struct PreferencesView: View { | |||
} | |||
.padding(.bottom) | |||
} | |||
.onChange(of: preferences.appearance) { value in | |||
preferences.updateAppearance(to: Appearance(rawValue: value) ?? .system) | |||
UserDefaults.shared.set(value, forKey: WFDefaults.colorSchemeIntegerKey) | |||
} | |||
} | |||
} | |||
@@ -136,6 +136,8 @@ | |||
17DFDE8B251D309400A25F31 /* OpenSans-License.txt in Resources */ = {isa = PBXBuildFile; fileRef = 17DFDE86251D309400A25F31 /* OpenSans-License.txt */; }; | |||
17DFDE8C251D309400A25F31 /* OpenSans-License.txt in Resources */ = {isa = PBXBuildFile; fileRef = 17DFDE86251D309400A25F31 /* OpenSans-License.txt */; }; | |||
17E5DF8A2543610700DCDC9B /* PostTextEditingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17E5DF892543610700DCDC9B /* PostTextEditingView.swift */; }; | |||
37095AE02AA4A0E700C9C5F8 /* NoSelectedPostView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37113EF82A98C10A00B36B98 /* NoSelectedPostView.swift */; }; | |||
37113EF92A98C10A00B36B98 /* NoSelectedPostView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37113EF82A98C10A00B36B98 /* NoSelectedPostView.swift */; }; | |||
375A67E828FC555C007A1AC0 /* MultilineTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 375A67E728FC555C007A1AC0 /* MultilineTextView.swift */; }; | |||
3779389729EC0C880032D6C1 /* HelpCommands.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3779389629EC0C880032D6C1 /* HelpCommands.swift */; }; | |||
37F749D129B4D3090087F0BF /* SearchablePostListFilteredView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37F749D029B4D3090087F0BF /* SearchablePostListFilteredView.swift */; }; | |||
@@ -270,6 +272,7 @@ | |||
17DFDE85251D309400A25F31 /* Lora-Cyrillic-OFL.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "Lora-Cyrillic-OFL.txt"; sourceTree = "<group>"; }; | |||
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>"; }; | |||
37113EF82A98C10A00B36B98 /* NoSelectedPostView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoSelectedPostView.swift; sourceTree = "<group>"; }; | |||
375A67E728FC555C007A1AC0 /* MultilineTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultilineTextView.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>"; }; | |||
@@ -586,6 +589,7 @@ | |||
isa = PBXGroup; | |||
children = ( | |||
17DF328224C87D3300BCE2E3 /* ContentView.swift */, | |||
37113EF82A98C10A00B36B98 /* NoSelectedPostView.swift */, | |||
); | |||
path = Navigation; | |||
sourceTree = "<group>"; | |||
@@ -922,6 +926,7 @@ | |||
173E19D1254318F600440F0F /* RemoteChangePromptView.swift in Sources */, | |||
17B37C5625C8679800FE75E9 /* WriteFreelyModel+API.swift in Sources */, | |||
17C42E622507D8E600072984 /* PostStatus.swift in Sources */, | |||
37095AE02AA4A0E700C9C5F8 /* NoSelectedPostView.swift in Sources */, | |||
1756DBBA24FED45500207AB8 /* LocalStorageManager.swift in Sources */, | |||
1727526A2809991A003D0A6A /* ErrorHandling.swift in Sources */, | |||
1756AE8124CB844500FD7257 /* View+Keyboard.swift in Sources */, | |||
@@ -975,6 +980,7 @@ | |||
17120DAA24E1B2F5002B9F6C /* AccountLogoutView.swift in Sources */, | |||
17DF32D624C8CA3400BCE2E3 /* PostStatusBadgeView.swift in Sources */, | |||
172C492E2593981900E20ADF /* MacUpdatesView.swift in Sources */, | |||
37113EF92A98C10A00B36B98 /* NoSelectedPostView.swift in Sources */, | |||
1727526728099802003D0A6A /* ErrorConstants.swift in Sources */, | |||
17479F152583D8E40072B7FB /* PostEditorSharingPicker.swift in Sources */, | |||
17480CA6251272EE00EB7765 /* Bundle+AppVersion.swift in Sources */, | |||
@@ -1060,7 +1066,7 @@ | |||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; | |||
CODE_SIGN_ENTITLEMENTS = "ActionExtension-iOS/ActionExtension-iOS.entitlements"; | |||
CODE_SIGN_STYLE = Automatic; | |||
CURRENT_PROJECT_VERSION = 704; | |||
CURRENT_PROJECT_VERSION = 706; | |||
DEVELOPMENT_TEAM = TPPAB4YBA6; | |||
GENERATE_INFOPLIST_FILE = YES; | |||
INFOPLIST_FILE = "ActionExtension-iOS/Info.plist"; | |||
@@ -1072,7 +1078,7 @@ | |||
"@executable_path/Frameworks", | |||
"@executable_path/../../Frameworks", | |||
); | |||
MARKETING_VERSION = 1.0.16; | |||
MARKETING_VERSION = 1.0.17; | |||
PRODUCT_BUNDLE_IDENTIFIER = "com.abunchtell.WriteFreely-MultiPlatform.ActionExtension-iOS"; | |||
PRODUCT_NAME = "$(TARGET_NAME)"; | |||
SDKROOT = iphoneos; | |||
@@ -1091,7 +1097,7 @@ | |||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; | |||
CODE_SIGN_ENTITLEMENTS = "ActionExtension-iOS/ActionExtension-iOS.entitlements"; | |||
CODE_SIGN_STYLE = Automatic; | |||
CURRENT_PROJECT_VERSION = 704; | |||
CURRENT_PROJECT_VERSION = 706; | |||
DEVELOPMENT_TEAM = TPPAB4YBA6; | |||
GENERATE_INFOPLIST_FILE = YES; | |||
INFOPLIST_FILE = "ActionExtension-iOS/Info.plist"; | |||
@@ -1103,7 +1109,7 @@ | |||
"@executable_path/Frameworks", | |||
"@executable_path/../../Frameworks", | |||
); | |||
MARKETING_VERSION = 1.0.16; | |||
MARKETING_VERSION = 1.0.17; | |||
PRODUCT_BUNDLE_IDENTIFIER = "com.abunchtell.WriteFreely-MultiPlatform.ActionExtension-iOS"; | |||
PRODUCT_NAME = "$(TARGET_NAME)"; | |||
SDKROOT = iphoneos; | |||
@@ -1234,7 +1240,7 @@ | |||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; | |||
CODE_SIGN_ENTITLEMENTS = "WriteFreely-MultiPlatform (iOS).entitlements"; | |||
CODE_SIGN_STYLE = Automatic; | |||
CURRENT_PROJECT_VERSION = 704; | |||
CURRENT_PROJECT_VERSION = 706; | |||
DEVELOPMENT_TEAM = TPPAB4YBA6; | |||
ENABLE_PREVIEWS = YES; | |||
INFOPLIST_FILE = iOS/Info.plist; | |||
@@ -1243,7 +1249,7 @@ | |||
"$(inherited)", | |||
"@executable_path/Frameworks", | |||
); | |||
MARKETING_VERSION = 1.0.16; | |||
MARKETING_VERSION = 1.0.17; | |||
PRODUCT_BUNDLE_IDENTIFIER = "com.abunchtell.WriteFreely-MultiPlatform"; | |||
PRODUCT_NAME = "WriteFreely-MultiPlatform"; | |||
SDKROOT = iphoneos; | |||
@@ -1260,7 +1266,7 @@ | |||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; | |||
CODE_SIGN_ENTITLEMENTS = "WriteFreely-MultiPlatform (iOS).entitlements"; | |||
CODE_SIGN_STYLE = Automatic; | |||
CURRENT_PROJECT_VERSION = 704; | |||
CURRENT_PROJECT_VERSION = 706; | |||
DEVELOPMENT_TEAM = TPPAB4YBA6; | |||
ENABLE_PREVIEWS = YES; | |||
INFOPLIST_FILE = iOS/Info.plist; | |||
@@ -1269,7 +1275,7 @@ | |||
"$(inherited)", | |||
"@executable_path/Frameworks", | |||
); | |||
MARKETING_VERSION = 1.0.16; | |||
MARKETING_VERSION = 1.0.17; | |||
PRODUCT_BUNDLE_IDENTIFIER = "com.abunchtell.WriteFreely-MultiPlatform"; | |||
PRODUCT_NAME = "WriteFreely-MultiPlatform"; | |||
SDKROOT = iphoneos; | |||
@@ -50,7 +50,10 @@ struct PostEditorView: View { | |||
PostEditorStatusToolbarView(post: post) | |||
} | |||
ToolbarItem(placement: .primaryAction) { | |||
if model.isProcessingRequest { | |||
if !model.hasNetworkConnection { | |||
Image(systemName: "wifi.exclamationmark") | |||
.foregroundColor(.secondary) | |||
} else if model.isProcessingRequest { | |||
ProgressView() | |||
} else { | |||
Menu(content: { | |||
@@ -115,6 +115,7 @@ final class CustomTextView: NSView { | |||
let scrollView = NSScrollView() | |||
scrollView.drawsBackground = false | |||
scrollView.borderType = .noBorder | |||
scrollView.autohidesScrollers = true | |||
scrollView.hasVerticalScroller = true | |||
scrollView.hasHorizontalRuler = false | |||
scrollView.autoresizingMask = [.width, .height] | |||
@@ -167,6 +168,8 @@ final class CustomTextView: NSView { | |||
.font: font ?? NSFont.systemFont(ofSize: 17), // Fall back to system font if we can't unwrap font argument | |||
.foregroundColor: NSColor.labelColor | |||
] | |||
textView.textContainer?.lineFragmentPadding = 16 | |||
textView.textContainerInset = NSSize(width: 0, height: 16) | |||
return textView | |||
}() | |||
@@ -9,65 +9,72 @@ struct PostEditorView: View { | |||
@State private var updatingFromServer: Bool = false | |||
var body: some View { | |||
PostTextEditingView( | |||
post: post, | |||
updatingFromServer: $updatingFromServer | |||
) | |||
.padding() | |||
.background(Color(NSColor.controlBackgroundColor)) | |||
.onAppear(perform: { | |||
model.editor.setInitialValues(for: post) | |||
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() | |||
VStack { | |||
if !model.hasNetworkConnection { | |||
Label("You are not connected to the internet", systemImage: "wifi.exclamationmark") | |||
.font(.caption) | |||
.foregroundColor(.secondary) | |||
.padding(.top, 8) | |||
} | |||
DispatchQueue.main.async { | |||
LocalStorageManager.standard.saveContext() | |||
} | |||
}) | |||
.onChange(of: model.hasError) { value in | |||
if value { | |||
if let error = model.currentError { | |||
self.errorHandling.handle(error: error) | |||
PostTextEditingView( | |||
post: post, | |||
updatingFromServer: $updatingFromServer | |||
) | |||
.background(Color(NSColor.controlBackgroundColor)) | |||
.onAppear(perform: { | |||
model.editor.setInitialValues(for: post) | |||
if post.status != PostStatus.published.rawValue { | |||
DispatchQueue.main.async { | |||
self.model.editor.saveLastDraft(post) | |||
} | |||
} else { | |||
self.errorHandling.handle(error: AppError.genericError()) | |||
self.model.editor.clearLastDraft() | |||
} | |||
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) | |||
}) | |||
.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() | |||
} | |||
} else if post.status != PostStatus.published.rawValue { | |||
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() | |||
} | |||
} | |||
}) | |||
} | |||
} | |||
} | |||
@@ -15,7 +15,8 @@ struct PostTextEditingView: View { | |||
if combinedText.count == 0 { | |||
Text("Write…") | |||
.foregroundColor(Color(NSColor.placeholderTextColor)) | |||
.padding(.horizontal, 5) | |||
.padding(.horizontal, 16) | |||
.padding(.vertical, 16) | |||
.font(.custom(appearance.rawValue, size: 17, relativeTo: .body)) | |||
} | |||
if post.appearance == "sans" { | |||