Page MenuHomeMusing Studio

No OneTemporary

diff --git a/Shared/PostEditor/PostEditorStatusToolbarView.swift b/Shared/PostEditor/PostEditorStatusToolbarView.swift
index e76e2b1..580e051 100644
--- a/Shared/PostEditor/PostEditorStatusToolbarView.swift
+++ b/Shared/PostEditor/PostEditorStatusToolbarView.swift
@@ -1,152 +1,88 @@
import SwiftUI
struct PostEditorStatusToolbarView: View {
- #if os(iOS)
- @Environment(\.horizontalSizeClass) var horizontalSizeClass
- @Environment(\.presentationMode) var presentationMode
- #endif
@EnvironmentObject var model: WriteFreelyModel
@ObservedObject var post: WFAPost
var body: some View {
if post.hasNewerRemoteCopy {
#if os(iOS)
- if horizontalSizeClass == .compact {
- VStack {
- PostStatusBadgeView(post: post)
- HStack {
- Text("⚠️ Newer copy on server. Replace local copy?")
- .font(.caption)
- .foregroundColor(.secondary)
- Button(action: {
- model.updateFromServer(post: post)
- }, label: {
- Image(systemName: "square.and.arrow.down")
- })
- }
- .padding(.bottom)
- }
- .padding(.top)
- } else {
- HStack {
- 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")
- })
- }
- }
+ PostStatusBadgeView(post: post)
#else
HStack {
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 {
#if os(iOS)
- if horizontalSizeClass == .compact {
- VStack {
- PostStatusBadgeView(post: post)
- HStack {
- Text("‼️ Post deleted from server. Delete local copy?")
- .font(.caption)
- .foregroundColor(.secondary)
- Button(action: {
- self.presentationMode.wrappedValue.dismiss()
- model.selectedPost = nil
- model.posts.remove(post)
- }, label: {
- Image(systemName: "trash")
- })
- }
- .padding(.bottom)
- }
- .padding(.top)
- } else {
- HStack {
- PostStatusBadgeView(post: post)
- .padding(.trailing)
- Text("‼️ Post deleted from server. Delete local copy?")
- .font(.callout)
- .foregroundColor(.secondary)
- Button(action: {
- self.presentationMode.wrappedValue.dismiss()
- model.selectedPost = nil
- model.posts.remove(post)
- }, label: {
- Image(systemName: "trash")
- })
- }
- }
+ PostStatusBadgeView(post: post)
#else
HStack {
PostStatusBadgeView(post: post)
.padding(.trailing)
- Text("‼️ Post deleted from server. Delete local copy?")
+ Text("⚠️ Post deleted from server. Delete local copy?")
.font(.callout)
.foregroundColor(.secondary)
Button(action: {
model.selectedPost = nil
- model.posts.remove(post)
+ DispatchQueue.main.async {
+ model.posts.remove(post)
+ }
}, label: {
Image(systemName: "trash")
})
}
#endif
} else {
PostStatusBadgeView(post: post)
}
}
}
struct PESTView_StandardPreviews: PreviewProvider {
static var previews: some View {
let context = LocalStorageManager.persistentContainer.viewContext
let model = WriteFreelyModel()
let testPost = WFAPost(context: context)
testPost.status = PostStatus.published.rawValue
return PostEditorStatusToolbarView(post: testPost)
.environmentObject(model)
}
}
struct PESTView_OutdatedLocalCopyPreviews: PreviewProvider {
static var previews: some View {
let context = LocalStorageManager.persistentContainer.viewContext
let model = WriteFreelyModel()
let updatedPost = WFAPost(context: context)
updatedPost.status = PostStatus.published.rawValue
updatedPost.hasNewerRemoteCopy = true
return PostEditorStatusToolbarView(post: updatedPost)
.environmentObject(model)
}
}
struct PESTView_DeletedRemoteCopyPreviews: PreviewProvider {
static var previews: some View {
let context = LocalStorageManager.persistentContainer.viewContext
let model = WriteFreelyModel()
let deletedPost = WFAPost(context: context)
deletedPost.status = PostStatus.published.rawValue
deletedPost.wasDeletedFromServer = true
return PostEditorStatusToolbarView(post: deletedPost)
.environmentObject(model)
}
}
diff --git a/iOS/PostEditor/PostEditorView.swift b/iOS/PostEditor/PostEditorView.swift
index 2994cd2..884d9f8 100644
--- a/iOS/PostEditor/PostEditorView.swift
+++ b/iOS/PostEditor/PostEditorView.swift
@@ -1,180 +1,243 @@
import SwiftUI
struct PostEditorView: View {
@EnvironmentObject var model: WriteFreelyModel
-
+ @Environment(\.horizontalSizeClass) var horizontalSizeClass
+ @Environment(\.presentationMode) var presentationMode
@ObservedObject var post: WFAPost
var body: some View {
VStack {
+ if post.hasNewerRemoteCopy {
+ HStack {
+ Text("⚠️ Newer copy on server. Replace local copy?")
+ .font(horizontalSizeClass == .compact ? .caption : .body)
+ .foregroundColor(.secondary)
+ Button(action: {
+ model.updateFromServer(post: post)
+ }, label: {
+ Image(systemName: "square.and.arrow.down")
+ })
+ }
+ .padding(EdgeInsets(top: 10, leading: 20, bottom: 10, trailing: 20))
+ .background(Color(UIColor.secondarySystemBackground))
+ .clipShape(Capsule())
+ .padding(.bottom)
+ } else if post.wasDeletedFromServer {
+ HStack {
+ Text("⚠️ Post deleted from server. Delete local copy?")
+ .font(horizontalSizeClass == .compact ? .caption : .body)
+ .foregroundColor(.secondary)
+ Button(action: {
+ self.presentationMode.wrappedValue.dismiss()
+ DispatchQueue.main.async {
+ model.posts.remove(post)
+ }
+ }, label: {
+ Image(systemName: "trash")
+ })
+ }
+ .padding(EdgeInsets(top: 10, leading: 20, bottom: 10, trailing: 20))
+ .background(Color(UIColor.secondarySystemBackground))
+ .clipShape(Capsule())
+ .padding(.bottom)
+ }
switch post.appearance {
case "sans":
TextField("Title (optional)", text: $post.title)
.font(.custom("OpenSans-Regular", size: 26, relativeTo: Font.TextStyle.largeTitle))
.onChange(of: post.title) { _ in
if post.status == PostStatus.published.rawValue {
post.status = PostStatus.edited.rawValue
}
}
ZStack(alignment: .topLeading) {
if post.body.count == 0 {
Text("Write...")
.foregroundColor(Color(UIColor.placeholderText))
.padding(.horizontal, 4)
.padding(.vertical, 8)
.font(.custom("OpenSans-Regular", size: 17, relativeTo: Font.TextStyle.body))
}
TextEditor(text: $post.body)
.font(.custom("OpenSans-Regular", size: 17, relativeTo: Font.TextStyle.body))
.onChange(of: post.body) { _ in
if post.status == PostStatus.published.rawValue {
post.status = PostStatus.edited.rawValue
}
}
}
case "wrap", "mono", "code":
TextField("Title (optional)", text: $post.title)
.font(.custom("Hack", size: 26, relativeTo: Font.TextStyle.largeTitle))
.onChange(of: post.title) { _ in
if post.status == PostStatus.published.rawValue {
post.status = PostStatus.edited.rawValue
}
}
ZStack(alignment: .topLeading) {
if post.body.count == 0 {
Text("Write...")
.foregroundColor(Color(UIColor.placeholderText))
.padding(.horizontal, 4)
.padding(.vertical, 8)
.font(.custom("Hack", size: 17, relativeTo: Font.TextStyle.body))
}
TextEditor(text: $post.body)
.font(.custom("Hack", size: 17, relativeTo: Font.TextStyle.body))
.onChange(of: post.body) { _ in
if post.status == PostStatus.published.rawValue {
post.status = PostStatus.edited.rawValue
}
}
}
default:
TextField("Title (optional)", text: $post.title)
.font(.custom("Lora", size: 26, relativeTo: Font.TextStyle.largeTitle))
.onChange(of: post.title) { _ in
if post.status == PostStatus.published.rawValue {
post.status = PostStatus.edited.rawValue
}
}
ZStack(alignment: .topLeading) {
if post.body.count == 0 {
Text("Write...")
.foregroundColor(Color(UIColor.placeholderText))
.padding(.horizontal, 4)
.padding(.vertical, 8)
.font(.custom("Lora", size: 17, relativeTo: Font.TextStyle.body))
}
TextEditor(text: $post.body)
.font(.custom("Lora", size: 17, relativeTo: Font.TextStyle.body))
.onChange(of: post.body) { _ in
if post.status == PostStatus.published.rawValue {
post.status = PostStatus.edited.rawValue
}
}
}
}
}
.navigationBarTitleDisplayMode(.inline)
.padding()
.toolbar {
ToolbarItem(placement: .principal) {
PostEditorStatusToolbarView(post: post)
}
- ToolbarItem(placement: .primaryAction) {
+ ToolbarItemGroup(placement: .navigationBarTrailing) {
Button(action: {
publishPost()
}, label: {
Image(systemName: "paperplane")
})
.disabled(
post.status == PostStatus.published.rawValue ||
!model.account.isLoggedIn ||
!model.hasNetworkConnection
)
+ Button(action: {
+ sharePost()
+ }, label: {
+ Image(systemName: "square.and.arrow.up")
+ })
+ .disabled(post.postId == nil)
}
}
.onChange(of: post.hasNewerRemoteCopy, perform: { _ in
if post.status == PostStatus.edited.rawValue && !post.hasNewerRemoteCopy {
post.status = PostStatus.published.rawValue
}
})
.onChange(of: post.status, perform: { _ in
if post.status != PostStatus.published.rawValue {
DispatchQueue.main.async {
model.editor.setLastDraft(post)
}
} else {
DispatchQueue.main.async {
model.editor.clearLastDraft()
}
}
})
.onDisappear(perform: {
if post.title.count == 0
&& post.body.count == 0
&& post.status == PostStatus.local.rawValue
&& post.updatedDate == nil
&& post.postId == nil {
- withAnimation {
+ DispatchQueue.main.async {
model.posts.remove(post)
model.posts.loadCachedPosts()
}
} else if post.status != PostStatus.published.rawValue {
DispatchQueue.main.async {
LocalStorageManager().saveContext()
}
}
})
}
private func publishPost() {
DispatchQueue.main.async {
LocalStorageManager().saveContext()
model.posts.loadCachedPosts()
model.publish(post: post)
}
#if os(iOS)
self.hideKeyboard()
#endif
}
+
+ private func sharePost() {
+ guard let urlString = model.selectedPost?.slug != nil ?
+ "\(model.account.server)/\((model.selectedPost?.collectionAlias)!)/\((model.selectedPost?.slug)!)" :
+ "\(model.account.server)/\((model.selectedPost?.postId)!)" else { return }
+ 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)
}
}
diff --git a/macOS/PostEditor/PostEditorView.swift b/macOS/PostEditor/PostEditorView.swift
index 9fb1e34..3ba7381 100644
--- a/macOS/PostEditor/PostEditorView.swift
+++ b/macOS/PostEditor/PostEditorView.swift
@@ -1,199 +1,199 @@
import SwiftUI
struct PostEditorView: View {
@EnvironmentObject var model: WriteFreelyModel
@ObservedObject var post: WFAPost
@State private var isHovering: Bool = false
var body: some View {
VStack {
switch post.appearance {
case "sans":
TextField("Title (optional)", text: $post.title)
.textFieldStyle(PlainTextFieldStyle())
.padding(.bottom)
.font(.custom("OpenSans-Regular", size: 26, relativeTo: Font.TextStyle.largeTitle))
.onChange(of: post.title) { _ in
if post.status == PostStatus.published.rawValue {
post.status = PostStatus.edited.rawValue
}
}
ZStack(alignment: .topLeading) {
if post.body.count == 0 {
Text("Write...")
.foregroundColor(Color(NSColor.placeholderTextColor))
.padding(.horizontal, 4)
.padding(.vertical, 2)
.font(.custom("OpenSans-Regular", size: 17, relativeTo: Font.TextStyle.body))
}
TextEditor(text: $post.body)
.font(.custom("OpenSans-Regular", size: 17, relativeTo: Font.TextStyle.body))
.opacity(post.body.count == 0 && !isHovering ? 0.0 : 1.0)
.onChange(of: post.body) { _ in
if post.status == PostStatus.published.rawValue {
post.status = PostStatus.edited.rawValue
}
}
.onHover(perform: { hovering in
self.isHovering = hovering
})
}
.background(Color(NSColor.controlBackgroundColor))
case "wrap", "mono", "code":
TextField("Title (optional)", text: $post.title)
.textFieldStyle(PlainTextFieldStyle())
.padding(.bottom)
.font(.custom("Hack", size: 26, relativeTo: Font.TextStyle.largeTitle))
.onChange(of: post.title) { _ in
if post.status == PostStatus.published.rawValue {
post.status = PostStatus.edited.rawValue
}
}
ZStack(alignment: .topLeading) {
if post.body.count == 0 {
Text("Write...")
.foregroundColor(Color(NSColor.placeholderTextColor))
.padding(.horizontal, 4)
.padding(.vertical, 2)
.font(.custom("Hack", size: 17, relativeTo: Font.TextStyle.body))
}
TextEditor(text: $post.body)
.font(.custom("Hack", size: 17, relativeTo: Font.TextStyle.body))
.opacity(post.body.count == 0 && !isHovering ? 0.0 : 1.0)
.onChange(of: post.body) { _ in
if post.status == PostStatus.published.rawValue {
post.status = PostStatus.edited.rawValue
}
}
.onHover(perform: { hovering in
self.isHovering = hovering
})
}
.background(Color(NSColor.controlBackgroundColor))
default:
TextField("Title (optional)", text: $post.title)
.textFieldStyle(PlainTextFieldStyle())
.padding(.bottom)
.font(.custom("Lora", size: 26, relativeTo: Font.TextStyle.largeTitle))
.onChange(of: post.title) { _ in
if post.status == PostStatus.published.rawValue {
post.status = PostStatus.edited.rawValue
}
}
ZStack(alignment: .topLeading) {
if post.body.count == 0 {
Text("Write...")
.foregroundColor(Color(NSColor.placeholderTextColor))
.padding(.horizontal, 4)
.padding(.vertical, 2)
.font(.custom("Lora", size: 17, relativeTo: Font.TextStyle.body))
}
TextEditor(text: $post.body)
.font(.custom("Lora", size: 17, relativeTo: Font.TextStyle.body))
.opacity(post.body.count == 0 && !isHovering ? 0.0 : 1.0)
.onChange(of: post.body) { _ in
if post.status == PostStatus.published.rawValue {
post.status = PostStatus.edited.rawValue
}
}
.onHover(perform: { hovering in
self.isHovering = hovering
})
}
.background(Color(NSColor.controlBackgroundColor))
}
}
.padding()
.background(Color.white)
.toolbar {
ToolbarItem(placement: .status) {
PostEditorStatusToolbarView(post: post)
}
ToolbarItem(placement: .primaryAction) {
Button(action: {
publishPost()
}, label: {
Image(systemName: "paperplane")
})
.disabled(
post.status == PostStatus.published.rawValue ||
!model.account.isLoggedIn ||
!model.hasNetworkConnection
)
}
}
.onChange(of: post.hasNewerRemoteCopy, perform: { _ in
if post.status == PostStatus.edited.rawValue && !post.hasNewerRemoteCopy {
post.status = PostStatus.published.rawValue
}
})
.onChange(of: post.status, perform: { _ in
if post.status != PostStatus.published.rawValue {
DispatchQueue.main.async {
model.editor.setLastDraft(post)
}
} else {
DispatchQueue.main.async {
model.editor.clearLastDraft()
}
}
})
.onDisappear(perform: {
if post.title.count == 0
&& post.body.count == 0
&& post.status == PostStatus.local.rawValue
&& post.updatedDate == nil
&& post.postId == nil {
- withAnimation {
+ DispatchQueue.main.async {
model.posts.remove(post)
model.posts.loadCachedPosts()
}
} else if post.status != PostStatus.published.rawValue {
DispatchQueue.main.async {
LocalStorageManager().saveContext()
}
}
})
}
private func publishPost() {
DispatchQueue.main.async {
LocalStorageManager().saveContext()
model.posts.loadCachedPosts()
model.publish(post: post)
}
}
}
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"
let model = WriteFreelyModel()
return PostEditorView(post: testPost)
.environment(\.managedObjectContext, context)
.environmentObject(model)
}
}

File Metadata

Mime Type
text/x-diff
Expires
Sat, Jan 31, 10:32 AM (1 d, 10 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3612269

Event Timeline