Compare commits

..

2 Commits

Author SHA1 Message Date
Shadowfacts c737354ed3 Fix cursor movement not working in compose text fields when emoji added
Removes workaround introduced in 8c4ef3caa6. This is no longer necessary
and autocorrect works fine without it since at least iOS 14.4.

Closes #118
2021-04-05 18:31:03 -04:00
Shadowfacts 8ea15d3bab Add preference for requiring confirmation before reblogging 2021-04-05 18:31:00 -04:00
5 changed files with 32 additions and 25 deletions

View File

@ -58,6 +58,7 @@ class Preferences: Codable, ObservableObject {
self.expandAllContentWarnings = try container.decodeIfPresent(Bool.self, forKey: .expandAllContentWarnings) ?? false self.expandAllContentWarnings = try container.decodeIfPresent(Bool.self, forKey: .expandAllContentWarnings) ?? false
self.collapseLongPosts = try container.decodeIfPresent(Bool.self, forKey: .collapseLongPosts) ?? true self.collapseLongPosts = try container.decodeIfPresent(Bool.self, forKey: .collapseLongPosts) ?? true
self.oppositeCollapseKeywords = try container.decodeIfPresent([String].self, forKey: .oppositeCollapseKeywords) ?? [] self.oppositeCollapseKeywords = try container.decodeIfPresent([String].self, forKey: .oppositeCollapseKeywords) ?? []
self.confirmBeforeReblog = try container.decodeIfPresent(Bool.self, forKey: .confirmBeforeReblog) ?? false
self.showFavoriteAndReblogCounts = try container.decode(Bool.self, forKey: .showFavoriteAndReblogCounts) self.showFavoriteAndReblogCounts = try container.decode(Bool.self, forKey: .showFavoriteAndReblogCounts)
self.defaultNotificationsMode = try container.decode(NotificationsMode.self, forKey: .defaultNotificationsType) self.defaultNotificationsMode = try container.decode(NotificationsMode.self, forKey: .defaultNotificationsType)
@ -91,6 +92,7 @@ class Preferences: Codable, ObservableObject {
try container.encode(expandAllContentWarnings, forKey: .expandAllContentWarnings) try container.encode(expandAllContentWarnings, forKey: .expandAllContentWarnings)
try container.encode(collapseLongPosts, forKey: .collapseLongPosts) try container.encode(collapseLongPosts, forKey: .collapseLongPosts)
try container.encode(oppositeCollapseKeywords, forKey: .oppositeCollapseKeywords) try container.encode(oppositeCollapseKeywords, forKey: .oppositeCollapseKeywords)
try container.encode(confirmBeforeReblog, forKey: .confirmBeforeReblog)
try container.encode(showFavoriteAndReblogCounts, forKey: .showFavoriteAndReblogCounts) try container.encode(showFavoriteAndReblogCounts, forKey: .showFavoriteAndReblogCounts)
try container.encode(defaultNotificationsMode, forKey: .defaultNotificationsType) try container.encode(defaultNotificationsMode, forKey: .defaultNotificationsType)
@ -125,6 +127,7 @@ class Preferences: Codable, ObservableObject {
@Published var expandAllContentWarnings = false @Published var expandAllContentWarnings = false
@Published var collapseLongPosts = true @Published var collapseLongPosts = true
@Published var oppositeCollapseKeywords: [String] = [] @Published var oppositeCollapseKeywords: [String] = []
@Published var confirmBeforeReblog = false
// MARK: Digital Wellness // MARK: Digital Wellness
@Published var showFavoriteAndReblogCounts = true @Published var showFavoriteAndReblogCounts = true
@ -157,6 +160,7 @@ class Preferences: Codable, ObservableObject {
case expandAllContentWarnings case expandAllContentWarnings
case collapseLongPosts case collapseLongPosts
case oppositeCollapseKeywords case oppositeCollapseKeywords
case confirmBeforeReblog
case showFavoriteAndReblogCounts case showFavoriteAndReblogCounts
case defaultNotificationsType case defaultNotificationsType

View File

@ -57,14 +57,6 @@ struct ComposeContentWarningTextField: UIViewRepresentable {
updateAutocompleteState(textField: textField) updateAutocompleteState(textField: textField)
} }
func textFieldDidChangeSelection(_ textField: UITextField) {
// Update text binding before potentially triggering SwiftUI view update.
// See comment in MainComposeTextView.Coordinator.textViewDidChangeSelection
text.wrappedValue = textField.text ?? ""
updateAutocompleteState(textField: textField)
}
func autocomplete(with string: String) { func autocomplete(with string: String) {
guard let textField = textField, guard let textField = textField,
let text = textField.text, let text = textField.text,

View File

@ -258,21 +258,6 @@ struct MainComposeWrappedTextView: UIViewRepresentable {
updateAutocompleteState() updateAutocompleteState()
} }
func textViewDidChangeSelection(_ textView: UITextView) {
// Update the value of the text binding.
// Sometimes, when the user accepts an autocomplete suggestion from the system keyboard, the system
// calls didChangeSelection before textDidChange, resulting in a loop where the updating the Tusker autocomplete
// state in didChangeSection (via updateAutocompleteState) triggers a new SwiftUI view update,
// but when that SwiftUI update is handled, the model still has the old text (from prior to accepting the autocomplete
// suggestion), meaning the UITextView's text gets set back to whatever it was prior to the system autocomplete.
// To work around that, we also update the text binding in didChangeSelection, to ensure that, if the autocomplete state
// does change and trigger a SwiftUI update, the binding will have the correct text that was produced by the system
// autocompletion.
text.wrappedValue = textView.text ?? ""
updateAutocompleteState()
}
func autocomplete(with string: String) { func autocomplete(with string: String) {
guard let textView = textView, guard let textView = textView,
let text = textView.text, let text = textView.text,

View File

@ -13,14 +13,23 @@ struct BehaviorPrefsView: View {
var body: some View { var body: some View {
List { List {
untitledSection
linksSection linksSection
contentWarningsSection contentWarningsSection
} }
.listStyle(InsetGroupedListStyle()) .listStyle(InsetGroupedListStyle())
.navigationBarTitle(Text("Behavior")) .navigationBarTitle(Text("Behavior"))
} }
private var untitledSection: some View {
Section {
Toggle(isOn: $preferences.confirmBeforeReblog) {
Text("Require Confirmation Before Reblogging")
}
}
}
var linksSection: some View { private var linksSection: some View {
Section(header: Text("Links")) { Section(header: Text("Links")) {
Toggle(isOn: $preferences.openLinksInApps) { Toggle(isOn: $preferences.openLinksInApps) {
Text("Open Links in Apps") Text("Open Links in Apps")
@ -34,7 +43,7 @@ struct BehaviorPrefsView: View {
} }
} }
var contentWarningsSection: some View { private var contentWarningsSection: some View {
Section(header: Text("Content Warnings")) { Section(header: Text("Content Warnings")) {
Toggle(isOn: $preferences.collapseLongPosts) { Toggle(isOn: $preferences.collapseLongPosts) {
Text("Collapse Long Posts") Text("Collapse Long Posts")

View File

@ -403,6 +403,23 @@ class BaseStatusTableViewCell: UITableViewCell {
@IBAction func reblogPressed() { @IBAction func reblogPressed() {
guard let status = mastodonController.persistentContainer.status(for: statusID) else { fatalError("Missing cached status \(statusID!)") } guard let status = mastodonController.persistentContainer.status(for: statusID) else { fatalError("Missing cached status \(statusID!)") }
// if we are about to reblog and the user has confirmation enabled
if !reblogged,
Preferences.shared.confirmBeforeReblog {
let alert = UIAlertController(title: "Confirm Reblog", message: "Are you sure you want to reblog this post by @\(status.account.acct)?", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
alert.addAction(UIAlertAction(title: "Reblog", style: .default) { (_) in
self.toggleReblogInternal()
})
delegate?.present(alert, animated: true)
} else {
toggleReblogInternal()
}
}
private func toggleReblogInternal() {
guard let status = mastodonController.persistentContainer.status(for: statusID) else { fatalError("Missing cached status \(statusID!)") }
let oldValue = reblogged let oldValue = reblogged
reblogged = !reblogged reblogged = !reblogged