Conversation
WalkthroughThe PR replaces built-in edit-text scrolling with a container-managed approach: the editor is wrapped in a ScrollView, and the TextInputEditText’s internal scrolling is disabled. A new fast-scroll helper attaches a draggable thumb and touchable track to synchronize thumb position with scroll state and jump/drag the ScrollView. TextEditorFragment now wires the fast-scroll thumb/track, schedules caret-aware smooth scrolling after edits and on navigation, and cleans up listeners on view destruction. A new drawable resource defines the scroll thumb appearance and layout gains scroll_track/scroll_thumb placeholders. Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@presentation/src/main/java/org/cryptomator/presentation/ui/fragment/TextEditorFragment.kt`:
- Around line 144-156: In scrollCaretIntoView(), the layout line coordinates
need to be converted into scroll-content coordinates by adding
editor.paddingTop; update the visibility checks and scroll targets in the
function (referencing scrollCaretIntoView, editor, layout, lineTop, lineBottom,
scroll.scrollY, visibleHeight and scroll.smoothScrollTo) to use paddedTopLine =
editor.paddingTop + lineTop and paddedBottomLine = editor.paddingTop +
lineBottom, then compare paddedTopLine / paddedBottomLine against scroll.scrollY
and scroll.scrollY + visibleHeight and call smoothScrollTo with targets computed
from the padded coordinates.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 3e488b0c-94c0-4b5e-b3e9-dcb57a376108
📒 Files selected for processing (4)
presentation/src/main/java/org/cryptomator/presentation/ui/fragment/TextEditorFragment.ktpresentation/src/main/java/org/cryptomator/presentation/ui/layout/FastScrollHelper.ktpresentation/src/main/res/drawable/scroll_thumb.xmlpresentation/src/main/res/layout/fragment_text_editor.xml
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@presentation/src/main/java/org/cryptomator/presentation/ui/fragment/TextEditorFragment.kt`:
- Around line 138-142: The posted caret-scroll runnable and repeated
text-watcher registration must be guarded and cleaned up: change
setupCaretAutoScroll to register a single TextWatcher instance (store it as a
field, e.g., textWatcher) and add it to binding.textEditor in onViewCreated, and
remove it in onDestroyView (mirroring fastScrollCleanup) via
binding.textEditor.removeTextChangedListener(textWatcher); inside the watcher's
callback and the onQuery post call, guard any use of binding by checking if
(!isAdded) return before calling binding.textEditor.post or invoking
scrollCaretIntoView so the posted Runnable won't run against a detached view;
ensure scrollCaretIntoView references remain the same.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 16588f9b-d145-485a-8c76-f470c3d5daa3
📒 Files selected for processing (1)
presentation/src/main/java/org/cryptomator/presentation/ui/fragment/TextEditorFragment.kt
| private fun setupCaretAutoScroll() { | ||
| binding.textEditor.doAfterTextChanged { | ||
| binding.textEditor.post { scrollCaretIntoView() } | ||
| } | ||
| } |
There was a problem hiding this comment.
Guard the posted callback against view destruction and avoid stacking listeners.
Two small concerns with setupCaretAutoScroll:
- The
editor.post { scrollCaretIntoView() }runnable can be drained afteronDestroyView()(e.g., right after a quick edit followed by navigating away). Sincebindingis a lazyvalthat isn't reset, the call won't NPE, but it will operate on a detached view. Per the established pattern in this codebase, guard binding access withisAdded. - Because
binding(and thusbinding.textEditor) is not cleared inonDestroyView(), every call toonViewCreatedre-registers aTextWatcheron the sameEditableviadoAfterTextChanged, so listeners accumulate if the view is recreated for the same fragment instance (e.g., back stack pop). Consider keeping a reference to the watcher and removing it inonDestroyView(), mirroring thefastScrollCleanuppattern.
Same applies to the post { scrollCaretIntoView() } call on Line 111 inside onQuery.
🔧 Suggested adjustment
- private var fastScrollCleanup: (() -> Unit)? = null
+ private var fastScrollCleanup: (() -> Unit)? = null
+ private var caretAutoScrollWatcher: android.text.TextWatcher? = null
@@
override fun onDestroyView() {
fastScrollCleanup?.invoke()
fastScrollCleanup = null
+ caretAutoScrollWatcher?.let { binding.textEditor.removeTextChangedListener(it) }
+ caretAutoScrollWatcher = null
super.onDestroyView()
}
private fun setupCaretAutoScroll() {
- binding.textEditor.doAfterTextChanged {
- binding.textEditor.post { scrollCaretIntoView() }
- }
+ caretAutoScrollWatcher = binding.textEditor.doAfterTextChanged {
+ binding.textEditor.post {
+ if (!isAdded) return@post
+ scrollCaretIntoView()
+ }
+ }
}Based on learnings: in Cryptomator’s Android fragments using BaseFragment’s lazy binding, guard binding access with if (!isAdded) return rather than null-checking the binding.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@presentation/src/main/java/org/cryptomator/presentation/ui/fragment/TextEditorFragment.kt`
around lines 138 - 142, The posted caret-scroll runnable and repeated
text-watcher registration must be guarded and cleaned up: change
setupCaretAutoScroll to register a single TextWatcher instance (store it as a
field, e.g., textWatcher) and add it to binding.textEditor in onViewCreated, and
remove it in onDestroyView (mirroring fastScrollCleanup) via
binding.textEditor.removeTextChangedListener(textWatcher); inside the watcher's
callback and the onQuery post call, guard any use of binding by checking if
(!isAdded) return before calling binding.textEditor.post or invoking
scrollCaretIntoView so the posted Runnable won't run against a detached view;
ensure scrollCaretIntoView references remain the same.
Fixes #623