Reapply and rework "ux: Mute selected text"

This commit reapplies the "ux: Mute selected text" commit, with some
manual rework to solve logical conflicts during merge.

Rework testing
--------------

PASS

Device: iPhone 13 Mini
iOS: 17.6.1
Steps:
1. Go to a note
2. Select text and click on the "highlight" button. Ensure that highlight sheet appears with the correct text
3. Select text and click on the "mute" button. Ensure that mute sheet appears with the correct text

Original commit: d663155941
Original author: ericholguin <ericholguin@apache.org>
Reworked-by: Daniel D’Aquino <daniel@daquino.me>
Retested-by: Daniel D’Aquino <daniel@daquino.me>
This commit is contained in:
ericholguin
2024-09-04 11:38:58 -07:00
committed by Daniel D’Aquino
parent 51b1b81c0e
commit dd1fdf159b
3 changed files with 64 additions and 28 deletions

View File

@@ -13,7 +13,7 @@ struct SelectableText: View {
let event: NostrEvent? let event: NostrEvent?
let attributedString: AttributedString let attributedString: AttributedString
let textAlignment: NSTextAlignment let textAlignment: NSTextAlignment
@State private var highlightPostingState: HighlightPostingState = .hide @State private var selectedTextActionState: SelectedTextActionState = .hide
@State private var selectedTextHeight: CGFloat = .zero @State private var selectedTextHeight: CGFloat = .zero
@State private var selectedTextWidth: CGFloat = .zero @State private var selectedTextWidth: CGFloat = .zero
@@ -37,7 +37,10 @@ struct SelectableText: View {
textAlignment: self.textAlignment, textAlignment: self.textAlignment,
enableHighlighting: self.enableHighlighting(), enableHighlighting: self.enableHighlighting(),
postHighlight: { selectedText in postHighlight: { selectedText in
self.highlightPostingState = .show_post_view(highlighted_text: selectedText) self.selectedTextActionState = .show_highlight_post_view(highlighted_text: selectedText)
},
muteWord: { selectedText in
self.selectedTextActionState = .show_mute_word_view(highlighted_text: selectedText)
}, },
height: $selectedTextHeight height: $selectedTextHeight
) )
@@ -54,11 +57,11 @@ struct SelectableText: View {
} }
} }
.sheet(isPresented: Binding(get: { .sheet(isPresented: Binding(get: {
return self.highlightPostingState.show() return self.selectedTextActionState.should_show_highlight_post_view()
}, set: { newValue in }, set: { newValue in
self.highlightPostingState = newValue ? .show_post_view(highlighted_text: self.highlightPostingState.highlighted_text() ?? "") : .hide self.selectedTextActionState = newValue ? .show_highlight_post_view(highlighted_text: self.selectedTextActionState.highlighted_text() ?? "") : .hide
})) { })) {
if let event, case .show_post_view(let highlighted_text) = self.highlightPostingState { if let event, case .show_highlight_post_view(let highlighted_text) = self.selectedTextActionState {
PostView( PostView(
action: .highlighting(.init(selected_text: highlighted_text, source: .event(event))), action: .highlighting(.init(selected_text: highlighted_text, source: .event(event))),
damus_state: damus_state damus_state: damus_state
@@ -67,6 +70,17 @@ struct SelectableText: View {
.presentationDetents([.height(selectedTextHeight + 450), .medium, .large]) .presentationDetents([.height(selectedTextHeight + 450), .medium, .large])
} }
} }
.sheet(isPresented: Binding(get: {
return self.selectedTextActionState.should_show_mute_word_view()
}, set: { newValue in
self.selectedTextActionState = newValue ? .show_mute_word_view(highlighted_text: self.selectedTextActionState.highlighted_text() ?? "") : .hide
})) {
if case .show_mute_word_view(let highlighted_text) = selectedTextActionState {
AddMuteItemView(state: damus_state, new_text: .constant(highlighted_text))
.presentationDragIndicator(.visible)
.presentationDetents([.height(300), .medium, .large])
}
}
.frame(height: selectedTextHeight) .frame(height: selectedTextHeight)
} }
@@ -74,22 +88,28 @@ struct SelectableText: View {
self.event != nil self.event != nil
} }
enum HighlightPostingState { enum SelectedTextActionState {
case hide case hide
case show_post_view(highlighted_text: String) case show_highlight_post_view(highlighted_text: String)
case show_mute_word_view(highlighted_text: String)
func show() -> Bool { func should_show_highlight_post_view() -> Bool {
if case .show_post_view(let highlighted_text) = self { guard case .show_highlight_post_view(let highlighted_text) = self else { return false }
return true return true
} }
return false
func should_show_mute_word_view() -> Bool {
guard case .show_mute_word_view(let highlighted_text) = self else { return false }
return true
} }
func highlighted_text() -> String? { func highlighted_text() -> String? {
switch self { switch self {
case .hide: case .hide:
return nil return nil
case .show_post_view(highlighted_text: let highlighted_text): case .show_mute_word_view(highlighted_text: let highlighted_text):
return highlighted_text
case .show_highlight_post_view(highlighted_text: let highlighted_text):
return highlighted_text return highlighted_text
} }
} }
@@ -98,9 +118,11 @@ struct SelectableText: View {
fileprivate class TextView: UITextView { fileprivate class TextView: UITextView {
var postHighlight: (String) -> Void var postHighlight: (String) -> Void
var muteWord: (String) -> Void
init(frame: CGRect, textContainer: NSTextContainer?, postHighlight: @escaping (String) -> Void) { init(frame: CGRect, textContainer: NSTextContainer?, postHighlight: @escaping (String) -> Void, muteWord: @escaping (String) -> Void) {
self.postHighlight = postHighlight self.postHighlight = postHighlight
self.muteWord = muteWord
super.init(frame: frame, textContainer: textContainer) super.init(frame: frame, textContainer: textContainer)
} }
@@ -112,18 +134,32 @@ fileprivate class TextView: UITextView {
if action == #selector(highlightText(_:)) { if action == #selector(highlightText(_:)) {
return true return true
} }
if action == #selector(muteText(_:)) {
return true
}
return super.canPerformAction(action, withSender: sender) return super.canPerformAction(action, withSender: sender)
} }
func getSelectedText() -> String? {
guard let selectedRange = self.selectedTextRange else { return nil }
return self.text(in: selectedRange)
}
@objc public func highlightText(_ sender: Any?) { @objc public func highlightText(_ sender: Any?) {
guard let selectedRange = self.selectedTextRange else { return } guard let selectedText = self.getSelectedText() else { return }
guard let selectedText = self.text(in: selectedRange) else { return }
self.postHighlight(selectedText) self.postHighlight(selectedText)
} }
@objc public func muteText(_ sender: Any?) {
guard let selectedText = self.getSelectedText() else { return }
self.muteWord(selectedText)
}
} }
fileprivate struct TextViewRepresentable: UIViewRepresentable { fileprivate struct TextViewRepresentable: UIViewRepresentable {
let attributedString: AttributedString let attributedString: AttributedString
let textColor: UIColor let textColor: UIColor
@@ -132,10 +168,11 @@ fileprivate class TextView: UITextView {
let textAlignment: NSTextAlignment let textAlignment: NSTextAlignment
let enableHighlighting: Bool let enableHighlighting: Bool
let postHighlight: (String) -> Void let postHighlight: (String) -> Void
let muteWord: (String) -> Void
@Binding var height: CGFloat @Binding var height: CGFloat
func makeUIView(context: UIViewRepresentableContext<Self>) -> TextView { func makeUIView(context: UIViewRepresentableContext<Self>) -> TextView {
let view = TextView(frame: .zero, textContainer: nil, postHighlight: postHighlight) let view = TextView(frame: .zero, textContainer: nil, postHighlight: postHighlight, muteWord: muteWord)
view.isEditable = false view.isEditable = false
view.dataDetectorTypes = .all view.dataDetectorTypes = .all
view.isSelectable = true view.isSelectable = true
@@ -148,7 +185,8 @@ fileprivate class TextView: UITextView {
let menuController = UIMenuController.shared let menuController = UIMenuController.shared
let highlightItem = UIMenuItem(title: "Highlight", action: #selector(view.highlightText(_:))) let highlightItem = UIMenuItem(title: "Highlight", action: #selector(view.highlightText(_:)))
menuController.menuItems = self.enableHighlighting ? [highlightItem] : [] let muteItem = UIMenuItem(title: "Mute", action: #selector(view.muteText(_:)))
menuController.menuItems = self.enableHighlighting ? [highlightItem, muteItem] : []
return view return view
} }

View File

@@ -8,7 +8,7 @@ import SwiftUI
struct AddMuteItemView: View { struct AddMuteItemView: View {
let state: DamusState let state: DamusState
@State var new_text: String = "" @Binding var new_text: String
@State var expiration: DamusDuration = .indefinite @State var expiration: DamusDuration = .indefinite
@Environment(\.dismiss) var dismiss @Environment(\.dismiss) var dismiss
@@ -108,6 +108,6 @@ struct AddMuteItemView: View {
struct AddMuteItemView_Previews: PreviewProvider { struct AddMuteItemView_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
AddMuteItemView(state: test_damus_state) AddMuteItemView(state: test_damus_state, new_text: .constant(""))
} }
} }

View File

@@ -15,6 +15,8 @@ struct MutelistView: View {
@State var hashtags: [MuteItem] = [] @State var hashtags: [MuteItem] = []
@State var threads: [MuteItem] = [] @State var threads: [MuteItem] = []
@State var words: [MuteItem] = [] @State var words: [MuteItem] = []
@State var new_text: String = ""
func RemoveAction(item: MuteItem) -> some View { func RemoveAction(item: MuteItem) -> some View {
Button { Button {
@@ -120,13 +122,9 @@ struct MutelistView: View {
} }
} }
.sheet(isPresented: $show_add_muteitem, onDismiss: { self.show_add_muteitem = false }) { .sheet(isPresented: $show_add_muteitem, onDismiss: { self.show_add_muteitem = false }) {
if #available(iOS 16.0, *) { AddMuteItemView(state: damus_state, new_text: $new_text)
AddMuteItemView(state: damus_state) .presentationDetents([.height(300)])
.presentationDetents([.height(300)]) .presentationDragIndicator(.visible)
.presentationDragIndicator(.visible)
} else {
AddMuteItemView(state: damus_state)
}
} }
} }
} }