forked from shadowfacts/Tusker
Apply Mastodon poll limits in Compose view
This commit is contained in:
parent
32382c4783
commit
2d45fbbd91
|
@ -15,15 +15,17 @@ struct ComposeEmojiTextField: UIViewRepresentable {
|
||||||
|
|
||||||
@Binding var text: String
|
@Binding var text: String
|
||||||
let placeholder: String
|
let placeholder: String
|
||||||
|
let maxLength: Int?
|
||||||
let becomeFirstResponder: Binding<Bool>?
|
let becomeFirstResponder: Binding<Bool>?
|
||||||
let focusNextView: Binding<Bool>?
|
let focusNextView: Binding<Bool>?
|
||||||
private var didChange: ((String) -> Void)? = nil
|
private var didChange: ((String) -> Void)? = nil
|
||||||
private var didEndEditing: (() -> Void)? = nil
|
private var didEndEditing: (() -> Void)? = nil
|
||||||
private var backgroundColor: UIColor? = nil
|
private var backgroundColor: UIColor? = nil
|
||||||
|
|
||||||
init(text: Binding<String>, placeholder: String, becomeFirstResponder: Binding<Bool>? = nil, focusNextView: Binding<Bool>? = nil) {
|
init(text: Binding<String>, placeholder: String, maxLength: Int? = nil, becomeFirstResponder: Binding<Bool>? = nil, focusNextView: Binding<Bool>? = nil) {
|
||||||
self._text = text
|
self._text = text
|
||||||
self.placeholder = placeholder
|
self.placeholder = placeholder
|
||||||
|
self.maxLength = maxLength
|
||||||
self.becomeFirstResponder = becomeFirstResponder
|
self.becomeFirstResponder = becomeFirstResponder
|
||||||
self.focusNextView = focusNextView
|
self.focusNextView = focusNextView
|
||||||
self.didChange = nil
|
self.didChange = nil
|
||||||
|
@ -74,6 +76,7 @@ struct ComposeEmojiTextField: UIViewRepresentable {
|
||||||
} else {
|
} else {
|
||||||
uiView.text = text
|
uiView.text = text
|
||||||
}
|
}
|
||||||
|
context.coordinator.maxLength = maxLength
|
||||||
context.coordinator.didChange = didChange
|
context.coordinator.didChange = didChange
|
||||||
context.coordinator.didEndEditing = didEndEditing
|
context.coordinator.didEndEditing = didEndEditing
|
||||||
context.coordinator.focusNextView = focusNextView
|
context.coordinator.focusNextView = focusNextView
|
||||||
|
@ -95,6 +98,7 @@ struct ComposeEmojiTextField: UIViewRepresentable {
|
||||||
var text: Binding<String>!
|
var text: Binding<String>!
|
||||||
// break retained cycle through ComposeUIState.currentInput
|
// break retained cycle through ComposeUIState.currentInput
|
||||||
unowned var uiState: ComposeUIState!
|
unowned var uiState: ComposeUIState!
|
||||||
|
var maxLength: Int?
|
||||||
var didChange: ((String) -> Void)?
|
var didChange: ((String) -> Void)?
|
||||||
var didEndEditing: (() -> Void)?
|
var didEndEditing: (() -> Void)?
|
||||||
var focusNextView: Binding<Bool>?
|
var focusNextView: Binding<Bool>?
|
||||||
|
@ -114,6 +118,14 @@ struct ComposeEmojiTextField: UIViewRepresentable {
|
||||||
focusNextView?.wrappedValue = true
|
focusNextView?.wrappedValue = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
|
||||||
|
if let maxLength {
|
||||||
|
return ((textField.text ?? "") as NSString).replacingCharacters(in: range, with: string).count <= maxLength
|
||||||
|
} else {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func textFieldDidBeginEditing(_ textField: UITextField) {
|
func textFieldDidBeginEditing(_ textField: UITextField) {
|
||||||
uiState.currentInput = self
|
uiState.currentInput = self
|
||||||
updateAutocompleteState(textField: textField)
|
updateAutocompleteState(textField: textField)
|
||||||
|
|
|
@ -20,6 +20,7 @@ struct ComposePollView: View {
|
||||||
@ObservedObject var draft: Draft
|
@ObservedObject var draft: Draft
|
||||||
@ObservedObject var poll: Draft.Poll
|
@ObservedObject var poll: Draft.Poll
|
||||||
|
|
||||||
|
@EnvironmentObject var mastodonController: MastodonController
|
||||||
@Environment(\.colorScheme) var colorScheme: ColorScheme
|
@Environment(\.colorScheme) var colorScheme: ColorScheme
|
||||||
|
|
||||||
@State private var duration: Duration
|
@State private var duration: Duration
|
||||||
|
@ -30,6 +31,14 @@ struct ComposePollView: View {
|
||||||
|
|
||||||
self._duration = State(initialValue: .fromTimeInterval(poll.duration) ?? .oneDay)
|
self._duration = State(initialValue: .fromTimeInterval(poll.duration) ?? .oneDay)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var canAddOption: Bool {
|
||||||
|
if let pollConfig = mastodonController.instance?.pollsConfiguration {
|
||||||
|
return poll.options.count < pollConfig.maxOptions
|
||||||
|
} else {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack {
|
VStack {
|
||||||
|
@ -67,9 +76,15 @@ struct ComposePollView: View {
|
||||||
.frame(height: 44 * CGFloat(poll.options.count))
|
.frame(height: 44 * CGFloat(poll.options.count))
|
||||||
|
|
||||||
Button(action: self.addOption) {
|
Button(action: self.addOption) {
|
||||||
Label("Add Option", systemImage: "plus")
|
Label {
|
||||||
|
Text("Add Option")
|
||||||
|
} icon: {
|
||||||
|
Image(systemName: "plus")
|
||||||
|
.foregroundColor(.accentColor)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.buttonStyle(.borderless)
|
.buttonStyle(.borderless)
|
||||||
|
.disabled(!canAddOption)
|
||||||
|
|
||||||
HStack {
|
HStack {
|
||||||
MenuPicker(selection: $poll.multiple, options: [
|
MenuPicker(selection: $poll.multiple, options: [
|
||||||
|
@ -155,6 +170,8 @@ struct ComposePollOption: View {
|
||||||
@ObservedObject var option: Draft.Poll.Option
|
@ObservedObject var option: Draft.Poll.Option
|
||||||
let optionIndex: Int
|
let optionIndex: Int
|
||||||
|
|
||||||
|
@EnvironmentObject private var mastodonController: MastodonController
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
HStack(spacing: 4) {
|
HStack(spacing: 4) {
|
||||||
Checkbox(radiusFraction: poll.multiple ? 0.1 : 0.5, borderWidth: 2)
|
Checkbox(radiusFraction: poll.multiple ? 0.1 : 0.5, borderWidth: 2)
|
||||||
|
@ -173,7 +190,7 @@ struct ComposePollOption: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
private var textField: some View {
|
private var textField: some View {
|
||||||
var field = ComposeEmojiTextField(text: $option.text, placeholder: "Option \(optionIndex + 1)")
|
var field = ComposeEmojiTextField(text: $option.text, placeholder: "Option \(optionIndex + 1)", maxLength: mastodonController.instance?.pollsConfiguration?.maxCharactersPerOption)
|
||||||
return field.backgroundColor(.systemBackground)
|
return field.backgroundColor(.systemBackground)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue