Use PostBodyTitleView and PostBodyTextView for post editor

This commit is contained in:
Angelo Stavrow 2020-10-27 16:02:28 -04:00
parent 86cf0e976d
commit 3becfcbf73
No known key found for this signature in database
GPG Key ID: 1A49C7064E060EEE
4 changed files with 74 additions and 29 deletions

View File

@ -3,8 +3,8 @@ import CoreData
enum PostAppearance: String { enum PostAppearance: String {
case sans = "OpenSans-Regular" case sans = "OpenSans-Regular"
case mono = "Hack" case mono = "Hack-Regular"
case serif = "Lora" case serif = "Lora-Regular"
} }
struct PostEditorModel { struct PostEditorModel {

View File

@ -24,6 +24,7 @@ struct PostBodyTextView: UIViewRepresentable {
@Binding var text: String @Binding var text: String
@Binding var textStyle: UIFont @Binding var textStyle: UIFont
@Binding var isFirstResponder: Bool @Binding var isFirstResponder: Bool
var lineSpacing: CGFloat
func makeUIView(context: UIViewRepresentableContext<PostBodyTextView>) -> UITextView { func makeUIView(context: UIViewRepresentableContext<PostBodyTextView>) -> UITextView {
let textView = UITextView(frame: .zero) let textView = UITextView(frame: .zero)
@ -40,7 +41,16 @@ struct PostBodyTextView: UIViewRepresentable {
} }
func updateUIView(_ uiView: UITextView, context: UIViewRepresentableContext<PostBodyTextView>) { func updateUIView(_ uiView: UITextView, context: UIViewRepresentableContext<PostBodyTextView>) {
uiView.text = text let attributedString = NSMutableAttributedString(string: text)
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = lineSpacing
attributedString.addAttribute(
NSAttributedString.Key.paragraphStyle,
value: paragraphStyle,
range: NSMakeRange(0, attributedString.length) // swiftlint:disable:this legacy_constructor
)
uiView.attributedText = attributedString
let font = textStyle let font = textStyle
let fontMetrics = UIFontMetrics(forTextStyle: .largeTitle) let fontMetrics = UIFontMetrics(forTextStyle: .largeTitle)
uiView.font = fontMetrics.scaledFont(for: font) uiView.font = fontMetrics.scaledFont(for: font)

View File

@ -6,6 +6,11 @@ struct PostTextEditingView: View {
@Binding var updatingTitleFromServer: Bool @Binding var updatingTitleFromServer: Bool
@Binding var updatingBodyFromServer: Bool @Binding var updatingBodyFromServer: Bool
@State private var appearance: PostAppearance = .serif @State private var appearance: PostAppearance = .serif
@State private var titleTextStyle: UIFont = UIFont(name: "Lora-Regular", size: 26)!
@State private var titleTextHeight: CGFloat = 50
@State private var titleIsFirstResponder: Bool = true
@State private var bodyTextStyle: UIFont = UIFont(name: "Lora-Regular", size: 17)!
@State private var bodyIsFirstResponder: Bool = false
private let bodyLineSpacingMultiplier: CGFloat = 0.5 private let bodyLineSpacingMultiplier: CGFloat = 0.5
init( init(
@ -19,41 +24,69 @@ struct PostTextEditingView: View {
UITextView.appearance().backgroundColor = .clear UITextView.appearance().backgroundColor = .clear
} }
var titleFieldHeight: CGFloat {
let minHeight: CGFloat = 50
if titleTextHeight < minHeight {
return minHeight
}
return titleTextHeight
}
var body: some View { var body: some View {
VStack { VStack {
TextField("Title (optional)", text: $post.title)
.font(.custom(appearance.rawValue, size: 26, relativeTo: .largeTitle))
.padding(.horizontal, 4)
.onChange(of: post.title) { _ in
if post.status == PostStatus.published.rawValue && !updatingTitleFromServer {
post.status = PostStatus.edited.rawValue
}
}
ZStack(alignment: .topLeading) { ZStack(alignment: .topLeading) {
if post.body.count == 0 { if post.title.count == 0 {
Text("Write…") Text("Title (optional)")
.font(.custom(appearance.rawValue, size: 17, relativeTo: .body)) .font(Font(titleTextStyle))
.foregroundColor(Color(UIColor.placeholderText)) .foregroundColor(Color(UIColor.placeholderText))
.padding(.horizontal, 4) .padding(.horizontal, 4)
.padding(.vertical, 8) .padding(.vertical, 8)
} }
TextEditor(text: $post.body) PostTitleTextView(
.font(.custom(appearance.rawValue, size: 17, relativeTo: .body)) text: $post.title,
.lineSpacing( textStyle: $titleTextStyle,
17 * ( height: $titleTextHeight,
horizontalSizeClass == .compact ? bodyLineSpacingMultiplier / 2 : bodyLineSpacingMultiplier isFirstResponder: $titleIsFirstResponder
) )
) .frame(height: titleFieldHeight)
.onChange(of: post.body) { _ in .onChange(of: post.title) { _ in
if post.status == PostStatus.published.rawValue && !updatingBodyFromServer { if post.status == PostStatus.published.rawValue && !updatingTitleFromServer {
post.status = PostStatus.edited.rawValue post.status = PostStatus.edited.rawValue
}
if updatingBodyFromServer {
updatingBodyFromServer = false
}
} }
if updatingTitleFromServer {
updatingTitleFromServer = false
}
}
}
ZStack(alignment: .topLeading) {
if post.body.count == 0 {
Text("Write…")
.font(Font(bodyTextStyle))
.foregroundColor(Color(UIColor.placeholderText))
.padding(.horizontal, 4)
.padding(.vertical, 8)
}
PostBodyTextView(
text: $post.body,
textStyle: $bodyTextStyle,
isFirstResponder: $bodyIsFirstResponder,
lineSpacing: 17 * (
horizontalSizeClass == .compact ? bodyLineSpacingMultiplier / 2 : bodyLineSpacingMultiplier
)
)
.onChange(of: post.body) { _ in
if post.status == PostStatus.published.rawValue && !updatingBodyFromServer {
post.status = PostStatus.edited.rawValue
}
if updatingBodyFromServer {
updatingBodyFromServer = false
}
}
} }
} }
.onChange(of: titleIsFirstResponder, perform: { _ in
self.bodyIsFirstResponder.toggle()
})
.onAppear(perform: { .onAppear(perform: {
switch post.appearance { switch post.appearance {
case "sans": case "sans":
@ -63,6 +96,8 @@ struct PostTextEditingView: View {
default: default:
self.appearance = .serif self.appearance = .serif
} }
self.titleTextStyle = UIFont(name: appearance.rawValue, size: 26)!
self.bodyTextStyle = UIFont(name: appearance.rawValue, size: 17)!
}) })
} }
} }

View File

@ -24,7 +24,7 @@ class Coordinator: NSObject, UITextViewDelegate, NSLayoutManagerDelegate {
} }
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
if (text == "\n") { if text == "\n" {
self.isFirstResponder.toggle() self.isFirstResponder.toggle()
return false return false
} }