Skip to content

Conversation

@btnguyenPersonal
Copy link
Contributor

@btnguyenPersonal btnguyenPersonal commented Jul 4, 2025

Type of change(s)

  • Bug fix
  • Feature / enhancement
  • Infrastructure / tooling (CI, build, deps, tests)
  • Documentation

What changed and why

  • Fixed keyboard hiding cursor on startup in long notes when config.showKeyboard is true

I don't know if this is the cleanest place to put this, let me know if there is a better place and I'll change it!

Before/After Screenshots/Screen Record

before:
https://github.com/user-attachments/assets/871dea74-eb7e-4138-96e1-ae949ee944e1

after:

fixed2.mp4

Fixes the following issue(s)

Checklist

  • I read the contribution guidelines.
  • I manually tested my changes on device/emulator (if applicable).
  • I updated the "Unreleased" section in CHANGELOG.md (if applicable).
  • All checks are passing.

@btnguyenPersonal btnguyenPersonal marked this pull request as ready for review July 4, 2025 19:07
Copy link
Member

@naveensingh naveensingh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The action bar and tab layout now move off-screen due to those flags. I think this should be fixed directly in the fragment (e.g., by scrolling to the end) rather than activity level.

(Is that i3wm or sway in your video?)

@naveensingh naveensingh added the waiting for author If the author does not respond, the issue will be closed. Otherwise, the label will be removed. label Jul 5, 2025
@btnguyenPersonal
Copy link
Contributor Author

The action bar and tab layout now move off-screen due to those flags. I think this should be fixed directly in the fragment (e.g., by scrolling to the end) rather than activity level.

(Is that i3wm or sway in your video?)

ah I didn't see that, good catch

it's my own build of dwm

@btnguyenPersonal
Copy link
Contributor Author

I'm a little stumped on this one. I'm new to android so I'm sure that I am missing something obvious. I can't figure out where to find the callback for after the keyboard appears fully.

I also was searching in the docs for a way to find out what the keyboard height would be when fully rendered so that I could just calculate where the fragment should scroll to, but I wasn't able to find that either.

Currently the only thing that I can get to work is to make the scroll happen on a delay after the onResume of TextFragment, but it's beyond hacky

app/src/main/kotlin/org/fossify/notes/fragments/TextFragment.kt:165

if (config.showKeyboard && isMenuVisible && (!note!!.isLocked() || shouldShowLockedContent)) {
                onGlobalLayout {
                    if (activity?.isDestroyed == false) {
                        requestFocus()
                        val inputManager = requireActivity().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
                        inputManager.showSoftInput(this, InputMethodManager.SHOW_IMPLICIT)
+
+                        val rect = Rect()
+                        noteEditText.getFocusedRect(rect)
+                        binding.notesScrollview.postDelayed({
+                            binding.notesScrollview.smoothScrollTo(0, rect.bottom)
+                        }, 1000)
                    }
                }
            }

@naveensingh
Copy link
Member

How about a window inset listener? For example, see setupKeyboardListener() in ThreadActivity.

@naveensingh naveensingh removed the waiting for author If the author does not respond, the issue will be closed. Otherwise, the label will be removed. label Jul 6, 2025
Co-authored-by: Naveen Singh <36371707+naveensingh@users.noreply.github.com>
@btnguyenPersonal
Copy link
Contributor Author

There's an issue now that we moved the code over to a window inset listener. Every time we open/close the keyboard it executes the scroll

@btnguyenPersonal
Copy link
Contributor Author

I'm thinking we could keep it on the onResume and force it to only run once, then unset itself. That way we get only once per resume, and not every time we open/close the keyboard in the app.

Is there a better way?

@naveensingh
Copy link
Member

naveensingh commented Jul 6, 2025

force it to only run once, then unset itself

That's what I'm also thinking:

    private fun setupKeyboardListener() {
        requireActivity().window.decorView.apply {
            setOnApplyWindowInsetsListener { view, insets ->
                val windowInsets = WindowInsetsCompat.toWindowInsetsCompat(insets)
                if (windowInsets.isVisible(WindowInsetsCompat.Type.ime())) {
                    scrollToEndOfNote()
                    setOnApplyWindowInsetsListener(null) // clear to avoid scrolling every time
                }
                view.onApplyWindowInsets(insets)
            }
        }
    }

In addition to checking keyboard visibility, we also need to check whether config.placeCursorToEnd is enabled before scrolling.

(This trick should work without side effects here because nothing else in this activity is calling decorView.setOnApplyWindowInsetsListener, but generally, things would go wrong if used in other places)

Is there a better way?

Nope, none that I can think of now.

@naveensingh
Copy link
Member

There's one more issue:

The scroll only works on cold starts. Exit app via back button ➜ reopen app ➜ content still behind the keyboard.

@btnguyenPersonal
Copy link
Contributor Author

looking into it more, my current code is probably not a good solution because even closing and reopening the keyboard leads to the same covering issue.

I think the best way would be to always scroll right to where to cursor is on keyboard open if the cursor isn't on screen after the keyboard fully opens, then we wouldn't have to unset it, and would work in all cases. I don't know if that's easy to do or if I need to do some calculations or if that's even possible idk.

@naveensingh
Copy link
Member

I think the best way would be to always scroll right to where to cursor is on keyboard open if the cursor isn't on screen after the keyboard fully opens, then we wouldn't have to unset it, and would work in all cases.

Good idea! I have a solution, but I haven't tested it much:

  1. Set android:fitsSystemWindows="true" in activity_main.xml
  2. Set listener on binding.root in onViewCreated()
  3. Call noteEditText.bringPointIntoView when keyboard becomes visible.

@btnguyenPersonal
Copy link
Contributor Author

I think the best way would be to always scroll right to where to cursor is on keyboard open if the cursor isn't on screen after the keyboard fully opens, then we wouldn't have to unset it, and would work in all cases.

Good idea! I have a solution, but I haven't tested it much:

1. Set `android:fitsSystemWindows="true"` in `activity_main.xml`

2. Set listener on `binding.root` in `onViewCreated()`

3. Call `noteEditText.bringPointIntoView` when keyboard becomes visible.

that worked perfectly! it seems to work exactly how it should by scrolling the cursor into view every time the keyboard is opened

Copy link
Member

@naveensingh naveensingh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@naveensingh naveensingh merged commit 2c81907 into FossifyOrg:main Jul 9, 2025
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

on startup keyboard obscures cursor on long note

2 participants