Commit: 6de2f7e
Parent: 2e8e7e4

Fix the keyboard covering the bottom of long notes

Mårten Åsberg committed on 2026-08-04 at 10:34
The editor's ScrollView-wrapping-a-wrap_content-EditText was the
wrong shape for this: it added a second, redundant scroll layer, and
patching the IME inset in as the EditText's own bottom padding fought
with the view's internal text/scroll bookkeeping - fine on most
lines, but tapping the very last line produced a bogus extra
keyboard-height gap between the text and the keyboard.

The EditText is now a direct, bounded-height child (no ScrollView) so
it scrolls and follows the cursor on its own. The IME inset instead
pads the root container (folded into the existing EdgeToEdgeHelper,
taking whichever of the nav bar or keyboard is taller rather than
summing them) - since the EditText is the layout's only weighted
child, padding the root makes it genuinely shrink through normal
layout instead of via internal padding. windowSoftInputMode is now
adjustNothing so the OS's own pan/resize doesn't stack on top and
drag the toolbar off-screen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
src/AndroidManifest.xml +5 -1
diff --git a/src/AndroidManifest.xml b/src/AndroidManifest.xml
index e58975d..4b45036 100644
@@ -13,7 +13,11 @@
<activity android:name=".Activities.SettingsActivity" android:exported="false" />
<activity android:name=".Activities.FolderPickerActivity" android:exported="false" />
<activity android:name=".Activities.NoteListActivity" android:exported="false" />
<activity android:name=".Activities.NoteViewActivity" android:exported="false" />
<activity
android:name=".Activities.NoteViewActivity"
android:exported="false"
android:windowSoftInputMode="adjustNothing"
/>
<activity android:name="microsoft.identity.client.BrowserTabActivity" android:exported="true">
<intent-filter>
src/Resources/layout/activity_note_view.xml +9 -14
diff --git a/src/Resources/layout/activity_note_view.xml b/src/Resources/layout/activity_note_view.xml
index 73bd6fc..65e6de5 100644
@@ -20,21 +20,16 @@
android:indeterminate="true"
/>
<ScrollView
<EditText
android:id="@+id/note_view_content"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
>
<EditText
android:id="@+id/note_view_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:textSize="16sp"
android:fontFamily="@font/cascadia_mono"
android:inputType="textMultiLine"
android:gravity="top|start"
android:background="@android:color/transparent"
/>
</ScrollView>
android:padding="16dp"
android:textSize="16sp"
android:fontFamily="@font/cascadia_mono"
android:inputType="textMultiLine"
android:gravity="top|start"
android:background="@android:color/transparent"
/>
</LinearLayout>
src/Views/EdgeToEdgeHelper.cs +9 -1
diff --git a/src/Views/EdgeToEdgeHelper.cs b/src/Views/EdgeToEdgeHelper.cs
index 267a474..10e821d 100644
@@ -23,6 +23,13 @@ public static class EdgeToEdgeHelper
);
}
// Bottom padding also accounts for the IME (on-screen keyboard), taking whichever of the
// nav bar or the keyboard is taller rather than summing them - the keyboard, when visible,
// already covers the nav bar's region, so adding both would double that overlap. Padding
// the root (rather than e.g. a text field directly) means a weighted child in a vertical
// layout - like NoteViewActivity's EditText - genuinely shrinks via normal layout, instead
// of the child having to reconcile its own padding against its internal text/scroll state.
// A view with no keyboard ever focused inside it just sees Ime().Bottom stay 0 always.
private class Listener(int baseLeft, int baseTop, int baseRight, int baseBottom)
: Java.Lang.Object,
IOnApplyWindowInsetsListener
@@ -33,11 +40,12 @@ public static class EdgeToEdgeHelper
return insets;
var bars = insets.GetInsets(WindowInsetsCompat.Type.SystemBars())!;
var ime = insets.GetInsets(WindowInsetsCompat.Type.Ime())!;
v.SetPadding(
baseLeft + bars.Left,
baseTop + bars.Top,
baseRight + bars.Right,
baseBottom + bars.Bottom
baseBottom + Math.Max(bars.Bottom, ime.Bottom)
);
return insets;
}