A calm, minimal mood-tracking app for high-achieving people who struggle to check in with themselves during busy seasons. Built with .NET MAUI, designed around a single morphing mood orb that merges a 1–5 scale, a pastel color, and an emotive face into one quiet daily ritual.
This is also a working demo of LaunchDarkly mobile observability + session replay — every meaningful user action emits a span, and screen activity is recorded with text-input masking applied automatically.
- Onboarding — a quiet wordmark and a single Begin button. Shown once.
- Today — time-of-day greeting, today's status card (empty CTA or logged orb + truncated note), a Monday-start week strip with mood-colored dots, recent reflections, and a one-line weekly insight (A brighter stretch / Mostly steady / A heavier few days).
- Check-in — three light steps:
- Mood scale. Tap one of five points; the orb's color and face morph live, and the page picks up a faint tint of the chosen mood.
- Feeling tags. Multi-select from a fixed vocabulary (Calm, Grateful, Tired, Anxious, Hopeful, Overwhelmed, Content, Energized, Proud, Stressed, Peaceful, Focused, Lonely, Restless).
- Journal note. Optional serif editor. Saving writes an entry under today's date.
- History — a month calendar with Mon-start week. Logged days render as mood-colored circles; tap one to open its entry detail. Bottom of the page carries the 5-step mood-scale legend.
- Entry detail — back chevron, weekday eyebrow + serif date, time, big orb + label, feeling chips, and the full note (or an italic empty-state line when there is none).
| Score | Label | Color (pastel) |
|---|---|---|
| 1 | Rough | dusty blue #A8B8C9 |
| 2 | Low | lavender #B6AECC |
| 3 | Okay | sage #B7CDB3 |
| 4 | Good | sand #D4C896 |
| 5 | Great | apricot #E8B898 |
The orb's mouth is a quadratic curve whose control point shifts by score — frown at 1, neutral at 3, smile at 5. All five colors share low chroma so the screen never shouts.
- .NET MAUI (net10.0) targeting iOS and Android
- CommunityToolkit.Mvvm for source-generated
ObservableProperty/RelayCommand - MAUI
Preferencesfor local JSON-serialized persistence - LaunchDarkly Client SDK (
5.x) — feature flags - LaunchDarkly Observability — traces wrapped around user actions
- LaunchDarkly Session Replay (
0.x) — text-input masking on by default
Build targets:
net10.0-iosandnet10.0-android. MacCatalyst is not supported byLaunchDarkly.SessionReplay 0.10.x(it ships binaries only fornet9.0-iosandnet9.0-android).
mood-tracker/
├── App.xaml(.cs) application root + resource dictionaries
├── AppShell.xaml(.cs) Shell with Login + Onboarding + main TabBar
├── MauiProgram.cs DI registration + LaunchDarkly client bootstrap
│
├── Models/
│ ├── MoodScore.cs 1–5 enum + Label/Color extensions
│ ├── MoodEntry.cs date, score, feelings, note, time
│ └── FeelingTag.cs fixed feeling vocabulary
│
├── Services/
│ ├── IEntryStore.cs GetAll / GetByDate / Upsert
│ └── EntryStore.cs Preferences-backed JSON store, seeds demo data once
│
├── Controls/
│ └── MoodOrbView.cs reusable pastel orb with morphing face
│
├── Converters/
│ ├── InvertedBoolConverter.cs
│ ├── ScoreToLabelConverter.cs
│ └── HasNoteToFontAttrConverter.cs
│
├── ViewModels/
│ ├── BaseViewModel.cs
│ ├── LoginViewModel.cs
│ ├── OnboardingViewModel.cs
│ ├── TodayViewModel.cs + DayDot, ReflectionRow
│ ├── CheckInViewModel.cs + MoodOption, FeelingChip
│ ├── HistoryViewModel.cs + CalendarCell, MoodLegendItem
│ └── EntryDetailViewModel.cs
│
├── Pages/
│ ├── LoginPage.xaml(.cs)
│ ├── OnboardingPage.xaml(.cs)
│ ├── TodayPage.xaml(.cs)
│ ├── CheckInPage.xaml(.cs)
│ ├── HistoryPage.xaml(.cs)
│ └── EntryDetailPage.xaml(.cs)
│
├── Observability/
│ └── LDConfig.cs mobile key, service name, feature flag keys
│
└── Resources/Styles/
├── Colors.xaml Tend palette tokens + mood pastels
└── Styles.xaml typography, page bg, card border, etc.
- macOS with Xcode (for iOS) or Android SDK/emulator (for Android)
- .NET 10 SDK with the MAUI workload:
dotnet workload install maui
Tend ships with a placeholder LaunchDarkly mobile key in Observability/LDConfig.cs. Replace it with a key from your own LaunchDarkly project (Account → Projects → Environments → mobile SDK key):
public const string MobileKey = "mob-XXXXXXXX-...";
public const string ServiceName = "mood-tracker-maui-demo";If you skip this step the app still runs locally — LaunchDarkly just won't receive anything.
# iOS simulator
dotnet build -f net10.0-ios
# Android
dotnet build -f net10.0-androidUse your IDE (Visual Studio, Rider, VS Code with the .NET MAUI extension) to deploy to a simulator/emulator or device. From the CLI:
# iOS simulator
dotnet build -t:Run -f net10.0-ios
# Android emulator
dotnet build -t:Run -f net10.0-androidFirst launch flows through Login → Onboarding → Today. After onboarding completes once, subsequent launches go straight from Login to Today (the flag is stored in Preferences under tend.hasOnboarded).
A single MoodEntry per day, keyed by ISO date:
public class MoodEntry
{
public string Date { get; set; } // "2026-06-23"
public MoodScore Score { get; set; } // 1–5
public List<string> Feelings { get; set; } = new();
public string Note { get; set; } = "";
public string Time { get; set; } = ""; // "9:41 AM"
}Entries are JSON-serialized into Preferences under tend.entries.v1. On first launch the store seeds ~3 weeks of plausible demo entries (gated by tend.seeded.v1) so Today and History have something to render immediately.
Each meaningful user action opens an active span via LDObserve.StartActiveSpan(...):
| Action | Span | Attributes |
|---|---|---|
| Sign in | Login |
username.length |
| Onboarding complete | Onboarding.Begin |
— |
| Open Today | TodayPage.Refresh |
today.logged, reflection.count |
| Save check-in | CheckIn.Save |
score, feeling.count, note.length |
| Open History | HistoryPage.BuildCalendar |
month, logged |
| Open Entry | EntryDetailPage.Load |
date |
Session Replay is enabled with maskTextInputs: true so journal text and the password field are blocked in recordings by default. PasswordEntry.LDMask() is also called from LoginPage as belt-and-suspenders.
- Deep dark mode (palette is in
Colors.xaml; needsAppThemeBindingplumbing) - Settings panel: tone of voice (Gentle / Direct / Playful), faces on/off, week-start Mon/Sun
- Name entry during onboarding to personalize the Today greeting
- Reminders / notifications
- Trends & insights view (chart of last 30 days, streaks, mood distribution)
- Real backend sync as an alternative to local-only Preferences
Design system inspired by the Tend product mockup explored at the start of this project — soft pastels, warm off-white surfaces, serif headlines (Georgia), Hanken Grotesk fallback (OpenSans) for UI.
Built with .NET MAUI, CommunityToolkit.Mvvm, and the LaunchDarkly Client SDK.