WIP Fix mentions when writing notes

This commit is contained in:
2023-03-25 22:52:20 -06:00
parent 9590166367
commit d946dbe50d
3 changed files with 48 additions and 18 deletions

View File

@@ -16,6 +16,7 @@ let POST_PLACEHOLDER = NSLocalizedString("Type your post here...", comment: "Tex
struct PostView: View {
@State var post: NSMutableAttributedString = NSMutableAttributedString()
@State var cursor: Int = 0
@FocusState var focus: Bool
@State var showPrivateKeyWarning: Bool = false
@State var attach_media: Bool = false
@@ -104,7 +105,7 @@ struct PostView: View {
var TextEntry: some View {
ZStack(alignment: .topLeading) {
TextViewWrapper(attributedText: $post)
TextViewWrapper(attributedText: $post, cursor: $cursor)
.focused($focus)
.textInputAutocapitalization(.sentences)
.onChange(of: post) { _ in
@@ -191,7 +192,7 @@ struct PostView: View {
var body: some View {
VStack(alignment: .leading, spacing: 0) {
let searching = get_searching_string(post.string)
let searching = get_searching_string(post.string, cursor: cursor)
TopBar
@@ -204,7 +205,7 @@ struct PostView: View {
// This if-block observes @ for tagging
if let searching {
UserSearch(damus_state: damus_state, search: searching, post: $post)
UserSearch(damus_state: damus_state, search: searching, post: $post, cursor: $cursor)
.frame(maxHeight: .infinity)
} else {
Divider()
@@ -253,8 +254,12 @@ struct PostView: View {
}
}
func get_searching_string(_ post: String) -> String? {
guard let last_word = post.components(separatedBy: .whitespacesAndNewlines).last else {
func get_searching_string(_ post: String, cursor: Int) -> String? {
guard cursor > 0 else {
return nil
}
guard let last_word = post[...post.index(post.startIndex, offsetBy: cursor - 1)].components(separatedBy: .whitespacesAndNewlines).last else {
return nil
}

View File

@@ -22,6 +22,7 @@ struct UserSearch: View {
let search: String
@Binding var post: NSMutableAttributedString
@Binding var cursor: Int
var users: [SearchedUser] {
guard let contacts = damus_state.contacts.event else {
@@ -36,38 +37,57 @@ struct UserSearch: View {
return
}
// Remove all characters after the last '@'
removeCharactersAfterLastAtSymbol()
// Remove all characters after the '@' and before the cursor
let newCursor = removeCharactersAfterAtSymbol()
// Create and append the user tag
let tagAttributedString = createUserTag(for: user, with: pk)
appendUserTag(tagAttributedString)
insertUserTag(tagAttributedString, cursor: newCursor)
cursor = newCursor
}
private func removeCharactersAfterLastAtSymbol() {
while post.string.last != "@" {
post.deleteCharacters(in: NSRange(location: post.length - 1, length: 1))
private func removeCharactersAfterAtSymbol() -> Int {
let newCursor = cursor
guard newCursor > 0 else {
return 0
}
post.deleteCharacters(in: NSRange(location: post.length - 1, length: 1))
var atSymbolOffset = newCursor
while atSymbolOffset > 0 && post.string[post.string.index(post.string.startIndex, offsetBy: atSymbolOffset - 1)] != "@" {
atSymbolOffset -= 1
}
var endOfWordOffset = newCursor
while endOfWordOffset < post.string.count && !post.string[post.string.index(post.string.startIndex, offsetBy: endOfWordOffset)].isWhitespace {
endOfWordOffset += 1
}
post.deleteCharacters(in: NSRange(location: atSymbolOffset - 1, length: endOfWordOffset - atSymbolOffset + 1))
return atSymbolOffset - 1
}
private func createUserTag(for user: SearchedUser, with pk: String) -> NSMutableAttributedString {
let name = Profile.displayName(profile: user.profile, pubkey: pk).username
let tagString = "@\(name)\u{200B} "
let tagString = "\u{200B}@\(name)\u{200B} "
let tagAttributedString = NSMutableAttributedString(string: tagString,
attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 18.0),
NSAttributedString.Key.link: "@\(pk)"])
tagAttributedString.removeAttribute(.link, range: NSRange(location: 0, length: 1))
tagAttributedString.removeAttribute(.link, range: NSRange(location: tagAttributedString.length - 2, length: 2))
tagAttributedString.addAttributes([NSAttributedString.Key.foregroundColor: UIColor.label], range: NSRange(location: 0, length: 1))
tagAttributedString.addAttributes([NSAttributedString.Key.foregroundColor: UIColor.label], range: NSRange(location: tagAttributedString.length - 2, length: 2))
return tagAttributedString
}
private func appendUserTag(_ tagAttributedString: NSMutableAttributedString) {
private func insertUserTag(_ tagAttributedString: NSMutableAttributedString, cursor: Int) {
let mutableString = NSMutableAttributedString()
mutableString.append(post)
mutableString.append(tagAttributedString)
mutableString.insert(tagAttributedString, at: cursor)
post = mutableString
}
@@ -88,9 +108,10 @@ struct UserSearch: View {
struct UserSearch_Previews: PreviewProvider {
static let search: String = "jb55"
@State static var post: NSMutableAttributedString = NSMutableAttributedString(string: "some @jb55")
@State static var cursor: Int = 0
static var previews: some View {
UserSearch(damus_state: test_damus_state(), search: search, post: $post)
UserSearch(damus_state: test_damus_state(), search: search, post: $post, cursor: $cursor)
}
}

View File

@@ -9,6 +9,7 @@ import SwiftUI
struct TextViewWrapper: UIViewRepresentable {
@Binding var attributedText: NSMutableAttributedString
@Binding var cursor: Int
func makeUIView(context: Context) -> UITextView {
let textView = UITextView()
@@ -31,18 +32,21 @@ struct TextViewWrapper: UIViewRepresentable {
}
func makeCoordinator() -> Coordinator {
Coordinator(attributedText: $attributedText)
Coordinator(attributedText: $attributedText, cursor: $cursor)
}
class Coordinator: NSObject, UITextViewDelegate {
@Binding var attributedText: NSMutableAttributedString
@Binding var cursor: Int
init(attributedText: Binding<NSMutableAttributedString>) {
init(attributedText: Binding<NSMutableAttributedString>, cursor: Binding<Int>) {
_attributedText = attributedText
_cursor = cursor
}
func textViewDidChange(_ textView: UITextView) {
attributedText = NSMutableAttributedString(attributedString: textView.attributedText)
cursor = textView.selectedRange.upperBound
}
}
}