Page MenuHomeMusing Studio

No OneTemporary

diff --git a/macOS/PostEditor/MacEditorTextView.swift b/macOS/PostEditor/MacEditorTextView.swift
index 6bdac42..852c38a 100644
--- a/macOS/PostEditor/MacEditorTextView.swift
+++ b/macOS/PostEditor/MacEditorTextView.swift
@@ -1,203 +1,203 @@
// Based on:
//
// MacEditorTextView
// Copyright (c) Thiago Holanda 2020
// https://twitter.com/tholanda
//
// MIT license
//
// See: https://gist.github.com/unnamedd/6e8c3fbc806b8deb60fa65d6b9affab0
import Combine
import SwiftUI
struct MacEditorTextView: NSViewRepresentable {
@Binding var text: String
var isFirstResponder: Bool = false
var isEditable: Bool = true
- var font: NSFont? = .systemFont(ofSize: 14, weight: .regular)
+ var font: NSFont? = NSFont(name: PostAppearance.serif.rawValue, size: 17)
var onEditingChanged: () -> Void = {}
var onCommit: () -> Void = {}
var onTextChange: (String) -> Void = { _ in }
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeNSView(context: Context) -> CustomTextView {
let textView = CustomTextView(
text: text,
isEditable: isEditable,
isFirstResponder: isFirstResponder,
font: font
)
textView.delegate = context.coordinator
return textView
}
func updateNSView(_ view: CustomTextView, context: Context) {
view.text = text
view.selectedRanges = context.coordinator.selectedRanges
}
}
// MARK: - Coordinator
extension MacEditorTextView {
class Coordinator: NSObject, NSTextViewDelegate {
var parent: MacEditorTextView
var selectedRanges: [NSValue] = []
var didBecomeFirstResponder: Bool = false
init(_ parent: MacEditorTextView) {
self.parent = parent
}
func textDidBeginEditing(_ notification: Notification) {
guard let textView = notification.object as? NSTextView else {
return
}
self.parent.text = textView.string
self.parent.onEditingChanged()
}
func textDidChange(_ notification: Notification) {
guard let textView = notification.object as? NSTextView else {
return
}
self.parent.text = textView.string
self.selectedRanges = textView.selectedRanges
self.parent.onTextChange(textView.string)
}
func textDidEndEditing(_ notification: Notification) {
guard let textView = notification.object as? NSTextView else {
return
}
self.parent.text = textView.string
self.parent.onCommit()
}
}
}
// MARK: - CustomTextView
final class CustomTextView: NSView {
private var isFirstResponder: Bool
private var isEditable: Bool
private var font: NSFont?
weak var delegate: NSTextViewDelegate?
var text: String {
didSet {
textView.string = text
}
}
var selectedRanges: [NSValue] = [] {
didSet {
guard selectedRanges.count > 0 else {
return
}
textView.selectedRanges = selectedRanges
}
}
private lazy var scrollView: NSScrollView = {
let scrollView = NSScrollView()
scrollView.drawsBackground = false
scrollView.borderType = .noBorder
scrollView.hasVerticalScroller = true
scrollView.hasHorizontalRuler = false
scrollView.autoresizingMask = [.width, .height]
scrollView.translatesAutoresizingMaskIntoConstraints = false
return scrollView
}()
private lazy var textView: NSTextView = {
let contentSize = scrollView.contentSize
let textStorage = NSTextStorage()
let layoutManager = NSLayoutManager()
textStorage.addLayoutManager(layoutManager)
let textContainer = NSTextContainer(containerSize: scrollView.frame.size)
textContainer.widthTracksTextView = true
textContainer.containerSize = NSSize(
width: contentSize.width,
height: CGFloat.greatestFiniteMagnitude
)
layoutManager.addTextContainer(textContainer)
let textView = NSTextView(frame: .zero, textContainer: textContainer)
textView.autoresizingMask = .width
textView.delegate = self.delegate
textView.drawsBackground = false
textView.font = self.font
textView.isEditable = self.isEditable
textView.isHorizontallyResizable = false
textView.isVerticallyResizable = true
textView.maxSize = NSSize(
width: CGFloat.greatestFiniteMagnitude,
height: CGFloat.greatestFiniteMagnitude
)
textView.minSize = NSSize(width: 0, height: contentSize.height)
textView.textColor = NSColor.labelColor
return textView
}()
// MARK: - Init
init(text: String, isEditable: Bool, isFirstResponder: Bool, font: NSFont?) {
self.font = font
self.isFirstResponder = isFirstResponder
self.isEditable = isEditable
self.text = text
super.init(frame: .zero)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - Life cycle
override func viewWillDraw() {
super.viewWillDraw()
setupScrollViewConstraints()
setupTextView()
if isFirstResponder {
self.window?.makeFirstResponder(self.textView)
}
}
func setupScrollViewConstraints() {
scrollView.translatesAutoresizingMaskIntoConstraints = false
addSubview(scrollView)
NSLayoutConstraint.activate([
scrollView.topAnchor.constraint(equalTo: topAnchor),
scrollView.trailingAnchor.constraint(equalTo: trailingAnchor),
scrollView.bottomAnchor.constraint(equalTo: bottomAnchor),
scrollView.leadingAnchor.constraint(equalTo: leadingAnchor)
])
}
func setupTextView() {
scrollView.documentView = textView
}
}
diff --git a/macOS/PostEditor/PostEditorView.swift b/macOS/PostEditor/PostEditorView.swift
index 400bc3c..73a9acd 100644
--- a/macOS/PostEditor/PostEditorView.swift
+++ b/macOS/PostEditor/PostEditorView.swift
@@ -1,100 +1,98 @@
import SwiftUI
struct PostEditorView: View {
private let bodyLineSpacing: CGFloat = 17 * 0.5
@EnvironmentObject var model: WriteFreelyModel
@ObservedObject var post: WFAPost
@State private var isHovering: Bool = false
- @State private var updatingTitleFromServer: Bool = false
- @State private var updatingBodyFromServer: Bool = false
+ @State private var updatingFromServer: Bool = false
var body: some View {
PostTextEditingView(
post: post,
- updatingTitleFromServer: $updatingTitleFromServer,
- updatingBodyFromServer: $updatingBodyFromServer
+ updatingFromServer: $updatingFromServer
)
.padding()
.background(Color(NSColor.controlBackgroundColor))
.toolbar {
ToolbarItem(placement: .status) {
PostEditorStatusToolbarView(post: post)
}
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.status == PostStatus.edited.rawValue && !post.hasNewerRemoteCopy {
post.status = PostStatus.published.rawValue
}
})
.onDisappear(perform: {
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)
}
}
}
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)
}
}
diff --git a/macOS/PostEditor/PostTextEditingView.swift b/macOS/PostEditor/PostTextEditingView.swift
index c2864c0..3b7115b 100644
--- a/macOS/PostEditor/PostTextEditingView.swift
+++ b/macOS/PostEditor/PostTextEditingView.swift
@@ -1,124 +1,133 @@
import SwiftUI
struct PostTextEditingView: View {
@ObservedObject var post: WFAPost
- @Binding var updatingTitleFromServer: Bool
- @Binding var updatingBodyFromServer: Bool
- @State private var isHovering: Bool = false
+ @Binding var updatingFromServer: Bool
@State private var appearance: PostAppearance = .serif
@State private var combinedText = ""
var body: some View {
// VStack {
// TextField("Title (optional)", text: $post.title)
// .textFieldStyle(PlainTextFieldStyle())
// .padding(.horizontal, 4)
// .font(.custom(appearance.rawValue, size: 26, relativeTo: .largeTitle))
// .onChange(of: post.title) { _ in
// if post.status == PostStatus.published.rawValue && !updatingTitleFromServer {
// post.status = PostStatus.edited.rawValue
// }
// if updatingTitleFromServer {
// updatingTitleFromServer = false
// }
// }
// .padding(4)
// .background(Color(NSColor.controlBackgroundColor))
// .padding(.bottom)
// ZStack(alignment: .topLeading) {
// if post.body.count == 0 {
// Text("Write…")
// .foregroundColor(Color(NSColor.placeholderTextColor))
// .padding(.horizontal, 4)
// .padding(.vertical, 2)
// .font(.custom(appearance.rawValue, size: 17, relativeTo: .body))
// }
// TextEditor(text: $post.body)
// .font(.custom(appearance.rawValue, size: 17, relativeTo: .body))
// .opacity(post.body.count == 0 && !isHovering ? 0.0 : 1.0)
// .onChange(of: post.body) { _ in
// if post.status == PostStatus.published.rawValue && !updatingBodyFromServer {
// post.status = PostStatus.edited.rawValue
// }
// if updatingBodyFromServer {
// updatingBodyFromServer = false
// }
// }
// .onHover(perform: { hovering in
// self.isHovering = hovering
// })
// }
// .padding(4)
// .background(Color(NSColor.controlBackgroundColor))
// }
ZStack(alignment: .topLeading) {
if combinedText.count == 0 {
Text("Write…")
.foregroundColor(Color(NSColor.placeholderTextColor))
.padding(.horizontal, 5)
.font(.custom(appearance.rawValue, size: 17, relativeTo: .body))
}
- MacEditorTextView(
- text: $combinedText,
- isFirstResponder: combinedText.isEmpty,
- isEditable: true,
- font: NSFont(name: appearance.rawValue, size: 17),
- onEditingChanged: onEditingChanged,
- onCommit: onCommit,
- onTextChange: onTextChange
- )
+ if post.appearance == "sans" {
+ MacEditorTextView(
+ text: $combinedText,
+ isFirstResponder: combinedText.isEmpty,
+ isEditable: true,
+ font: NSFont(name: "OpenSans-Regular", size: 17),
+ onEditingChanged: onEditingChanged,
+ onCommit: onCommit,
+ onTextChange: onTextChange
+ )
+ } else if post.appearance == "wrap" || post.appearance == "mono" || post.appearance == "code" {
+ MacEditorTextView(
+ text: $combinedText,
+ isFirstResponder: combinedText.isEmpty,
+ isEditable: true,
+ font: NSFont(name: "Hack-Regular", size: 17),
+ onEditingChanged: onEditingChanged,
+ onCommit: onCommit,
+ onTextChange: onTextChange
+ )
+ } else {
+ MacEditorTextView(
+ text: $combinedText,
+ isFirstResponder: combinedText.isEmpty,
+ isEditable: true,
+ font: NSFont(name: "Lora-Regular", size: 17),
+ onEditingChanged: onEditingChanged,
+ onCommit: onCommit,
+ onTextChange: onTextChange
+ )
+ }
}
.background(Color(NSColor.controlBackgroundColor))
.onAppear(perform: {
- switch post.appearance {
- case "sans":
- self.appearance = .sans
- case "wrap", "mono", "code":
- self.appearance = .mono
- default:
- self.appearance = .serif
- }
- print("Font: \(appearance.rawValue)")
-
if post.title.isEmpty {
self.combinedText = post.body
} else {
self.combinedText = "# \(post.title)\n\n\(post.body)"
}
})
}
private func onEditingChanged() {
print("onEditingChanged fired")
}
private func onTextChange(_ text: String) {
- print("onTextChange fired")
extractTitle(text)
}
private func onCommit() {
print("onCommit fired")
}
private func extractTitle(_ text: String) {
var detectedTitle: String
if text.hasPrefix("# ") {
let endOfTitleIndex = text.firstIndex(of: "\n") ?? text.endIndex
detectedTitle = String(text[..<endOfTitleIndex])
self.post.title = String(detectedTitle.dropFirst("# ".count))
let remainingText = String(text.dropFirst(detectedTitle.count).dropFirst(1))
if remainingText.hasPrefix("\n") {
self.post.body = String(remainingText.dropFirst(1))
} else {
self.post.body = remainingText
}
} else {
self.post.title = ""
self.post.body = text
}
}
}

File Metadata

Mime Type
text/x-diff
Expires
Thu, Mar 12, 8:01 AM (9 h, 57 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3653350

Event Timeline