Skip to content

Commit 55ebf2d

Browse files
committed
fix cursor position
1 parent dcde5e3 commit 55ebf2d

File tree

3 files changed

+37
-17
lines changed

3 files changed

+37
-17
lines changed

iosApp/flare/UI/Screen/ComposeScreen.swift

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ struct ComposeScreen: View {
1111
@FocusState private var cwKeyboardFocused: Bool
1212
@StateObject private var presenter: KotlinPresenter<ComposeState>
1313
@State private var viewModel = ComposeInputViewModel()
14-
@State private var uiTextView: UITextField?
14+
@State private var uiTextView: UITextView?
15+
@State private var pendingCursor: Int?
1516

1617
var body: some View {
1718
VStack(
@@ -82,15 +83,14 @@ struct ComposeScreen: View {
8283
TextField(text: $viewModel.text, axis: .vertical) {
8384
Text("compose_placeholder")
8485
}
85-
.introspect(.textField, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { textField in
86+
.introspect(.textField(axis: .vertical), on: .iOS(.v16, .v17, .v18, .v26)) { textField in
8687
self.uiTextView = textField
88+
applyCursorIfPossible()
8789
}
8890
.textFieldStyle(.plain)
8991
.focused($keyboardFocused)
9092
.onAppear {
91-
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
92-
keyboardFocused = true
93-
}
93+
keyboardFocused = true
9494
}
9595
Spacer()
9696
if viewModel.mediaViewModel.items.count > 0 {
@@ -265,6 +265,7 @@ struct ComposeScreen: View {
265265
.popover(isPresented: $viewModel.showEmoji) {
266266
EmojiPopup(data: emojis) { item in
267267
viewModel.addEmoji(emoji: item)
268+
insert(item.insertText)
268269
}
269270
}
270271
}
@@ -290,15 +291,10 @@ struct ComposeScreen: View {
290291
.onChange(of: presenter.state.initialTextState) { oldValue, newValue in
291292
if case .success(let initialText) = onEnum(of: newValue) {
292293
viewModel.text = initialText.data.text
294+
pendingCursor = Int(initialText.data.cursorPosition)
295+
applyCursorIfPossible()
293296
}
294297
}
295-
.onChange(of: uiTextView, { oldValue, newValue in
296-
if case .success(let initialText) = onEnum(of: presenter.state.initialTextState),
297-
let textField = newValue,
298-
let newPosition = textField.position(from: textField.beginningOfDocument, offset: Int(initialText.data.cursorPosition)) {
299-
textField.selectedTextRange = textField.textRange(from: newPosition, to: newPosition)
300-
}
301-
})
302298
.toolbarTitleDisplayMode(.inline)
303299
.toolbar {
304300
ToolbarItem(placement: .principal) {
@@ -334,6 +330,35 @@ struct ComposeScreen: View {
334330
}
335331
}
336332
}
333+
334+
private func applyCursorIfPossible() {
335+
guard let textView = uiTextView, textView.isFirstResponder, let pendingCursor else { return }
336+
let length = textView.text.count
337+
let clamped = NSRange(location: max(0, min(pendingCursor, length)),
338+
length: 0)
339+
textView.selectedRange = clamped
340+
textView.scrollRangeToVisible(clamped)
341+
self.pendingCursor = nil
342+
}
343+
344+
private func insert(_ s: String) {
345+
guard let textView = uiTextView else { return }
346+
347+
if textView.markedTextRange != nil { return }
348+
349+
let sel = textView.selectedRange
350+
let current = textView.text ?? ""
351+
let ns = current as NSString
352+
let newText = ns.replacingCharacters(in: sel, with: s)
353+
354+
textView.text = newText
355+
viewModel.text = newText
356+
357+
let newLocation = sel.location + (s as NSString).length
358+
textView.selectedRange = NSRange(location: newLocation, length: 0)
359+
textView.scrollRangeToVisible(NSRange(location: max(0, newLocation - 1), length: 1))
360+
}
361+
337362
}
338363

339364
struct EmojiPopup: View {

shared/build.gradle.kts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ kotlin {
1919
applyDefaultHierarchyTemplate {
2020
common {
2121
group("apple") {
22-
withMacos()
2322
withIos()
2423
}
2524
group("androidJvm") {
@@ -42,8 +41,6 @@ kotlin {
4241
iosX64(),
4342
iosArm64(),
4443
iosSimulatorArm64(),
45-
macosArm64(),
46-
macosX64(),
4744
).forEach { appleTarget ->
4845
appleTarget.binaries.framework {
4946
baseName = "shared"

shared/ui/build.gradle.kts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@ kotlin {
2222
iosX64(),
2323
iosArm64(),
2424
iosSimulatorArm64(),
25-
// macosArm64(),
26-
// macosX64(),
2725
).forEach { appleTarget ->
2826
appleTarget.binaries.framework {
2927
baseName = "sharedUI"

0 commit comments

Comments
 (0)