Commit: e2be544
Parent: 15df0dc

Modernize UI with Material 3, real edge-to-edge, and navigation

Mårten Åsberg committed on 2026-08-01 at 17:59
Target API 36 for real instead of dodging Android 15+'s forced
edge-to-edge - every screen now handles system bar insets properly via
EdgeToEdge.Enable() + a shared inset-padding helper. Adopts Material
Design 3 (AppCompatActivity, MaterialToolbar, dynamic color) across
all screens, replaces the overlay-style loading spinners with
LinearProgressIndicator bars that occupy their own space instead of
covering content, and adds a settings gear icon + Up navigation so
Settings and the note list are reachable from each other.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Directory.Packages.props +2 -0
diff --git a/Directory.Packages.props b/Directory.Packages.props
index c9ddc2a..074317f 100644
@@ -18,5 +18,7 @@
<PackageVersion Include="Xamarin.AndroidX.Core" Version="1.19.0.1" />
<PackageVersion Include="Xamarin.AndroidX.Browser" Version="1.10.0.1" />
<PackageVersion Include="Xamarin.AndroidX.RecyclerView" Version="1.4.0.6" />
<PackageVersion Include="Xamarin.Google.Android.Material" Version="1.14.0.6" />
<PackageVersion Include="Xamarin.AndroidX.AppCompat" Version="1.7.1.4" />
</ItemGroup>
</Project>
\ No newline at end of file
src/Activities/FolderPickerActivity.cs +20 -4
diff --git a/src/Activities/FolderPickerActivity.cs b/src/Activities/FolderPickerActivity.cs
index b4ddb5f..ba1792a 100644
@@ -1,21 +1,25 @@
using Android.Content;
using Android.Views;
using AndroidX.AppCompat.App;
using AndroidX.RecyclerView.Widget;
using Google.Android.Material.ProgressIndicator;
using NotesApp.Adapters;
using NotesApp.Auth;
using NotesApp.Graph;
using NotesApp.Models;
using NotesApp.Views;
using Toolbar = AndroidX.AppCompat.Widget.Toolbar;
namespace NotesApp.Activities;
[Activity(Label = "@string/choose_folder_title", Exported = false)]
public class FolderPickerActivity : Activity
public class FolderPickerActivity : AppCompatActivity
{
private const int SelectFolderRequestCode = 100;
public const string ExtraFolderId = "folder_id";
public const string ExtraFolderPath = "folder_path";
private ProgressBar _progressBar = null!;
private LinearProgressIndicator _progressBar = null!;
private FolderListAdapter _adapter = null!;
private GraphService _graphService = null!;
@@ -24,15 +28,21 @@ public class FolderPickerActivity : Activity
protected override void OnCreate(Bundle? savedInstanceState)
{
AndroidX.Activity.EdgeToEdge.Enable(this);
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.activity_folder_picker);
EdgeToEdgeHelper.Apply(FindViewById(Resource.Id.folder_picker_root)!);
_folderId = Intent?.GetStringExtra(ExtraFolderId);
_folderPath = Intent?.GetStringExtra(ExtraFolderPath) ?? "/";
FindViewById<TextView>(Resource.Id.folder_path_label)!.Text = _folderPath;
var toolbar = FindViewById<Toolbar>(Resource.Id.folder_picker_toolbar)!;
toolbar.Title = _folderPath;
SetSupportActionBar(toolbar);
SupportActionBar?.SetDisplayHomeAsUpEnabled(true);
_progressBar = FindViewById<ProgressBar>(Resource.Id.folder_progress)!;
_progressBar = FindViewById<LinearProgressIndicator>(Resource.Id.folder_progress)!;
var recyclerView = FindViewById<RecyclerView>(Resource.Id.folder_recycler_view)!;
recyclerView.SetLayoutManager(new LinearLayoutManager(this));
@@ -48,6 +58,12 @@ public class FolderPickerActivity : Activity
_ = LoadFoldersAsync();
}
public override bool OnSupportNavigateUp()
{
Finish();
return true;
}
protected override void OnActivityResult(int requestCode, Result resultCode, Intent? data)
{
base.OnActivityResult(requestCode, resultCode, data);
src/Activities/NoteListActivity.cs +28 -3
diff --git a/src/Activities/NoteListActivity.cs b/src/Activities/NoteListActivity.cs
index 5edfb10..cb231c4 100644
@@ -1,34 +1,43 @@
using Android.Content;
using Android.Views;
using AndroidX.AppCompat.App;
using AndroidX.RecyclerView.Widget;
using Google.Android.Material.ProgressIndicator;
using NotesApp.Adapters;
using NotesApp.Graph;
using NotesApp.Models;
using NotesApp.Storage;
using NotesApp.Views;
using Toolbar = AndroidX.AppCompat.Widget.Toolbar;
namespace NotesApp.Activities;
[Activity(Label = "@string/app_name", Exported = false)]
public class NoteListActivity : Activity
public class NoteListActivity : AppCompatActivity
{
private RecyclerView _recyclerView = null!;
private ProgressBar _progressBar = null!;
private LinearProgressIndicator _progressBar = null!;
private NoteListAdapter _adapter = null!;
private GraphService _graphService = null!;
private bool _hasScrolledToBottom;
protected override void OnCreate(Bundle? savedInstanceState)
{
AndroidX.Activity.EdgeToEdge.Enable(this);
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.activity_note_list);
EdgeToEdgeHelper.Apply(FindViewById(Resource.Id.note_list_root)!);
SetSupportActionBar(FindViewById<Toolbar>(Resource.Id.note_list_toolbar));
_recyclerView = FindViewById<RecyclerView>(Resource.Id.note_recycler_view)!;
_recyclerView.SetLayoutManager(new LinearLayoutManager(this));
_adapter = new NoteListAdapter(OnNoteTapped);
_recyclerView.SetAdapter(_adapter);
_progressBar = FindViewById<ProgressBar>(Resource.Id.note_refresh_progress)!;
_progressBar = FindViewById<LinearProgressIndicator>(Resource.Id.note_refresh_progress)!;
_graphService = new GraphService(this);
@@ -87,6 +96,22 @@ public class NoteListActivity : Activity
}
}
public override bool OnCreateOptionsMenu(IMenu? menu)
{
MenuInflater.Inflate(Resource.Menu.menu_note_list, menu);
return true;
}
public override bool OnOptionsItemSelected(IMenuItem item)
{
if (item.ItemId == Resource.Id.action_settings)
{
StartActivity(new Intent(this, typeof(SettingsActivity)));
return true;
}
return base.OnOptionsItemSelected(item);
}
private void OnNoteTapped(NoteCacheEntry entry)
{
var intent = new Intent(this, typeof(NoteViewActivity));
src/Activities/NoteViewActivity.cs +22 -4
diff --git a/src/Activities/NoteViewActivity.cs b/src/Activities/NoteViewActivity.cs
index ed34290..286ec9b 100644
@@ -1,29 +1,41 @@
using Android.Views;
using AndroidX.AppCompat.App;
using Google.Android.Material.ProgressIndicator;
using NotesApp.Graph;
using NotesApp.Views;
using Toolbar = AndroidX.AppCompat.Widget.Toolbar;
namespace NotesApp.Activities;
[Activity(Label = "@string/app_name", Exported = false)]
public class NoteViewActivity : Activity
public class NoteViewActivity : AppCompatActivity
{
public const string ExtraNoteId = "note_id";
public const string ExtraNoteName = "note_name";
public const string ExtraNotePreview = "note_preview";
private TextView _contentView = null!;
private ProgressBar _progressBar = null!;
private LinearProgressIndicator _progressBar = null!;
private GraphService _graphService = null!;
protected override void OnCreate(Bundle? savedInstanceState)
{
AndroidX.Activity.EdgeToEdge.Enable(this);
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.activity_note_view);
EdgeToEdgeHelper.Apply(FindViewById(Resource.Id.note_view_root)!);
var toolbar = FindViewById<Toolbar>(Resource.Id.note_view_toolbar)!;
SetSupportActionBar(toolbar);
SupportActionBar?.SetDisplayHomeAsUpEnabled(true);
var noteId = Intent?.GetStringExtra(ExtraNoteId);
Title = Intent?.GetStringExtra(ExtraNoteName) ?? GetString(Resource.String.app_name);
toolbar.Title =
Intent?.GetStringExtra(ExtraNoteName) ?? GetString(Resource.String.app_name);
_contentView = FindViewById<TextView>(Resource.Id.note_view_content)!;
_progressBar = FindViewById<ProgressBar>(Resource.Id.note_view_progress)!;
_progressBar = FindViewById<LinearProgressIndicator>(Resource.Id.note_view_progress)!;
_contentView.Text = Intent?.GetStringExtra(ExtraNotePreview) ?? "";
_graphService = new GraphService(this);
@@ -32,6 +44,12 @@ public class NoteViewActivity : Activity
_ = LoadContentAsync(noteId);
}
public override bool OnSupportNavigateUp()
{
Finish();
return true;
}
private async Task LoadContentAsync(string noteId)
{
_progressBar.Visibility = ViewStates.Visible;
src/Activities/SettingsActivity.cs +18 -1
diff --git a/src/Activities/SettingsActivity.cs b/src/Activities/SettingsActivity.cs
index 9c828e1..9bc2cc8 100644
@@ -1,11 +1,14 @@
using Android.Content;
using AndroidX.AppCompat.App;
using NotesApp.Auth;
using NotesApp.Storage;
using NotesApp.Views;
using Toolbar = AndroidX.AppCompat.Widget.Toolbar;
namespace NotesApp.Activities;
[Activity(Label = "@string/settings_title", Exported = false)]
public class SettingsActivity : Activity
public class SettingsActivity : AppCompatActivity
{
private const int ChooseFolderRequestCode = 200;
@@ -15,9 +18,17 @@ public class SettingsActivity : Activity
protected override void OnCreate(Bundle? savedInstanceState)
{
AndroidX.Activity.EdgeToEdge.Enable(this);
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.activity_settings);
EdgeToEdgeHelper.Apply(FindViewById(Resource.Id.settings_root)!);
SetSupportActionBar(FindViewById<Toolbar>(Resource.Id.settings_toolbar));
// Only show Up when reached via the note list's gear icon - there's nothing to
// go "up" to yet during first-run setup, before a folder is configured.
SupportActionBar?.SetDisplayHomeAsUpEnabled(AppSettings.HasRootFolder);
_accountStatus = FindViewById<TextView>(Resource.Id.account_status)!;
_signInButton = FindViewById<Button>(Resource.Id.sign_in_button)!;
_folderStatus = FindViewById<TextView>(Resource.Id.folder_status)!;
@@ -30,6 +41,12 @@ public class SettingsActivity : Activity
_ = RefreshAccountStatusAsync();
}
public override bool OnSupportNavigateUp()
{
Finish();
return true;
}
protected override void OnActivityResult(int requestCode, Result resultCode, Intent? data)
{
base.OnActivityResult(requestCode, resultCode, data);
src/AndroidManifest.xml +2 -4
diff --git a/src/AndroidManifest.xml b/src/AndroidManifest.xml
index 5948b9e..48d7d08 100644
@@ -1,15 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- targetSdkVersion pinned below 35 to avoid Android 15's forced edge-to-edge, which
draws content behind the status bar/title bar unless every Activity applies window
inset padding - not worth the boilerplate for a personal, non-Play-Store app. -->
<uses-sdk android:minSdkVersion="24" android:targetSdkVersion="34" />
<uses-sdk android:minSdkVersion="24" android:targetSdkVersion="36" />
<application
android:allowBackup="true"
android:icon="@mipmap/appicon"
android:label="@string/app_name"
android:roundIcon="@mipmap/appicon_round"
android:supportsRtl="true"
android:theme="@style/Theme.NotesApp"
>
<activity android:name=".Activities.SettingsActivity" android:exported="false" />
<activity android:name=".Activities.FolderPickerActivity" android:exported="false" />
src/MainActivity.cs +2 -1
diff --git a/src/MainActivity.cs b/src/MainActivity.cs
index 6d764a0..98d940c 100644
@@ -1,11 +1,12 @@
using Android.Content;
using AndroidX.AppCompat.App;
using NotesApp.Activities;
using NotesApp.Storage;
namespace NotesApp.Android;
[Activity(Label = "@string/app_name", MainLauncher = true)]
public class MainActivity : Activity
public class MainActivity : AppCompatActivity
{
protected override void OnCreate(Bundle? savedInstanceState)
{
src/NotesApp.csproj +2 -0
diff --git a/src/NotesApp.csproj b/src/NotesApp.csproj
index 60b571e..c8df5c6 100644
@@ -17,5 +17,7 @@
<PackageReference Include="Xamarin.AndroidX.Core" />
<PackageReference Include="Xamarin.AndroidX.Browser" />
<PackageReference Include="Xamarin.AndroidX.RecyclerView" />
<PackageReference Include="Xamarin.Google.Android.Material" />
<PackageReference Include="Xamarin.AndroidX.AppCompat" />
</ItemGroup>
</Project>
src/NotesApplication.cs +15 -0
diff --git a/src/NotesApplication.cs b/src/NotesApplication.cs
new file mode 100644
index 0000000..2a17264
@@ -0,0 +1,15 @@
using Android.Runtime;
using Google.Android.Material.Color;
namespace NotesApp.Android;
[Application]
public class NotesApplication(IntPtr handle, JniHandleOwnership ownership)
: Application(handle, ownership)
{
public override void OnCreate()
{
base.OnCreate();
DynamicColors.ApplyToActivitiesIfAvailable(this);
}
}
src/Resources/drawable/ic_settings_24.xml +14 -0
diff --git a/src/Resources/drawable/ic_settings_24.xml b/src/Resources/drawable/ic_settings_24.xml
new file mode 100644
index 0000000..dd72640
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorOnSurface"
>
<path
android:fillColor="#FF000000"
android:pathData="M19.14,12.94c0.04,-0.3 0.06,-0.61 0.06,-0.94c0,-0.32 -0.02,-0.64 -0.07,-0.94l2.03,-1.58c0.18,-0.14 0.23,-0.41 0.12,-0.61l-1.92,-3.32c-0.12,-0.22 -0.37,-0.29 -0.59,-0.22l-2.39,0.96c-0.5,-0.38 -1.03,-0.7 -1.62,-0.94L14.4,2.81c-0.04,-0.24 -0.24,-0.41 -0.48,-0.41h-3.84c-0.24,0 -0.43,0.17 -0.47,0.41L9.25,5.35C8.66,5.59 8.12,5.92 7.63,6.29L5.24,5.33c-0.22,-0.08 -0.47,0 -0.59,0.22L2.74,8.87C2.62,9.08 2.66,9.34 2.86,9.48l2.03,1.58C4.84,11.36 4.8,11.69 4.8,12s0.02,0.64 0.07,0.94l-2.03,1.58c-0.18,0.14 -0.23,0.41 -0.12,0.61l1.92,3.32c0.12,0.22 0.37,0.29 0.59,0.22l2.39,-0.96c0.5,0.38 1.03,0.7 1.62,0.94l0.36,2.54c0.05,0.24 0.24,0.41 0.48,0.41h3.84c0.24,0 0.44,-0.17 0.47,-0.41l0.36,-2.54c0.59,-0.24 1.13,-0.56 1.62,-0.94l2.39,0.96c0.22,0.08 0.47,0 0.59,-0.22l1.92,-3.32c0.12,-0.22 0.07,-0.47 -0.12,-0.61L19.14,12.94zM12,15.6c-1.98,0 -3.6,-1.62 -3.6,-3.6s1.62,-3.6 3.6,-3.6s3.6,1.62 3.6,3.6S13.98,15.6 12,15.6z"
/>
</vector>
src/Resources/layout/activity_folder_picker.xml +19 -22
diff --git a/src/Resources/layout/activity_folder_picker.xml b/src/Resources/layout/activity_folder_picker.xml
index fa13a43..64242c5 100644
@@ -1,39 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/folder_picker_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<TextView
android:id="@+id/folder_path_label"
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/folder_picker_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/folder_recycler_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
/>
<com.google.android.material.progressindicator.LinearProgressIndicator
android:id="@+id/folder_progress"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="12dp"
android:textStyle="bold"
android:visibility="gone"
android:indeterminate="true"
/>
<Button
android:id="@+id/select_folder_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/select_this_folder"
/>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/folder_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<ProgressBar
android:id="@+id/folder_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="gone"
/>
</FrameLayout>
</LinearLayout>
src/Resources/layout/activity_main.xml +0 -15
diff --git a/src/Resources/layout/activity_main.xml b/src/Resources/layout/activity_main.xml
deleted file mode 100644
index 550796f..0000000
@@ -1,15 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="@string/app_text"
/>
</RelativeLayout>
src/Resources/layout/activity_note_list.xml +18 -7
diff --git a/src/Resources/layout/activity_note_list.xml b/src/Resources/layout/activity_note_list.xml
index 0c4d756..4643ba8 100644
@@ -1,20 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/note_list_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/note_list_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:title="@string/app_name"
/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/note_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
/>
<ProgressBar
<com.google.android.material.progressindicator.LinearProgressIndicator
android:id="@+id/note_refresh_progress"
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:layout_marginBottom="16dp"
android:visibility="gone"
android:indeterminate="true"
/>
</FrameLayout>
</LinearLayout>
src/Resources/layout/activity_note_view.xml +19 -6
diff --git a/src/Resources/layout/activity_note_view.xml b/src/Resources/layout/activity_note_view.xml
index 2be7e00..2c7fecd 100644
@@ -1,10 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/note_view_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<ScrollView android:layout_width="match_parent" android:layout_height="match_parent">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/note_view_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
/>
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
>
<TextView
android:id="@+id/note_view_content"
android:layout_width="match_parent"
@@ -14,11 +26,12 @@
android:textIsSelectable="true"
/>
</ScrollView>
<ProgressBar
<com.google.android.material.progressindicator.LinearProgressIndicator
android:id="@+id/note_view_progress"
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="gone"
android:indeterminate="true"
/>
</FrameLayout>
</LinearLayout>
src/Resources/layout/activity_settings.xml +42 -27
diff --git a/src/Resources/layout/activity_settings.xml b/src/Resources/layout/activity_settings.xml
index 3a24a44..106db32 100644
@@ -1,39 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/settings_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="24dp"
>
<TextView
android:id="@+id/account_status"
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/settings_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/not_signed_in"
android:textSize="16sp"
android:paddingBottom="16dp"
/>
<Button
android:id="@+id/sign_in_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/sign_in_button"
android:layout_height="?attr/actionBarSize"
app:title="@string/settings_title"
/>
<TextView
android:id="@+id/folder_status"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/no_folder_selected"
android:textSize="16sp"
android:paddingTop="32dp"
android:paddingBottom="16dp"
/>
<Button
android:id="@+id/choose_folder_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/choose_folder_button"
/>
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="24dp"
>
<TextView
android:id="@+id/account_status"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/not_signed_in"
android:textSize="16sp"
android:paddingBottom="16dp"
/>
<Button
android:id="@+id/sign_in_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/sign_in_button"
/>
<TextView
android:id="@+id/folder_status"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/no_folder_selected"
android:textSize="16sp"
android:paddingTop="32dp"
android:paddingBottom="16dp"
/>
<Button
android:id="@+id/choose_folder_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/choose_folder_button"
/>
</LinearLayout>
</LinearLayout>
src/Resources/menu/menu_note_list.xml +12 -0
diff --git a/src/Resources/menu/menu_note_list.xml b/src/Resources/menu/menu_note_list.xml
new file mode 100644
index 0000000..3ef1089
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<menu
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
>
<item
android:id="@+id/action_settings"
android:title="@string/settings_title"
android:icon="@drawable/ic_settings_24"
app:showAsAction="ifRoom"
/>
</menu>
src/Resources/values/strings.xml +0 -1
diff --git a/src/Resources/values/strings.xml b/src/Resources/values/strings.xml
index 28c873f..7eb5b9f 100644
@@ -1,6 +1,5 @@
<resources>
<string name="app_name">NotesApp</string>
<string name="app_text">Hello, Notes!</string>
<string name="msal_client_id" translatable="false">61377814-56c4-4e92-b5ae-fb06e46ca864</string>
<string name="msal_redirect_scheme" translatable="false"
src/Resources/values/themes.xml +3 -0
diff --git a/src/Resources/values/themes.xml b/src/Resources/values/themes.xml
new file mode 100644
index 0000000..16ca680
@@ -0,0 +1,3 @@
<resources>
<style name="Theme.NotesApp" parent="Theme.Material3.DayNight.NoActionBar" />
</resources>
src/Views/EdgeToEdgeHelper.cs +45 -0
diff --git a/src/Views/EdgeToEdgeHelper.cs b/src/Views/EdgeToEdgeHelper.cs
new file mode 100644
index 0000000..267a474
@@ -0,0 +1,45 @@
using Android.Views;
using AndroidX.Core.View;
namespace NotesApp.Views;
// Under Android 15+'s forced edge-to-edge, content draws behind the status/nav bars unless
// something applies their insets as padding. android:fitsSystemWindows only works for
// Material's AppBarLayout, which this app doesn't use (no collapsing/scroll behavior needed),
// so each screen's root view gets this explicit ViewCompat listener instead - padding all four
// edges on top of whatever padding was already authored in the layout XML.
public static class EdgeToEdgeHelper
{
public static void Apply(View root)
{
var baseLeft = root.PaddingLeft;
var baseTop = root.PaddingTop;
var baseRight = root.PaddingRight;
var baseBottom = root.PaddingBottom;
ViewCompat.SetOnApplyWindowInsetsListener(
root,
new Listener(baseLeft, baseTop, baseRight, baseBottom)
);
}
private class Listener(int baseLeft, int baseTop, int baseRight, int baseBottom)
: Java.Lang.Object,
IOnApplyWindowInsetsListener
{
public WindowInsetsCompat? OnApplyWindowInsets(View? v, WindowInsetsCompat? insets)
{
if (v is null || insets is null)
return insets;
var bars = insets.GetInsets(WindowInsetsCompat.Type.SystemBars())!;
v.SetPadding(
baseLeft + bars.Left,
baseTop + bars.Top,
baseRight + bars.Right,
baseBottom + bars.Bottom
);
return insets;
}
}
}
src/packages.lock.json +295 -0
diff --git a/src/packages.lock.json b/src/packages.lock.json
index 58c22c5..fb64160 100644
@@ -49,6 +49,31 @@
"resolved": "10.0.10",
"contentHash": "f5VCIE7AJpd5YvzNTeMGVzQIgyE9tX+AreTYwQF+REbu+DZo/2Ae+jNSwhPEYrVz6RRkd7y8ubXjk6Nn6Ka+Cg=="
},
"Xamarin.AndroidX.AppCompat": {
"type": "Direct",
"requested": "[1.7.1.4, )",
"resolved": "1.7.1.4",
"contentHash": "txambMgIFpDjAEpwqk0j1GK+pQdwu3JSxVqu5Zd83RrGSFnHoUZEM4ep+ESD75UARqLWYqhMfxpl5P52O2q6pQ==",
"dependencies": {
"Xamarin.AndroidX.Activity": "1.13.0.1",
"Xamarin.AndroidX.Annotation": "1.10.0.1",
"Xamarin.AndroidX.AppCompat.AppCompatResources": "[1.7.1.4, 1.7.2)",
"Xamarin.AndroidX.Collection": "1.6.0.1",
"Xamarin.AndroidX.Core": "1.19.0.1",
"Xamarin.AndroidX.Core.Core.Ktx": "1.19.0.1",
"Xamarin.AndroidX.CursorAdapter": "1.0.0.37",
"Xamarin.AndroidX.DrawerLayout": "1.2.0.21",
"Xamarin.AndroidX.Emoji2": "1.6.0.3",
"Xamarin.AndroidX.Emoji2.ViewsHelper": "1.6.0.3",
"Xamarin.AndroidX.Fragment": "1.8.9.3",
"Xamarin.AndroidX.Lifecycle.Runtime": "2.11.0.1",
"Xamarin.AndroidX.Lifecycle.ViewModel": "2.11.0.1",
"Xamarin.AndroidX.ProfileInstaller.ProfileInstaller": "1.4.1.8",
"Xamarin.AndroidX.ResourceInspection.Annotation": "1.0.1.25",
"Xamarin.AndroidX.SavedState": "1.5.0.1",
"Xamarin.Kotlin.StdLib": "2.4.0.1"
}
},
"Xamarin.AndroidX.Browser": {
"type": "Direct",
"requested": "[1.10.0.1, )",
@@ -103,6 +128,34 @@
"Xamarin.AndroidX.ProfileInstaller.ProfileInstaller": "1.4.1.8"
}
},
"Xamarin.Google.Android.Material": {
"type": "Direct",
"requested": "[1.14.0.6, )",
"resolved": "1.14.0.6",
"contentHash": "xC0oD3awmOwrW0OZesBjwN3kCBSN7tPduRht5Kmy9Dea/OwhQjr4GunT1MsTYcNT3VCruYa1mcYdN13n9Wwg0w==",
"dependencies": {
"Xamarin.AndroidX.Activity": "1.13.0.1",
"Xamarin.AndroidX.Annotation": "1.10.0.1",
"Xamarin.AndroidX.Annotation.Experimental": "1.6.0.1",
"Xamarin.AndroidX.AppCompat": "1.7.1.4",
"Xamarin.AndroidX.CardView": "1.0.0.39",
"Xamarin.AndroidX.ConstraintLayout": "2.2.1.6",
"Xamarin.AndroidX.CoordinatorLayout": "1.3.0.6",
"Xamarin.AndroidX.Core": "1.19.0.1",
"Xamarin.AndroidX.CustomView": "1.2.0.4",
"Xamarin.AndroidX.DrawerLayout": "1.2.0.21",
"Xamarin.AndroidX.DynamicAnimation": "1.1.0.6",
"Xamarin.AndroidX.Fragment": "1.8.9.3",
"Xamarin.AndroidX.Graphics.Shapes": "1.1.0.3",
"Xamarin.AndroidX.Lifecycle.Runtime": "2.11.0.1",
"Xamarin.AndroidX.RecyclerView": "1.4.0.6",
"Xamarin.AndroidX.ResourceInspection.Annotation": "1.0.1.25",
"Xamarin.AndroidX.Transition": "1.7.0.2",
"Xamarin.AndroidX.VectorDrawable": "1.2.0.11",
"Xamarin.AndroidX.ViewPager2": "1.1.0.11",
"Xamarin.Google.ErrorProne.Annotations": "2.50.0.1"
}
},
"Azure.Core": {
"type": "Transitive",
"resolved": "1.50.0",
@@ -329,6 +382,18 @@
"Xamarin.Kotlin.StdLib": "2.4.0.1"
}
},
"Xamarin.AndroidX.AppCompat.AppCompatResources": {
"type": "Transitive",
"resolved": "1.7.1.4",
"contentHash": "FMooskcnJ3pU03GtRMVd1Y16ZGahVQ6mgl4msPzWQ2QUoxlie2yPijYQka5k9ssNWjQNsSuEAOfpPz1A3LYsxg==",
"dependencies": {
"Xamarin.AndroidX.Annotation": "1.10.0.1",
"Xamarin.AndroidX.Collection": "1.6.0.1",
"Xamarin.AndroidX.Core": "1.19.0.1",
"Xamarin.AndroidX.VectorDrawable": "1.2.0.11",
"Xamarin.AndroidX.VectorDrawable.Animated": "1.2.0.11"
}
},
"Xamarin.AndroidX.Arch.Core.Common": {
"type": "Transitive",
"resolved": "2.2.0.21",
@@ -346,6 +411,14 @@
"Xamarin.AndroidX.Arch.Core.Common": "[2.2.0.21, 2.2.1)"
}
},
"Xamarin.AndroidX.CardView": {
"type": "Transitive",
"resolved": "1.0.0.39",
"contentHash": "GrbCWOtxZ9SATCOkscTF8kJ1zJlC/8b19Usfp3TduzZscEGi7rFf7fuX7I08Rsdjostrs0FuWWQZub80pVRsKw==",
"dependencies": {
"Xamarin.AndroidX.Annotation": "1.10.0.1"
}
},
"Xamarin.AndroidX.Collection": {
"type": "Transitive",
"resolved": "1.6.0.1",
@@ -392,6 +465,37 @@
"Xamarin.JSpecify": "1.0.0.7"
}
},
"Xamarin.AndroidX.ConstraintLayout": {
"type": "Transitive",
"resolved": "2.2.1.6",
"contentHash": "F9f8BHPkY/nBVBFi5d2yq1vdRZPLDSqHFltuam6cFeMuz6ZhQDEqQ6YLn8tnVoONUaqH+dUVaEptY1n5RTTRcg==",
"dependencies": {
"Xamarin.AndroidX.AppCompat": "1.7.1.4",
"Xamarin.AndroidX.ConstraintLayout.Core": "1.1.1.6",
"Xamarin.AndroidX.Core": "1.19.0.1",
"Xamarin.AndroidX.ProfileInstaller.ProfileInstaller": "1.4.1.8"
}
},
"Xamarin.AndroidX.ConstraintLayout.Core": {
"type": "Transitive",
"resolved": "1.1.1.6",
"contentHash": "NhN2xmmqUcBq0XlKMY322h0v6Zm11rtbB35ADwz5pFoK/AiP4iiTotSFX1A0NDpE/2VF/JqUZeBEjQmWgZF9IQ==",
"dependencies": {
"Xamarin.AndroidX.Annotation": "1.10.0.1"
}
},
"Xamarin.AndroidX.CoordinatorLayout": {
"type": "Transitive",
"resolved": "1.3.0.6",
"contentHash": "ehTNCwpmVBSglqdBnxfQmtL4BJA/YqNHxdDQwSVJYK/iELixLbj3Ymbj+8dl8myd/ZAHjJ1vDRlLHWBVDRYHeQ==",
"dependencies": {
"Xamarin.AndroidX.Annotation": "1.10.0.1",
"Xamarin.AndroidX.Collection": "1.6.0.1",
"Xamarin.AndroidX.Core": "1.19.0.1",
"Xamarin.AndroidX.CustomView": "1.2.0.4",
"Xamarin.JSpecify": "1.0.0.7"
}
},
"Xamarin.AndroidX.Core.Core.Ktx": {
"type": "Transitive",
"resolved": "1.19.0.1",
@@ -409,6 +513,14 @@
"Xamarin.Kotlin.StdLib": "2.4.0.1"
}
},
"Xamarin.AndroidX.CursorAdapter": {
"type": "Transitive",
"resolved": "1.0.0.37",
"contentHash": "tZxKuVjw9HwxSSVyhxVw4Hs+YRNHbLwpu+5QpSq6RCjY7NVNoHeLklytntBVuDY2EUKOuR2hSrBRhcgijfrxXg==",
"dependencies": {
"Xamarin.AndroidX.Annotation": "1.10.0.1"
}
},
"Xamarin.AndroidX.CustomView": {
"type": "Transitive",
"resolved": "1.2.0.4",
@@ -429,6 +541,94 @@
"Xamarin.Kotlin.StdLib": "2.4.0.1"
}
},
"Xamarin.AndroidX.DrawerLayout": {
"type": "Transitive",
"resolved": "1.2.0.21",
"contentHash": "BIvdnKMHI6JFPpApPBjL5/inu/L0wU88bKMDZOE+fnIAob0Qz4ZxyynSJJkC8D2dw2mVITYcAJxXK7zPkas3rg==",
"dependencies": {
"Xamarin.AndroidX.Annotation": "1.10.0.1",
"Xamarin.AndroidX.Core": "1.19.0.1",
"Xamarin.AndroidX.CustomView": "1.2.0.4"
}
},
"Xamarin.AndroidX.DynamicAnimation": {
"type": "Transitive",
"resolved": "1.1.0.6",
"contentHash": "XvXv5+Wxcou+J3Z/waDbhKKfjKFPIPIY50uDbyB8HhvN023POUp2WBatKclf/jWao6X+3ML0j3ZEyJXwi5lVtg==",
"dependencies": {
"Xamarin.AndroidX.Collection": "1.6.0.1",
"Xamarin.AndroidX.Core": "1.19.0.1",
"Xamarin.JSpecify": "1.0.0.7"
}
},
"Xamarin.AndroidX.Emoji2": {
"type": "Transitive",
"resolved": "1.6.0.3",
"contentHash": "Pb603fbsfvfqbLHrFyn0deReLxb4gJMzBnSXRuuJrh2VL9TcOeNQ7WgpLa0QGJ0Z+3b6iuQhfnd6vNZ7fvYg5w==",
"dependencies": {
"Xamarin.AndroidX.Annotation": "1.10.0.1",
"Xamarin.AndroidX.Collection": "1.6.0.1",
"Xamarin.AndroidX.Core": "1.19.0.1",
"Xamarin.AndroidX.Lifecycle.Process": "2.11.0.1",
"Xamarin.AndroidX.Startup.StartupRuntime": "1.2.0.8",
"Xamarin.JSpecify": "1.0.0.7"
}
},
"Xamarin.AndroidX.Emoji2.ViewsHelper": {
"type": "Transitive",
"resolved": "1.6.0.3",
"contentHash": "gVKEntE5UctFDeszUM+/+JVyqiyNkVyRyKXlf27/qUjPV5BzTVCx2JG2xL5C5hYNDQ+XiqKMEA35P+q9hZD+MQ==",
"dependencies": {
"Xamarin.AndroidX.Collection": "1.6.0.1",
"Xamarin.AndroidX.Core": "1.19.0.1",
"Xamarin.AndroidX.Emoji2": "[1.6.0.3, 1.6.1)",
"Xamarin.JSpecify": "1.0.0.7"
}
},
"Xamarin.AndroidX.Fragment": {
"type": "Transitive",
"resolved": "1.8.9.3",
"contentHash": "PJ4Cz/w2kDMiS2Jb74qQVFFYspE6aySP46v8CnBXTSL5GdvQ18LR/MvpOvHVqy6owXh+MhOFhQYcumQHqqPRIA==",
"dependencies": {
"Xamarin.AndroidX.Activity": "1.13.0.1",
"Xamarin.AndroidX.Annotation": "1.10.0.1",
"Xamarin.AndroidX.Annotation.Experimental": "1.6.0.1",
"Xamarin.AndroidX.Collection": "1.6.0.1",
"Xamarin.AndroidX.Core.Core.Ktx": "1.19.0.1",
"Xamarin.AndroidX.Lifecycle.LiveData.Core": "2.11.0.1",
"Xamarin.AndroidX.Lifecycle.Runtime": "2.11.0.1",
"Xamarin.AndroidX.Lifecycle.ViewModel": "2.11.0.1",
"Xamarin.AndroidX.Lifecycle.ViewModelSavedState": "2.11.0.1",
"Xamarin.AndroidX.Loader": "1.1.0.37",
"Xamarin.AndroidX.ProfileInstaller.ProfileInstaller": "1.4.1.8",
"Xamarin.AndroidX.SavedState": "1.5.0.1",
"Xamarin.AndroidX.ViewPager": "1.1.0.7",
"Xamarin.Kotlin.StdLib": "2.4.0.1"
}
},
"Xamarin.AndroidX.Graphics.Shapes": {
"type": "Transitive",
"resolved": "1.1.0.3",
"contentHash": "CCa5/ra0N3+oI5ZxD/hl5CxhsKfJyzaMscEd5qCySTQHr3MAVxR60Nx13UL0TXsjH1sfmRXZcCTo6ty72niWlQ==",
"dependencies": {
"Xamarin.AndroidX.Annotation": "1.10.0.1",
"Xamarin.AndroidX.Collection": "1.6.0.1",
"Xamarin.AndroidX.Graphics.Shapes.Android": "1.1.0.3",
"Xamarin.Kotlin.StdLib": "2.4.0.1"
}
},
"Xamarin.AndroidX.Graphics.Shapes.Android": {
"type": "Transitive",
"resolved": "1.1.0.3",
"contentHash": "8U3dqKE1wJD8MA/vouByH4WAFN6Zkv/W+Hgr3TSNBG5auW/2DpT8zF/XSOVe1O+YE7UmZvfaUIJdIriG6pms6A==",
"dependencies": {
"Xamarin.AndroidX.Annotation.Experimental": "1.6.0.1",
"Xamarin.AndroidX.Annotation.Jvm": "1.10.0.1",
"Xamarin.AndroidX.Collection.Jvm": "1.6.0.1",
"Xamarin.AndroidX.Core.Core.Ktx": "1.19.0.1",
"Xamarin.Kotlin.StdLib": "2.4.0.1"
}
},
"Xamarin.AndroidX.Interpolator": {
"type": "Transitive",
"resolved": "1.0.0.37",
@@ -471,6 +671,17 @@
"Xamarin.Kotlin.StdLib": "2.4.0.1"
}
},
"Xamarin.AndroidX.Lifecycle.Process": {
"type": "Transitive",
"resolved": "2.11.0.1",
"contentHash": "vQbEwTh0oOhmGgJUx6zobjLl6ZEvFfEL9ZTsmQAovOdtvJvrQb/9bAqTxRgO81pOP8b3ZFiwISl5b1yd2hkKXw==",
"dependencies": {
"Xamarin.AndroidX.Annotation": "1.10.0.1",
"Xamarin.AndroidX.Lifecycle.Runtime": "[2.11.0.1, 2.11.1)",
"Xamarin.AndroidX.Startup.StartupRuntime": "1.2.0.8",
"Xamarin.Kotlin.StdLib": "2.4.0.1"
}
},
"Xamarin.AndroidX.Lifecycle.Runtime": {
"type": "Transitive",
"resolved": "2.11.0.1",
@@ -561,6 +772,18 @@
"Xamarin.KotlinX.Serialization.Core.Jvm": "1.11.0.1"
}
},
"Xamarin.AndroidX.Loader": {
"type": "Transitive",
"resolved": "1.1.0.37",
"contentHash": "pwovhD7xX+PlXLH9O9aU+oZXmAcjCS51f1JN7DoUoE83DWYK90/mWCSSuYcxdly9gJHCcHGoklIoM01qHv7Z7w==",
"dependencies": {
"Xamarin.AndroidX.Annotation": "1.10.0.1",
"Xamarin.AndroidX.Collection": "1.6.0.1",
"Xamarin.AndroidX.Core": "1.19.0.1",
"Xamarin.AndroidX.Lifecycle.LiveData.Core": "2.11.0.1",
"Xamarin.AndroidX.Lifecycle.ViewModel": "2.11.0.1"
}
},
"Xamarin.AndroidX.NavigationEvent": {
"type": "Transitive",
"resolved": "1.1.2.1",
@@ -600,6 +823,14 @@
"Xamarin.Google.Guava.ListenableFuture": "1.0.0.32"
}
},
"Xamarin.AndroidX.ResourceInspection.Annotation": {
"type": "Transitive",
"resolved": "1.0.1.25",
"contentHash": "0L7m/q7Ea0Q8Dx4nFK3BjtJZtcQfPs1DyziPpt7BXplj6zrf4GqKjHhneWNowr/LJxUZvxO+qx9F3/GU+ELlbA==",
"dependencies": {
"Xamarin.AndroidX.Annotation": "1.10.0.1"
}
},
"Xamarin.AndroidX.SavedState": {
"type": "Transitive",
"resolved": "1.5.0.1",
@@ -657,6 +888,42 @@
"Xamarin.Kotlin.StdLib": "2.4.0.1"
}
},
"Xamarin.AndroidX.Transition": {
"type": "Transitive",
"resolved": "1.7.0.2",
"contentHash": "S5cDtVjwTQN1rbnisPQ1psqj+GTWORI2WEiP2kvcqfhJXOziNJM/zTyKIMABQuWAv6Dsy/eDYlXovy0MzIqFjQ==",
"dependencies": {
"Xamarin.AndroidX.Annotation": "1.10.0.1",
"Xamarin.AndroidX.Collection": "1.6.0.1",
"Xamarin.AndroidX.Core": "1.19.0.1",
"Xamarin.AndroidX.DynamicAnimation": "1.1.0.6",
"Xamarin.AndroidX.Fragment": "1.8.9.3",
"Xamarin.JSpecify": "1.0.0.7",
"Xamarin.Kotlin.StdLib": "2.4.0.1"
}
},
"Xamarin.AndroidX.VectorDrawable": {
"type": "Transitive",
"resolved": "1.2.0.11",
"contentHash": "281B3dHTUiAyLl3ewj/cHgY0Sm0KAUP4PgLRs2jbeYt+TAvSoIoIM7EXu//bnmG6erY1dIFAfbNKfHQ/yBNp2A==",
"dependencies": {
"Xamarin.AndroidX.Annotation": "1.10.0.1",
"Xamarin.AndroidX.Collection": "1.6.0.1",
"Xamarin.AndroidX.Core": "1.19.0.1"
}
},
"Xamarin.AndroidX.VectorDrawable.Animated": {
"type": "Transitive",
"resolved": "1.2.0.11",
"contentHash": "6IIN9+ShJm59mc3mEe/s3HmB1EHh3wlfyBoQj7boMbmdK0e/kcLxvcVtLFH1WfkmhyYeWwGZY3mLTryVF8mWoQ==",
"dependencies": {
"Xamarin.AndroidX.Annotation": "1.10.0.1",
"Xamarin.AndroidX.Collection": "1.6.0.1",
"Xamarin.AndroidX.Core": "1.19.0.1",
"Xamarin.AndroidX.Interpolator": "1.0.0.37",
"Xamarin.AndroidX.VectorDrawable": "1.2.0.11"
}
},
"Xamarin.AndroidX.VersionedParcelable": {
"type": "Transitive",
"resolved": "1.2.1.6",
@@ -667,6 +934,34 @@
"Xamarin.JSpecify": "1.0.0.7"
}
},
"Xamarin.AndroidX.ViewPager": {
"type": "Transitive",
"resolved": "1.1.0.7",
"contentHash": "O8iQpk7iyF9yIdctfT1RMq2m2paOoJ6oDhkK6EC02iQuCrv09dv7n7suS0N1a9XEL+UNzQd3ul/lCXHmsIB3QA==",
"dependencies": {
"Xamarin.AndroidX.Annotation": "1.10.0.1",
"Xamarin.AndroidX.Core": "1.19.0.1",
"Xamarin.AndroidX.CustomView": "1.2.0.4"
}
},
"Xamarin.AndroidX.ViewPager2": {
"type": "Transitive",
"resolved": "1.1.0.11",
"contentHash": "uqHV7+hIgsV90v67ykdBW4zcQMQa3IwS5FPP9EZjBwjpaa8+JIZPxzyGLuq7fTqUYEBeKVMmHmPZ6mjpjtI1XQ==",
"dependencies": {
"Xamarin.AndroidX.Annotation": "1.10.0.1",
"Xamarin.AndroidX.Annotation.Experimental": "1.6.0.1",
"Xamarin.AndroidX.Collection": "1.6.0.1",
"Xamarin.AndroidX.Core": "1.19.0.1",
"Xamarin.AndroidX.Fragment": "1.8.9.3",
"Xamarin.AndroidX.RecyclerView": "1.4.0.6"
}
},
"Xamarin.Google.ErrorProne.Annotations": {
"type": "Transitive",
"resolved": "2.50.0.1",
"contentHash": "ip4SsCz/U2n/nJVL4Hk6BVzNWdWeQkyyLyo6zm3vWrCeAq/U4tIdNnR7i355pTZMzFeDwcITsTvStf0JQhpBxQ=="
},
"Xamarin.Google.Guava.ListenableFuture": {
"type": "Transitive",
"resolved": "1.0.0.32",