A personal life management app for Android. One place for university exams, finances, tasks, groceries, goals, notes, and links — everything stored locally on-device, with no account, no backend, and no subscription required.
Built out of frustration with having a different app for every life domain — one for tasks, one for finances, one for university grades — each with its own data model, notification system, and sync requirement. LifeOS consolidates everything into a single local-first app where all data is owned by the user and nothing leaves the device.
- Preview
- Features
- Known Issues
- Tech Stack
- Architecture
- Design Decisions
- Project Structure
- Getting Started
- Usage
- Configuration and Environment
- Roadmap
- Changelog
- Contributing
- License
![]() |
![]() |
|---|---|
| Home Dashboard | University and Exams |
![]() |
![]() |
|---|---|
| Finance Tracker | Tasks (incl. recurring habits) |
![]() |
![]() |
|---|---|
| Groceries | Life Goals |
![]() |
![]() |
|---|---|
| Notes | Links |
![]() |
![]() |
|---|---|
| Statistics | All Screens |
- Mission Control stat grid: tasks done/total, current balance, weighted average grade, active goals count
- Next exam countdown card
- Pending Tasks — every incomplete task across the app sorted by urgency, not capped to today
- Quick Links grid — up to 6 starred links from the Links section as tappable shortcuts
- Every section header links directly to its full screen via a navigation icon
- Section order is drag-to-reorder and persists across sessions
- First-launch tip bubbles pointing at each section, dismissable
- Full exam CRUD — add, edit, and delete exams at any status (to start / preparing / passed)
- Exam form requires name, credits (3–15 CFU), and a precise date via a shared calendar picker — future dates only for upcoming exams, past dates within 5 years for passed ones
- Passed exams require an achieved grade; unpassed exams accept an optional expected grade
- Grades use an 18–30L typeahead selector — typing narrows the list (e.g. "3" returns
30and30L) - Preparing exams show a progress bar that fills as the exam date approaches
- Credits Progress bar showing CFU earned vs. the degree total set at onboarding
- Stat grid: Credits Earned, Exams Passed This Year, Arithmetic Average, Arithmetic Average with expected grades, Weighted Average, Weighted Average with expected grades — the "with expected" boxes auto-hide when no expected grade is entered
- Grade Simulator — enter a hypothetical grade and CFU to preview the effect on both averages before the exam
- Unified task and habit manager in a single Microsoft To Do-style screen
- Sections: Today, Upcoming, Habits, No Date
- Pinned bottom composer for quick entry without opening a modal
- Recurring habits keep a 7-day dot history and streak counter
- Edit any item via a pencil icon
- Drag-to-reorder within each section
- Income and expense entries with date, amount, and category
- Date picker with a Today shortcut for quick entry
- Edit transactions via a pencil icon
- Overview stats: balance, total income, total expenses
- 6-month balance bar chart
- Task completion chart — last 7 days
- Grade trend chart — last 8 passed exams in chronological order
- University progress: graduation percentage, weighted average, degree grade projection
- Spending breakdown by category — last 30 days
- Habit streak leaderboard — top 5
- Checklist with category tags: supermarket, pharmacy, home, other
- Filter by all, to buy, or completed
- Numeric progress goals with a labeled target and current-progress field
- Inline stepper and direct numeric input
- Priority levels, optional deadline via the shared date picker (5-year cap)
- Editable after creation
- Editable title and free-text content
- Tag autocomplete: a dropdown of previously used tags appears while typing and dismisses on confirm — tags become purple chips, keyboard stays open for the next tag
- Tags are single-word and lowercase only
- Save URLs with a name and emoji icon
- Editable via a pencil icon
- Star up to 6 links to surface them on the Home Quick Links grid
- First-launch flow: name, degree course, year (1–5), and total credits — selected from common Italian degree credit totals with a custom Other option
- Black splash screen with a centered logo on load
- Fully in English throughout, including all displayed dates
- Every list-based screen includes a Clear All action to wipe demo data and start fresh
- Ships with realistic pre-seeded demo data across every section so the app looks used from first launch
The following bugs are open and unresolved as of the most recent update:
- Drag-to-reorder on Home and in Tasks is unreliable — items sometimes deselect mid-drag and scroll speed during a drag gesture is approximately doubled
- Task completion checkbox does not always register on the first tap
- The Tasks composer does not reliably stay pinned above the on-screen keyboard while typing
- Grade Simulator grade dropdown does not commit on tap — a value can only be confirmed by typing it and pressing Enter
- Android hardware back button closes the app instead of navigating back — a direct consequence of the hand-rolled navigation (see Roadmap)
- The left-side navigation drawer can overlap the system status bar depending on the device
| Dependency | Version | Notes |
|---|---|---|
| React Native | 0.81.5 | |
| React | 19.1.0 | |
| Expo SDK | 54 | |
| expo-blur | — | iOS real blur; flat fallback on Android. Used by GlassSheet, DatePicker, and CustomAlert — not listed in package.json (see Design Decisions) |
| react-native-svg | 15.12.1 | Powers the ProgressRing component |
| AsyncStorage | 2.2.0 | Sole persistence layer — SQLite migration is a tracked roadmap item |
| New Architecture | — | Enabled via newArchEnabled: true in app.json |
All data lives on-device via AsyncStorage under a lifeos_ key prefix. No backend, no authentication, no network calls at runtime.
| Screen | Notes |
|---|---|
OnboardingScreen |
First-launch: name, degree, year, credit total |
HomeScreen |
Dashboard with reorderable sections and Quick Links |
UniScreen |
Exam tracker, credits bar, stat grid, Grade Simulator |
JournalScreen |
Unified tasks and habits — presented in the UI as Tasks |
FinancesScreen |
Income and expense tracking |
StatsScreen |
Cross-section analytics — replaces Habits in the bottom nav |
GroceriesScreen |
Shopping checklist |
GoalsScreen |
Numeric progress goals |
NotesScreen |
Notes with tags |
LinksScreen |
Bookmarks with star and reorder |
| Component | Purpose |
|---|---|
DraggableList |
Long-press-to-reorder via PanResponder — see Known Issues for current bugs |
GradeSelector |
18–30L grade picker with typeahead — see Known Issues for tap-to-confirm bug |
DatePicker |
Shared calendar picker used by Exams, Finances, and Goals — enforces context-specific date constraints |
TagInput |
Chip input with autocomplete against existing Notes tags |
GlassSheet |
Bottom-sheet modal — real BlurView on iOS, flat panel on Android |
CustomAlert |
On-brand replacement for the stock Android alert dialog |
BarChart |
Dependency-free bar chart built from plain View components |
localDateKey(d)— timezone-safeYYYY-MM-DDformatter. AvoidstoISOString(), which converts to UTC before formatting and produces off-by-one date errors in UTC+ timezones including Italy (UTC+1/+2)usePersist(key, setter)— wraps every state setter so any update auto-saves to AsyncStorage without explicit save calls at each call site- Shared
DatePickercentralizes future-only, past-only, and 5-year-cap constraints in one place rather than duplicating date validation logic per screen
Why AsyncStorage instead of SQLite? AsyncStorage was chosen to minimize native build complexity during the prototyping phase — it requires no native module compilation, works out of the box with Expo Go, and is sufficient for the current data volume (at most a few hundred records per section). The tradeoff is a flat key-value model that makes relational queries verbose. Migrating to expo-sqlite is a tracked roadmap item for when the data model stabilizes.
Why hand-rolled navigation instead of React Navigation? The initial version was built quickly to validate the feature set before committing to an architectural pattern. A useState screen switcher with a custom drawer is a deliberate short-term tradeoff — it shipped faster but blocks the Android back-button fix. React Navigation adoption is planned once the Zustand migration is complete, so global state doesn't need to be threaded through a navigation context simultaneously with a persistence refactor.
Why expo-blur without declaring it in package.json? expo-blur is a transitive dependency of Expo SDK 54 and is available without explicit declaration in an Expo managed workflow. It was not added to package.json because Expo's managed workflow guarantees its availability — adding it explicitly could cause version conflicts on future SDK upgrades. The tradeoff is that the dependency is invisible to static analysis tools, which is worth fixing before a production release.
Why pre-seed demo data instead of an empty state? An empty app on first launch creates a poor first impression — every section shows a blank screen with no indication of what it will look like when used. Pre-seeded data with realistic entries communicates the value of each section immediately and lets users evaluate the app before committing to entering their own data. A Clear All action on every screen ensures the demo data is never in the way.
Why a monolithic App.js for global state? The current approach of holding all screen-level state in App.js was the simplest way to share data across screens without a state management library. It is also the biggest architectural liability — 11+ pieces of state in one component means every small update triggers a re-render of the entire tree. Migrating to Zustand is the first item in the Roadmap.
LifeOS/
├── App.js # Root — navigation state, global state, drawer
├── app.json # Expo config (package: com.mylifeos.app)
├── eas.json # EAS Build profiles (preview APK / production AAB)
├── package.json
├── src/
│ ├── config/
│ │ ├── colors.js # Design token palette
│ │ └── nav.js # Screen registry and bottom-nav config
│ ├── data/
│ │ ├── helpers.js # localDateKey, gradeWeight, calculateAverages, …
│ │ ├── seedData.js # Pre-seeded demo data, date-relative and deterministic
│ │ └── storage.js # loadJSON / saveJSON wrappers around AsyncStorage
│ ├── components/ # Shared UI — Card, StatCard, ProgressBar, DraggableList,
│ │ # GradeSelector, DatePicker, TagInput, GlassSheet,
│ │ # CustomAlert, BarChart, FadeSlideIn, …
│ └── screens/ # One file per screen — see Architecture table above
└── images/ # UI screenshots used in this README
- Node.js and npm
- Expo Go version 54 or later on an Android device, or an Android emulator
- An Expo account if you intend to use EAS Build
git clone https://github.com/mirconegri/LifeOS.git
cd LifeOS
npm installnpx expo start -cScan the QR code with Expo Go on Android. The -c flag clears the Metro cache — run with it after any dependency change or if the app hangs on first load.
eas build --platform android --profile previewProduces an installable .apk. The production profile targets an .aab for Play Store submission — deferred until the architecture items in the Roadmap are addressed.
No .env file and no API keys required. Configuration lives in two files:
| File | Purpose |
|---|---|
app.json |
Expo metadata — app name, Android package com.mylifeos.app, EAS project ID, newArchEnabled flag |
eas.json |
EAS Build profiles — preview (APK) and production (App Bundle) |
All user data is persisted via AsyncStorage under keys prefixed with lifeos_, entirely on-device.
The following are explicitly planned and not yet implemented. Play Store publication is intentionally deferred until items 1–3 are addressed:
- Migrate global state to Zustand — remove the 11+ state pieces from
App.jsto eliminate full-tree re-renders on every update - Adopt React Navigation (Bottom Tabs + Drawer) — replaces the hand-rolled
useStatenavigator and fixes the Android back-button issue - Migrate from AsyncStorage to
expo-sqlite— enables relational queries and a JSON export / cloud backup option - Google Sign-In with cloud sync — Firebase or Supabase under evaluation; both offer a free tier sufficient for current data volumes
- Home screen widgets — quick-add expense, quick-add task, and university status at a glance without opening the app
- Ad banners — once the architecture items above are stable
| Version | Date | Highlights |
|---|---|---|
v1.7 |
Jul 2026 | Drag-to-reorder and Grade Simulator fixes (in progress); drawer safe-area padding adjustments |
v1.6 |
Jun 2026 | Left-side drawer redesign, full English localization, per-screen Clear All action, black splash screen, Study Heatmap removed from Stats |
v1.5 |
Jun 2026 | Pre-seeded demo data, onboarding credit/year presets with custom Other option, architecture audit — React Navigation / SQLite / cloud-sync roadmap defined |
v1.4 |
May 2026 | Microsoft To Do-style Tasks screen, Habits merged into Tasks, Stats replaces Habits in bottom nav, dark visual redesign |
v1.3 |
May 2026 | Goals, Links, Notes, and Habits made editable; tag autocomplete; Study section removed; drag-to-reorder rolled out app-wide |
v1.2 |
Apr 2026 | Calendar exam dates, 18–30L grade picker, working exam Edit, Grade Simulator, shared date picker, mandatory field validation |
v1.1 |
Apr 2026 | Exam progress bar, CFU fields, Credits Progress bar, drawer safe-area fix, Links text-visibility fix |
v1.0 |
Apr 2026 | Onboarding flow, study timer removed, Quick Links widget on Home, custom delete dialogs, first-launch tips |
- Fork the repository
- Create a feature branch (
git checkout -b feature/your-feature) - Commit your changes with a clear message
- Open a Pull Request
For bugs or feature ideas, open an Issue.
Mirco Negri — Computer Science @ UniTrento
This project is licensed under the MIT License — see the LICENSE file for details.









