diff --git a/JournalApp/Components/DataPointView.razor b/JournalApp/Components/DataPointView.razor index 7718788..0768125 100644 --- a/JournalApp/Components/DataPointView.razor +++ b/JournalApp/Components/DataPointView.razor @@ -25,7 +25,7 @@ else if (Point.Type == PointType.Scale) } else if (Point.Type == PointType.LowToHigh) { - + None Low Medium @@ -34,7 +34,7 @@ else if (Point.Type == PointType.LowToHigh) } else if (Point.Type == PointType.MildToSevere) { - + None Mild Moderate @@ -43,18 +43,18 @@ else if (Point.Type == PointType.MildToSevere) } else if (Point.Type == PointType.Bool) { - + No Yes } else if (Point.Type == PointType.Number) { - + } else if (Point.Type == PointType.Text) { - + } else if (Point.Type == PointType.Note) { @@ -75,7 +75,7 @@ else if (Point.Type == PointType.Note) else if (Point.Type == PointType.Medication) {
- + No Yes diff --git a/JournalApp/Components/DataPointView.razor.css b/JournalApp/Components/DataPointView.razor.css index 0ba5c06..7b90237 100644 --- a/JournalApp/Components/DataPointView.razor.css +++ b/JournalApp/Components/DataPointView.razor.css @@ -5,6 +5,13 @@ gap: 8px; } +/* Fixed-width tabular readout so 9.5 -> 10.0 doesn't shift the slider. */ +::deep .sleep-hours { + min-width: 4ch; + text-align: center; + font-variant-numeric: tabular-nums; +} + .note-container { display: flex; flex-direction: column; diff --git a/JournalApp/Data/PreferenceService.cs b/JournalApp/Data/PreferenceService.cs index 4fb53b3..f9bf1be 100644 --- a/JournalApp/Data/PreferenceService.cs +++ b/JournalApp/Data/PreferenceService.cs @@ -15,14 +15,15 @@ public sealed partial class PreferenceService : IPreferences, IDisposable private MudTheme _mudTheme; private uint _mudThemeSeed; - // Mood colors are HCT values generated with material-color-utilities on a "coral reef" hue sweep: turquoise water (210Β°, great) through sand to coral (20Β°, awful). + // Mood colors are HCT values generated with material-color-utilities on a "coral reef" hue sweep: turquoise water (210Β°, great) through coral (20Β°, awful). // The light ramp stays in bright tones (62-86) so the theme's dark text-primary reads on every cell, and the dark ramp uses deep jewel tones (42-50) so the light text-primary does the same. πŸ€” (unset) intentionally has no color. + // 😐 sits at the middle of the ramp as a true neutral grey so it reads as no signal either way. private static readonly Dictionary _lightMoodColors = new() { ["🀩"] = "#2ACADF", ["πŸ˜€"] = "#50DBD0", ["πŸ™‚"] = "#8BE3C0", - ["😐"] = "#EED687", + ["😐"] = "#D9D9D9", ["πŸ˜•"] = "#FFB783", ["😒"] = "#FF9474", ["😭"] = "#F26B6B", @@ -33,7 +34,7 @@ public sealed partial class PreferenceService : IPreferences, IDisposable ["🀩"] = "#007E8C", ["πŸ˜€"] = "#00857E", ["πŸ™‚"] = "#2A8668", - ["😐"] = "#916C24", + ["😐"] = "#737373", ["πŸ˜•"] = "#A65911", ["😒"] = "#A94C2F", ["😭"] = "#A94041", diff --git a/JournalApp/MainPage.xaml b/JournalApp/MainPage.xaml index 0b34a8a..bcd90c0 100644 --- a/JournalApp/MainPage.xaml +++ b/JournalApp/MainPage.xaml @@ -1,14 +1,15 @@ -ο»Ώ + + SafeAreaEdges="All" + BackgroundColor="{AppThemeBinding Light=#FFF8F9, Dark=#181215}"> - + - \ No newline at end of file + diff --git a/JournalApp/MainPage.xaml.cs b/JournalApp/MainPage.xaml.cs index 957c618..605f12f 100644 --- a/JournalApp/MainPage.xaml.cs +++ b/JournalApp/MainPage.xaml.cs @@ -1,4 +1,6 @@ -ο»Ώnamespace JournalApp; +using Microsoft.AspNetCore.Components.WebView; + +namespace JournalApp; public partial class MainPage : ContentPage { @@ -6,4 +8,14 @@ public MainPage() { InitializeComponent(); } + + // The native WebView paints white before Blazor's first frame, which flashes hard against a dark splash, so let the themed page background show through instead. + private void OnBlazorWebViewInitialized(object sender, BlazorWebViewInitializedEventArgs e) + { +#if ANDROID + e.WebView.SetBackgroundColor(Android.Graphics.Color.Transparent); +#elif WINDOWS + e.WebView.DefaultBackgroundColor = Microsoft.UI.Colors.Transparent; +#endif + } } diff --git a/JournalApp/Pages/SettingsPage.razor b/JournalApp/Pages/SettingsPage.razor index b990fde..037f6b0 100644 --- a/JournalApp/Pages/SettingsPage.razor +++ b/JournalApp/Pages/SettingsPage.razor @@ -33,7 +33,7 @@ else
Theme - + Light Dark System diff --git a/JournalApp/Pages/Trends/TrendCategoryView.razor b/JournalApp/Pages/Trends/TrendCategoryView.razor index da2903a..b6a78fb 100644 --- a/JournalApp/Pages/Trends/TrendCategoryView.razor +++ b/JournalApp/Pages/Trends/TrendCategoryView.razor @@ -146,7 +146,8 @@ else }, Xaxis = new XAxis { - TickAmount = 15, + // Few enough ticks that M/d labels never collide on a phone-width chart. + TickAmount = 6, Labels = new XAxisLabels { HideOverlappingLabels = true, diff --git a/JournalApp/Platforms/Android/Resources/drawable/appicon_monochrome.xml b/JournalApp/Platforms/Android/Resources/drawable/appicon_monochrome.xml index 5d43191..dcf88e9 100644 --- a/JournalApp/Platforms/Android/Resources/drawable/appicon_monochrome.xml +++ b/JournalApp/Platforms/Android/Resources/drawable/appicon_monochrome.xml @@ -1,8 +1,8 @@ - + + android:insetLeft="7%" + android:insetTop="7%" + android:insetRight="7%" + android:insetBottom="7%" /> diff --git a/JournalApp/Platforms/Android/Resources/drawable/splash_screen.xml b/JournalApp/Platforms/Android/Resources/drawable/splash_screen.xml index c8c88d3..4f43886 100644 --- a/JournalApp/Platforms/Android/Resources/drawable/splash_screen.xml +++ b/JournalApp/Platforms/Android/Resources/drawable/splash_screen.xml @@ -1,6 +1,15 @@ + + + + + + diff --git a/JournalApp/Platforms/Android/Resources/values-night/colors.xml b/JournalApp/Platforms/Android/Resources/values-night/colors.xml index 34688a2..052cb0c 100644 --- a/JournalApp/Platforms/Android/Resources/values-night/colors.xml +++ b/JournalApp/Platforms/Android/Resources/values-night/colors.xml @@ -1,4 +1,5 @@ - #FFD8EE + + #181215 diff --git a/JournalApp/Platforms/Android/Resources/values-v31/styles.xml b/JournalApp/Platforms/Android/Resources/values-v31/styles.xml index 7108783..89ff053 100644 --- a/JournalApp/Platforms/Android/Resources/values-v31/styles.xml +++ b/JournalApp/Platforms/Android/Resources/values-v31/styles.xml @@ -1,7 +1,7 @@ + diff --git a/JournalApp/Platforms/Android/Resources/values/colors.xml b/JournalApp/Platforms/Android/Resources/values/colors.xml index 74430eb..40d24be 100644 --- a/JournalApp/Platforms/Android/Resources/values/colors.xml +++ b/JournalApp/Platforms/Android/Resources/values/colors.xml @@ -2,5 +2,8 @@ #844C72 #844C72 - #FFD8EE + + #FFF8F9 + + #FFD8EE diff --git a/JournalApp/Resources/AppIcon/appiconfg.svg b/JournalApp/Resources/AppIcon/appiconfg.svg index f172076..22d1bb9 100644 --- a/JournalApp/Resources/AppIcon/appiconfg.svg +++ b/JournalApp/Resources/AppIcon/appiconfg.svg @@ -1 +1 @@ - + diff --git a/JournalApp/Resources/AppIcon/appiconfg_debug.svg b/JournalApp/Resources/AppIcon/appiconfg_debug.svg index 557367a..ddd9051 100644 --- a/JournalApp/Resources/AppIcon/appiconfg_debug.svg +++ b/JournalApp/Resources/AppIcon/appiconfg_debug.svg @@ -1 +1 @@ - + diff --git a/JournalApp/wwwroot/app.css b/JournalApp/wwwroot/app.css index 1fe16a3..97ca516 100644 --- a/JournalApp/wwwroot/app.css +++ b/JournalApp/wwwroot/app.css @@ -12,11 +12,11 @@ body { display: none; } +/* Background colors come from the theme-matched media queries at the bottom so the native splash, this loading screen, and the app all share one tone. */ #splash-screen { display: flex; align-items: center; justify-content: center; - background-color: Canvas; color: CanvasText; position: fixed; width: 100%; @@ -83,6 +83,22 @@ body { color: var(--mud-palette-text-primary); } +/* On-scroll separation for the sticky header: a soft M3 level-1 shadow fades in once content passes underneath. */ +/* MD3 proper would retone the container instead, but that desyncs the natively colored status bar, so elevation stands in until edge-to-edge lands. */ +@supports (animation-timeline: scroll()) { + .page-header { + animation: header-on-scroll linear both; + animation-timeline: scroll(); + animation-range: 0 56px; + } +} + +@keyframes header-on-scroll { + to { + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 1px 3px 1px rgba(0, 0, 0, 0.15); + } +} + .page-body { width: 100%; max-width: 960px; @@ -126,23 +142,38 @@ body { gap: 8px; } -/* M3 segmented buttons: outlined container, neutral unselected text, selected segment fills secondaryContainer. */ +/* M3E connected button group: tonal segments separated by 2px gaps instead of an outlined pill with dividers. */ +/* The row of segments keeps fully rounded outer corners, and the selected segment morphs to a full pill with a secondaryContainer fill. */ .mud-toggle-group { flex-grow: 1; - border-radius: 999px; - border-color: var(--mud-palette-lines-inputs) !important; + gap: 2px; + border: none !important; + background-color: transparent; } .mud-toggle-group .mud-toggle-item { color: var(--mud-palette-text-primary); - background-color: transparent; - border-color: var(--mud-palette-lines-inputs) !important; + background-color: var(--mud-palette-gray-lighter); + border: none !important; + border-radius: 8px; min-height: 32px; + transition: border-radius 0.15s ease-out, background-color 0.15s ease-out; +} + +.mud-toggle-group .mud-toggle-item:first-child { + border-top-left-radius: 999px; + border-bottom-left-radius: 999px; +} + +.mud-toggle-group .mud-toggle-item:last-child { + border-top-right-radius: 999px; + border-bottom-right-radius: 999px; } .mud-toggle-group .mud-toggle-item.mud-toggle-item-selected { background-color: var(--mud-palette-secondary-lighten); color: var(--mud-palette-secondary-darken); + border-radius: 999px; } .mud-button { @@ -175,8 +206,13 @@ body { border-radius: 999px; } +/* The inactive track carries the M3E stop indicator dot near its trailing end. */ .mud-slider.mud-slider-primary .mud-slider-input::-webkit-slider-runnable-track { background-color: var(--mud-palette-secondary-lighten); + background-image: radial-gradient(circle, var(--mud-palette-primary) 0 2px, transparent 2.5px); + background-repeat: no-repeat; + background-position: right 5px center; + background-size: 5px 5px; } .mud-slider .mud-slider-filled, @@ -192,7 +228,8 @@ body { transform: none; border-radius: 2px; margin-top: -6px; - box-shadow: none; + /* M3E carves a gap between the handle and the track; surface-colored blocks either side of the bar fake it over the row container. */ + box-shadow: 6px 0 0 var(--mud-palette-surface), -6px 0 0 var(--mud-palette-surface); } /* M3 switch: 52x32 pill track with an outline, solid colors instead of translucent overlays, and a thumb that grows when checked. */ @@ -448,13 +485,13 @@ label.mud-switch.mud-disabled .mud-switch-span { } @media (prefers-color-scheme: dark) { - .status-bar-safe-area { + .status-bar-safe-area, #splash-screen { background-color: #181215; } } @media (prefers-color-scheme: light) { - .status-bar-safe-area { + .status-bar-safe-area, #splash-screen { background-color: #FFF8F9; } } diff --git a/README.md b/README.md index ca6fd0d..d10f33d 100644 --- a/README.md +++ b/README.md @@ -15,18 +15,18 @@ - πŸ“š **Guided worksheets** for mental health check-ins - 🚨 **Safety Plan** with your coping strategies and support contacts - πŸ’Ύ **Local backups** you can export and import as a single file +- 🎨 **Material You colors** that match your wallpaper on Android 12+ - πŸŒ™ **Light and dark themes** ## Privacy Your data never leaves your device. There is no account, no sign-up, and no cloud. See the [privacy policy](PRIVACY_POLICY.md) for details. -## Tech stack +## Tech - [.NET MAUI](https://learn.microsoft.com/dotnet/maui/) with [Blazor Hybrid](https://learn.microsoft.com/aspnet/core/blazor/hybrid/) for the UI -- [MudBlazor](https://mudblazor.com/) component library +- [MudBlazor](https://mudblazor.com/) components with custom [Material 3 Expressive](https://m3.material.io/) theming - [EF Core](https://learn.microsoft.com/ef/core/) with SQLite for local storage -- [ApexCharts](https://apexcharts.github.io/Blazor-ApexCharts/) for trends ## Contributing