feat: Murattal player enhancements & prayer schedule auto-scroll

- Murattal: Spotify-style 5-button controls [Shuffle, Prev, Play, Next, Playlist]
- Murattal: Animated 7-bar equalizer visualization in player circle
- Murattal: Unsplash API background with frosted glass player overlay
- Murattal: Transparent AppBar with backdrop blur
- Murattal: Surah playlist bottom sheet with full 114 Surah list
- Murattal: Auto-play disabled on screen open, enabled on navigation
- Murattal: Shuffle mode for random Surah playback
- Murattal: Photographer attribution per Unsplash guidelines
- Dashboard: Auto-scroll prayer schedule to next active prayer
- Fix: setState lifecycle errors on Reading & Murattal screens
- Setup: flutter_dotenv, cached_network_image, url_launcher deps
This commit is contained in:
dwindown
2026-03-13 15:42:17 +07:00
commit faadc1865d
189 changed files with 23834 additions and 0 deletions

884
PRD.md Normal file
View File

@@ -0,0 +1,884 @@
# Product Requirements Document
## Jamshalat Diary — Islamic Worship Companion App
**Version:** 1.0
**Date:** March 2026
**Platform:** Flutter (iOS + Android)
**Status:** Draft
---
## Table of Contents
1. [Overview](#1-overview)
2. [Target Users](#2-target-users)
3. [Design System](#3-design-system)
4. [App Architecture](#4-app-architecture)
5. [Navigation](#5-navigation)
6. [Feature Specifications](#6-feature-specifications)
- 6.1 Dashboard
- 6.2 Prayer Calendar (Imsakiyah)
- 6.3 Daily Checklist
- 6.4 Dzikir
- 6.5 Reports (Laporan)
- 6.6 Qibla Finder
- 6.7 Quran Reading
- 6.8 Quran Murattal
- 6.9 Settings
7. [Data Model](#7-data-model)
8. [Third-Party Dependencies](#8-third-party-dependencies)
9. [Non-Functional Requirements](#9-non-functional-requirements)
10. [Permissions](#10-permissions)
11. [Out of Scope (v1.0)](#11-out-of-scope-v10)
---
## 1. Overview
**Jamshalat Diary** is an offline-first Muslim daily worship companion app built in Flutter. It helps Muslim users track their daily prayers, worship habits, and spiritual growth with a clean, modern UI that supports both light and dark themes.
**Core value proposition:**
- Never miss a prayer — real-time prayer time countdowns with Adhan/Iqamah notifications
- Track daily worship completion — checklist for Sholat, Tilawah, Dzikir
- Build consistent habits — weekly/monthly progress reports
- All-in-one Islamic toolkit — Qibla compass, Quran reader, Murattal player, Dzikir counter
---
## 2. Target Users
**Primary:** Muslim adults (1845) who want to improve consistency in daily worship
**Secondary:** Parents tracking worship habits for the family
**User goals:**
- Know exact prayer times for their location, offline
- Get reminded for Adhan and Iqamah
- Log daily ibadah (worship) completion
- Read Quran and perform guided Dzikir
- Find Qibla direction while traveling
- Review worship quality over time
---
## 3. Design System
### 3.1 Color Tokens
| Token | Light Value | Dark Value | Usage |
|---|---|---|---|
| `primary` | `#70df20` | `#70df20` | Active states, CTAs, progress fills |
| `background` | `#f7f8f6` | `#182111` | App background |
| `surface` | `#ffffff` | `#1e2a14` | Cards, bottom nav |
| `sage` | `#728764` | `#728764` | Secondary text, section labels |
| `cream` | `#f2f4f0` | — | Dividers, borders (light mode) |
| `on-primary` | `#0a1a00` | `#0a1a00` | Text on primary bg |
| `text-primary` | `#1a2a0a` | `#f2f4f0` | Body text |
| `text-secondary` | `#64748b` | `#94a3b8` | Captions, labels |
| `error` | `#ef4444` | `#f87171` | Error states |
| `success` | `#22c55e` | `#4ade80` | Success/completed states |
### 3.2 Typography
| Style | Font | Weight | Size | Usage |
|---|---|---|---|---|
| `displayLarge` | Plus Jakarta Sans | 800 (ExtraBold) | 32sp | Hero numbers (next prayer) |
| `headlineMedium` | Plus Jakarta Sans | 700 (Bold) | 24sp | Screen titles, section headers |
| `titleMedium` | Plus Jakarta Sans | 600 (SemiBold) | 16sp | Card titles, nav labels |
| `bodyLarge` | Plus Jakarta Sans | 400 (Regular) | 16sp | Body text |
| `bodySmall` | Plus Jakarta Sans | 400 (Regular) | 12sp | Captions, timestamps |
| `labelSmall` | Plus Jakarta Sans | 700 (Bold) | 10sp | Uppercase tags, section labels |
| `arabicBody` | Amiri | 400 (Regular) | 24sp | Quran verses, Dzikir Arabic text |
| `arabicLarge` | Amiri | 700 (Bold) | 28sp | Surah headings in Arabic |
### 3.3 Spacing & Shape
| Token | Value | Flutter |
|---|---|---|
| `radiusSm` | 8dp | `BorderRadius.circular(8)` |
| `radiusMd` | 12dp | `BorderRadius.circular(12)` |
| `radiusLg` | 16dp | `BorderRadius.circular(16)` |
| `radiusXl` | 24dp | `BorderRadius.circular(24)` |
| `radiusFull` | 9999dp | `StadiumBorder()` |
| `spacingXs` | 4dp | — |
| `spacingSm` | 8dp | — |
| `spacingMd` | 16dp | — |
| `spacingLg` | 24dp | — |
| `spacingXl` | 32dp | — |
### 3.4 Iconography
- **Library:** Material Symbols Outlined (via `material_symbols_icons` Flutter package)
- **Filled variant:** Used for active bottom nav tab icons only
- **Size:** 24dp default, 20dp for compact rows, 32dp for feature section icons
### 3.5 Dark Mode
- Toggled via user preference in Settings (stored locally)
- Options: **Light**, **Dark**, **System (Auto)**
- Implemented via Flutter `ThemeMode``ThemeMode.light`, `ThemeMode.dark`, `ThemeMode.system`
- All color tokens have explicit light and dark values; no transparency hacks
---
## 4. App Architecture
### 4.1 Structure
```
lib/
├── main.dart
├── app/
│ ├── app.dart # MaterialApp.router + theme + locale
│ ├── router.dart # GoRouter — shell route for bottom nav
│ └── theme/
│ ├── app_theme.dart # ThemeData light + dark
│ ├── app_colors.dart # AppColors class with static consts
│ └── app_text_styles.dart # TextTheme definitions
├── core/
│ ├── widgets/
│ │ ├── bottom_nav_bar.dart
│ │ ├── prayer_time_card.dart
│ │ ├── section_header.dart
│ │ ├── ios_toggle.dart
│ │ ├── progress_bar.dart
│ │ └── circular_progress_indicator_custom.dart
│ ├── utils/
│ │ ├── date_utils.dart
│ │ ├── prayer_utils.dart # Hijri date conversion helpers
│ │ └── arabic_utils.dart # RTL text helpers
│ └── providers/
│ └── theme_provider.dart # ThemeMode state via Riverpod
├── features/
│ ├── dashboard/
│ │ ├── data/
│ │ ├── domain/
│ │ └── presentation/
│ │ ├── dashboard_screen.dart
│ │ └── widgets/
│ ├── imsakiyah/
│ ├── checklist/
│ ├── dzikir/
│ ├── laporan/
│ ├── qibla/
│ ├── quran/
│ │ ├── presentation/
│ │ │ ├── quran_screen.dart # Surah list
│ │ │ ├── quran_reading_screen.dart
│ │ │ └── quran_murattal_screen.dart
│ └── settings/
└── data/
├── local/
│ ├── hive_boxes.dart # Box names constants
│ └── adapters/ # Hive TypeAdapters
└── services/
├── prayer_service.dart # Adhan calculation
├── location_service.dart # GPS + last known
├── notification_service.dart
└── quran_service.dart # Local JSON asset
```
### 4.2 State Management
**Riverpod** (flutter_riverpod + riverpod_annotation + riverpod_generator)
- Every feature has its own `*_provider.dart`
- Async data via `AsyncNotifierProvider`
- UI state (loading, error, data) handled via `AsyncValue`
- Theme mode via `StateProvider<ThemeMode>`
### 4.3 Local Storage
**Hive** for offline-first persistence:
| Box | Key | Value type |
|---|---|---|
| `settings` | String key | dynamic |
| `checklist_items` | date string (yyyy-MM-dd) | `List<ChecklistItem>` |
| `worship_logs` | date string | `WorshipLog` |
| `dzikir_counters` | dzikir ID | int count |
| `cached_prayer_times` | `lat_lng_date` | `PrayerTimes` |
---
## 5. Navigation
### 5.1 Bottom Navigation Bar (5 tabs)
| Index | Label | Icon (inactive) | Icon (active) | Route |
|---|---|---|---|---|
| 0 | Home | `home_outlined` | `home` (filled) | `/` |
| 1 | Calendar | `calendar_today_outlined` | `calendar_today` | `/imsakiyah` |
| 2 | Checklist | `rule_outlined` | `rule` (filled) | `/checklist` |
| 3 | Reports | `bar_chart_outlined` | `bar_chart` | `/laporan` |
| 4 | Tools | `auto_fix_high_outlined` | `auto_fix_high` (filled) | `/tools` |
- Bottom nav is persistent across all 5 tabs (shell route via GoRouter)
- Safe area padding (bottom) applied to nav bar (`pb: 24dp`)
- Active tab: `primary` text + filled icon
- Inactive tab: `text-secondary` color
### 5.2 Full Route Map
```
/ → DashboardScreen
/qibla → QiblaScreen (push, no bottom nav)
/imsakiyah → ImsakiyahScreen
/checklist → ChecklistScreen
/laporan → LaporanScreen
/tools → ToolsScreen (hub for Dzikir, Quran, Qibla)
/tools/dzikir → DzikirScreen
/tools/quran → QuranListScreen
/tools/quran/:surahId → QuranReadingScreen
/tools/quran/:surahId/murattal → QuranMurattalScreen
/tools/qibla → QiblaScreen
/settings → SettingsScreen (push from Dashboard header)
```
---
## 6. Feature Specifications
---
### 6.1 Dashboard
**Route:** `/`
**Description:** App home screen showing next prayer, daily prayer schedule, checklist summary, and weekly progress.
#### UI Components
**Header (sticky)**
- Left: Circular user avatar (40dp, primary border 2dp) + greeting text ("Welcome back," / user name "Assalamu'alaikum, [Name]")
- Right: Notification bell `IconButton` → opens notification settings
**Next Prayer Hero Card**
- Full-width card, `bg-primary`, `borderRadius: 24dp`, `padding: 20dp`, `boxShadow: lg`
- Content:
- Label: "Next Prayer" with `schedule` icon
- Title: `"{PrayerName} at {HH:mm}"``displayLarge` weight 800
- Subtitle: `"Countdown: HH:mm:ss"` — live countdown timer updating every second
- Actions row:
- "View Qibla" button (`black bg`, `white text`, `explore icon`, `borderRadius: full`)
- Volume/mute toggle button (`white/30 backdrop-blur`, `rounded-full`)
- Decorative: white/20 blurred circle blob (top-right, size 120dp)
**Prayer Times Horizontal Scroll**
- Section title: "Daily Prayer Times" + "Today" chip (`primary/10 bg`, `primary text`)
- Horizontal `ListView.builder`, no scroll indicator, `padding: 16dp horizontal`
- Each card: `width: 112dp`, `borderRadius: 16dp`, `border: primary/10`
- Icon (Material Symbol): Fajr→`wb_twilight`, Dhuhr→`wb_sunny`, Asr→`filter_drama`, Maghrib→`wb_twilight`, Isha→`dark_mode`
- Prayer name (`sm font-bold`)
- Time string (`xs text-secondary`)
- **Active prayer card:** `bg-primary/10`, `border-2 border-primary`, primary text color
- **Adhan/Iqamah variant:** Active card shows notification badge (small bell icon, white circle, shadow, absolute top-right)
**Daily Checklist Summary Card**
- Title: "Today's Checklist" + subtitle "{n} dari {total} Ibadah selesai"
- Circular SVG progress indicator (48dp, `strokeWidth: 4`, `primary` stroke)
- Percentage text centered inside circle
- 2 preview items: "Sholat Fardhu (4 of 5)" and "Tilawah Quran (1 Juz)"
- Completed items: `check_circle` icon in `primary` color
- "View Full Checklist" CTA button → navigates to `/checklist`
**Weekly Progress Chart**
- Title: "Weekly Progress"
- `Container` with `bg-surface`, `borderRadius: 16dp`, `padding: 20dp`
- 7 vertical bars (MonSun): each bar is `Expanded`, `bg-primary/20`, with `primary` fill overlay proportional to completion %
- Day labels below each bar: `10sp`, `font-bold`, `text-secondary`
#### Behavior
- Countdown timer refreshes every 1 second via `Timer.periodic`
- Prayer times are calculated from device location via `adhan` package on app start
- If location unavailable, use last cached location; if none, prompt user
- Notification badge on prayer card: shown when Adhan has been called (within current window)
- Tapping the Next Prayer card → navigates to Imsakiyah screen
#### Acceptance Criteria
- [ ] Correct prayer times displayed for device's current GPS location
- [ ] Countdown shows real-time seconds tick
- [ ] Active prayer card highlighted with `primary` border and color
- [ ] Checklist summary reflects today's actual completion state from local storage
- [ ] Weekly chart bars reflect daily worship logs from past 7 days
- [ ] Works fully offline (cached prayer times used when no internet)
---
### 6.2 Prayer Calendar (Imsakiyah)
**Route:** `/imsakiyah`
**Description:** Full Hijri-calendar view of prayer times, organized by month, with location selection.
#### UI Components
**Header**
- Back arrow + "Prayer Calendar" (centered, `headlineMedium`) + `more_vert` menu button
**Month Selector**
- Horizontal scrolling chip row (no scrollbar)
- Selected: `bg-primary`, `text-slate-900`, `font-semibold`, `borderRadius: full`
- Unselected: `bg-surface`, `text-secondary`, `borderRadius: full`
- Months shown in Hijri format: "Ramadan 1445H", "Shawwal 1445H", etc.
**Location Card**
- `bg-surface`, `borderRadius: 16dp`, `border: 1dp`
- `location_on` icon (primary) + "Your Location" label + city name (e.g., "Jakarta, Indonesia")
- `expand_more` chevron — tapping opens city search/picker
**Prayer Times Table**
- 7-column grid: Day | Fajr | Sunrise | Dhuhr | Asr | Maghrib | Isha
- Header row: `bg-primary/10`, `10sp font-bold uppercase tracking-wider text-secondary`
- Data rows: alternating subtle bg for readability
- Today's row: highlighted with `primary/5` background, bold text
#### Behavior
- Loads prayer times for entire selected month using `adhan` package
- Location defaults to last GPS fix; editable via city search
- City search: local bundled list of major Indonesian cities (offline), Geocoding API optional
- Changing month or location recalculates and re-renders table
- Scroll position resets to today's row on initial load
#### Acceptance Criteria
- [ ] Displays complete monthly prayer timetable for selected Hijri month
- [ ] Today's row is visually highlighted
- [ ] Month chip scroll updates table data
- [ ] Location change triggers recalculation
- [ ] Works offline with bundled city coordinates
---
### 6.3 Daily Checklist
**Route:** `/checklist`
**Description:** Daily worship completion tracker with custom checklist items and progress visualization.
#### UI Components
**Header**
- "Daily Worship" (`headlineMedium`) + date string ("Tuesday, 24 Oct") + calendar icon button (date picker)
**Progress Card**
- `bg-slate-900 / bg-primary/10 (dark)`, `borderRadius: 16dp`, `padding: 20dp`
- Decorative `auto_awesome` icon (64sp, opacity 10%, top-right)
- "Today's Goal" label (`xs uppercase tracking-wider text-slate-400`)
- Percentage: "{n}% Complete" (`displayLarge font-bold white`)
- "{completed} / {total} Tasks" (`primary color xs`)
- Progress bar: `h-12dp`, `bg-white/10`, `primary fill`, `borderRadius: full`
- Motivational quote text below bar (`xs text-slate-300`)
**Task List**
Section header: "Religious Tasks" (`sm font-bold uppercase tracking-widest text-secondary`)
Each checklist item:
- `Container` with `bg-surface / bg-primary/5 (dark)`, `borderRadius: 12dp`, `border: 1dp`
- Custom checkbox: 24dp square, `border-2 border-primary/30`, `borderRadius: 6dp`
- Checked state: `bg-primary`, white checkmark SVG inside
- Task label: `bodyLarge font-medium`
- Optional: sub-label (e.g., target count for Tilawah)
**Default checklist items (seeded on first launch):**
| Item | Category | Default Target |
|---|---|---|
| Sholat Fajr | Sholat Fardhu | 1x |
| Sholat Dhuhr | Sholat Fardhu | 1x |
| Sholat Asr | Sholat Fardhu | 1x |
| Sholat Maghrib | Sholat Fardhu | 1x |
| Sholat Isha | Sholat Fardhu | 1x |
| Tilawah Quran | Tilawah | 1 Juz |
| Dzikir Pagi | Dzikir | 1 session |
| Dzikir Petang | Dzikir | 1 session |
| Sholat Sunnah Rawatib | Sunnah | 1x |
| Shodaqoh | Charity | 1x |
#### Behavior
- Checklist resets daily at midnight (new date key in Hive)
- Checking/unchecking an item updates Hive immediately (no "save" button)
- Progress card and percentage update reactively via Riverpod
- Motivational quotes rotate from a bundled list
- User can add/remove/reorder checklist items (edit mode)
- Completion data written to `worship_logs` for use by Reports feature
#### Acceptance Criteria
- [ ] Default 10 items seeded on first launch
- [ ] Checking item updates progress bar + percentage in real time
- [ ] Data persists across app restarts (Hive)
- [ ] New empty checklist created automatically on date change
- [ ] Historical completion accessible by Reports feature
---
### 6.4 Dzikir
**Route:** `/tools/dzikir`
**Description:** Guided morning and evening remembrance (Dzikir) with Arabic text, transliteration, translation, and tap counter.
#### UI Components
**Header (sticky)**
- `back arrow` + "Dzikir Pagi & Petang" (centered, `titleLarge font-bold`) + `info` icon button
- `bg-surface/80`, `backdropFilter: blur(12dp)`, `borderBottom: 1dp primary/10`
**Tab Bar**
- 2 tabs: "Pagi" (Morning) and "Petang" (Evening)
- Active tab: `border-bottom-2 border-primary`, `text-primary`, `font-semibold`
- Inactive tab: `text-secondary`
**Hero Banner**
- `text-center`, `padding: 32dp vertical`
- `bg-gradient(primary/5 → transparent, top → bottom)`
- Title: "Dzikir Pagi / Petang" (`headlineMedium font-bold`)
- Subtitle: context text in Indonesian (`bodySmall text-secondary max-width: 280dp`)
**Dzikir Cards (scrollable list)**
- Each card: `bg-surface`, `borderRadius: 16dp`, `border: 1dp primary/10`, `padding: 20dp`, `margin: 8dp bottom`
- **Arabic text** (`Amiri font`, `24sp`, `RTL direction`, `line-height: 2.0`, `text-right`)
- **Transliteration** (`bodySmall`, `italic`, `text-secondary`, `mt: 12dp`)
- **Translation (Indonesian)** (`bodyMedium`, `text-primary`, `mt: 8dp`)
- **Counter row:**
- "Dibaca: {count} / {target}x" label
- `+` tap button (`bg-primary/10`, `text-primary`, `borderRadius: full`, `size: 40dp`)
- Counter increments on tap; fills to target
- When target reached: button becomes `check_circle` (green), card shows completion glow
#### Behavior
- Default content: bundled local JSON with standard Dzikir Pagi (~20 items) and Dzikir Petang (~20 items)
- Counter state persisted per dzikir per session in Hive (`dzikir_counters` box)
- Counter resets daily (tied to date)
- "Pagi" tab auto-selected between Fajr and Dhuhr; "Petang" between Maghrib and Isha; user can override
- Info button → bottom sheet with brief explanation of dzikir practice
#### Acceptance Criteria
- [ ] Arabic text renders correctly with Amiri font, RTL direction
- [ ] Tap counter increments and persists within the day
- [ ] Counter resets the next day
- [ ] Tab switches between Pagi and Petang content
- [ ] Completion state shown when all counters reach target
---
### 6.5 Reports (Laporan)
**Route:** `/laporan`
**Description:** Visual analytics of worship completion across weekly, monthly, and yearly timeframes.
#### UI Components
**Header**
- Back arrow + "Worship Quality Report" (centered) + `share` icon button
**Tab Bar**
- 3 tabs: Weekly · Monthly · Yearly
- Active: `border-bottom-2 border-primary text-primary`
- Tab bar: `border-bottom: 1dp`
**Main Chart Card**
- `bg-surface`, `borderRadius: 16dp`, `border: 1dp`, `padding: 20dp`
- Header row:
- Left: `analytics` icon badge (`bg-primary/10`, `primary`, `borderRadius: 12dp`, `40dp size`)
- Center: "Daily Completion" label (`bodySmall text-secondary`) + percentage (`displayLarge font-bold`)
- Right: trend chip: `trending_up` icon + delta % (`text-emerald-500` if positive)
- **Bar Chart:**
- `height: 160dp`, flex row of 7 bars (weekly) or 30/12 bars
- Each bar: `Expanded`, `bg-primary/20` track, `bg-primary` fill overlay (proportional to % complete)
- `borderRadius: top only (full)`
- Day/date labels below (`10sp font-bold text-secondary uppercase`)
- Tapping a bar → shows tooltip with exact date + completion %
**Summary Stats Row (below chart)**
- 3 stat cards in a row:
- Best streak: "{n} days" + `local_fire_department` icon
- Average: "{n}%" + `percent` icon
- Total completed: "{n} tasks" + `check_circle` icon
#### Behavior
- Weekly: shows past 7 days (MonSun of current week)
- Monthly: shows all days of current month (30/31 bars, may need scroll)
- Yearly: shows 12 months as bars
- Data sourced from `worship_logs` Hive box (daily completion records)
- Share button: generates a shareable image/text summary of current period stats
#### Acceptance Criteria
- [ ] Correct bar heights proportional to actual daily completion %
- [ ] Tab switching updates chart data and labels
- [ ] Tooltip on bar tap shows date + details
- [ ] Summary stats calculated correctly from logs
- [ ] Empty state when no logs exist ("Start tracking to see your progress")
---
### 6.6 Qibla Finder
**Route:** `/tools/qibla` or `/qibla` (accessible from Dashboard hero card)
**Description:** Compass-based Qibla direction finder showing the direction of Mecca.
#### UI Components
**Header**
- Back arrow + "Qibla Finder" (centered) + `my_location` button (top-right, re-centers GPS)
**Main Content (centered)**
- Location display: `location_on` icon (primary) + city name + Qibla degree ("142.3° from North")
- **Compass widget:**
- Circular compass with N/S/E/W labels
- Rotating needle pointing to Qibla direction
- Mosque silhouette icon overlaid at compass center (fade-to-transparent mask top)
- Green pointer / arrow indicating Qibla direction
- Accuracy indicator: "High accuracy" / "Low accuracy" based on sensor confidence
#### Behavior
- Uses `flutter_qiblah` package for Qibla calculation + `flutter_compass` for device heading
- Rotates compass ring based on device orientation (sensor stream)
- Displays degree from North
- If location permission denied → prompt to enable, fallback to manual city entry
- Mosque silhouette uses a local SVG/image asset with `ShaderMask` fade
#### Acceptance Criteria
- [ ] Compass rotates smoothly with device orientation
- [ ] Qibla arrow points to correct direction based on GPS coordinates
- [ ] Works offline (no internet needed for calculation)
- [ ] Graceful fallback if compass sensor unavailable
---
### 6.7 Quran Reading
**Route:** `/tools/quran``/tools/quran/:surahId`
**Description:** Full Quran reader with Arabic text, Indonesian translation, and verse-by-verse display.
#### UI Components
**Surah List Screen (`/tools/quran`)**
- Search bar at top
- `ListView` of 114 Surahs: number badge + Arabic name + Latin name + verse count + Juz info
**Reading Screen (`/tools/quran/:surahId`)**
Header (sticky, `bg-surface/80 backdrop-blur`):
- Back arrow
- Center column: Surah name (Arabic, `Amiri`) + "Juz {n}" label + verse count
- `more_vert` menu (bookmarks, jump to verse, settings)
**Bismillah banner:** Centered, Arabic font, before verse 1 (except Surah 9)
**Verse Cards:**
- Each verse: `Container`, `bg-surface`, `borderRadius: 12dp`, `padding: 16dp`, `border: 1dp`
- Verse number badge: small circle, `bg-primary/10`, `primary text`, left-aligned
- **Arabic text:** `Amiri`, `28sp`, `RTL`, `line-height: 2.2`, right-aligned, full width
- **Transliteration** (optional, toggled in settings): `bodySmall italic text-secondary`
- **Indonesian translation:** `bodyMedium text-primary`, left-aligned, `mt: 8dp`
- Verse action row: `bookmark`, `share`, `play` (Murattal) icons
#### Behavior
- Quran data: bundled local JSON asset (`assets/quran/quran_id.json`) — 114 surahs, Arabic + Indonesian translation
- Reading position persisted per Surah (last verse read)
- Bookmarks stored in Hive
- "Play" icon on verse → navigates to Murattal screen for that Surah starting at that verse
- Font size adjustable via settings (stored preference)
#### Acceptance Criteria
- [ ] All 114 Surahs accessible
- [ ] Arabic text renders with Amiri font, correct RTL layout
- [ ] Indonesian translation displayed below each verse
- [ ] Reading position saved across app restarts
- [ ] Bookmarking a verse persists in Hive
- [ ] Works fully offline
---
### 6.8 Quran Murattal
**Route:** `/tools/quran/:surahId/murattal`
**Description:** Audio recitation player synchronized with Quran text display.
#### UI Components
**Header:** Same as Quran Reading (Surah name + Juz info)
**Quran Text:** Same as Reading screen — synchronized verse highlight follows audio playback
**Audio Player (bottom persistent panel)**
- Reciter name + surah name
- Progress slider (current position / total duration)
- `skip_previous` | `replay_10` | Play/Pause (`play_circle` / `pause_circle`, 56dp) | `forward_10` | `skip_next`
- Playback speed selector (0.75x, 1x, 1.25x, 1.5x)
- Sleep timer button
#### Behavior
- Audio source: Bundled MP3s for commonly used Surahs (short ones: Al-Fatihah, Juz Amma) — OR streamed from a free Quran audio API (e.g., mp3quran.net)
- Currently playing verse highlighted with `primary/10 bg` + left border accent
- Auto-scrolls to current verse during playback
- Background audio playback (continues when app backgrounded)
- Notification media controls shown in system tray during playback
#### Acceptance Criteria
- [ ] Audio plays and pauses correctly
- [ ] Current verse highlighted in sync with audio (best effort with timed segments)
- [ ] Background playback works (audio continues when screen off)
- [ ] System notification with media controls displayed during playback
- [ ] Playback speed adjustment works
---
### 6.9 Settings
**Route:** `/settings`
**Description:** User profile, notification preferences, display preferences, and app info.
#### UI Components
**Header (sticky)**
- Back arrow + "Settings" (`titleLarge font-bold`) + no right action
**Profile Section**
- Avatar: 64dp circle, `bg-primary/20`, `border-2 border-primary`, initials or photo
- Name: (`titleMedium font-bold`)
- Email: (`bodySmall text-secondary`)
- Edit button (`text-primary`, `edit` icon, top-right of card) → edit name/email inline
**Notification Settings Group**
Label: "NOTIFICATIONS" (`labelSmall uppercase tracking-wider sage color`)
Rows (separated by thin divider):
- **Adhan Notification** — per prayer toggle: Fajr, Dhuhr, Asr, Maghrib, Isha
- **Iqamah Reminder** — offset in minutes (default: 10 min, stepper or picker)
- **Daily Checklist Reminder** — time picker (default: 9:00 AM)
Each row: `leading icon (bg-primary/10, rounded-lg, 40dp)` + `label + subtitle` + **iOS-style toggle**
**iOS-style toggle spec:**
- Size: `51dp × 31dp`
- Track: `bg-cream (off)` / `bg-primary (on)`, `borderRadius: full`
- Thumb: `27dp` white circle, `shadow-md`, animates left↔right on toggle
- Implemented via `AnimatedContainer` + `GestureDetector`
**Display Settings Group**
Label: "DISPLAY"
Rows:
- **Dark Mode**: Light / Dark / Auto (3-way segmented control or cycle toggle)
- **Font Size**: Small / Medium / Large (affects Quran + Dzikir text)
- **Language**: Indonesian / English (UI language, not Quran translation)
**About Group**
Label: "ABOUT"
Rows:
- App Version: "Jamshalat Diary v1.0.0"
- Privacy Policy (launches in-app browser)
- Rate the App (links to store)
- Contact / Feedback
#### Behavior
- All settings persisted in Hive `settings` box immediately on change
- Dark mode change applies instantly (no restart needed) via ThemeMode Riverpod provider
- Notification toggles register/unregister `flutter_local_notifications` channels
- Iqamah offset: default 10 minutes, adjustable per prayer
- Profile name/email stored locally only (no backend account system in v1.0)
#### Acceptance Criteria
- [ ] All toggle states persisted and restored on restart
- [ ] Dark mode applies instantly with animation
- [ ] Adhan/Iqamah notifications schedule correctly based on calculated prayer times
- [ ] Notifications cancel when their toggle is turned off
- [ ] iOS-style toggle animation is smooth (no jank)
---
## 7. Data Model
### 7.1 Hive Boxes & Schemas
```dart
// Settings box (key-value)
class AppSettings {
String userName; // 'Alex Rivers'
String userEmail; // 'alex@example.com'
ThemeMode themeMode; // ThemeMode.system
double arabicFontSize; // 24.0
String uiLanguage; // 'id' | 'en'
Map<String, bool> adhanEnabled; // {'fajr': true, 'dhuhr': true, ...}
Map<String, int> iqamahOffset; // {'fajr': 15, 'dhuhr': 10, ...} in minutes
DateTime? checklistReminderTime;
double? lastLat;
double? lastLng;
String? lastCityName;
}
// Checklist box
@HiveType(typeId: 1)
class ChecklistItem {
String id; // UUID
String title; // 'Sholat Fajr'
String category; // 'sholat_fardhu'
String? subtitle; // '1 Juz'
int sortOrder;
bool isCustom; // false for default items
}
// Daily log box (keyed by 'yyyy-MM-dd')
@HiveType(typeId: 2)
class DailyWorshipLog {
String date; // '2026-03-06'
Map<String, bool> completedItems; // {'item_id': true}
int totalItems;
int completedCount;
double completionPercent;
}
// Dzikir counter box (keyed by 'dzikir_id:yyyy-MM-dd')
@HiveType(typeId: 3)
class DzikirCounter {
String dzikirId;
String date;
int count;
int target;
}
// Bookmarks box
@HiveType(typeId: 4)
class QuranBookmark {
int surahId;
int verseId;
String surahName;
String verseText; // Arabic snippet
DateTime savedAt;
}
// Cached prayer times box (keyed by 'lat_lng_yyyy-MM-dd')
@HiveType(typeId: 5)
class CachedPrayerTimes {
String key;
double lat;
double lng;
String date;
DateTime fajr;
DateTime sunrise;
DateTime dhuhr;
DateTime asr;
DateTime maghrib;
DateTime isha;
}
```
---
## 8. Third-Party Dependencies
| Package | Version | Purpose |
|---|---|---|
| `flutter_riverpod` | ^2.x | State management |
| `riverpod_annotation` | ^2.x | Code gen for providers |
| `go_router` | ^13.x | Declarative navigation |
| `hive_flutter` | ^1.x | Local key-value storage |
| `hive_generator` | ^2.x | Hive TypeAdapter codegen |
| `adhan` | ^1.x | Prayer time calculation (offline) |
| `geolocator` | ^11.x | GPS location |
| `geocoding` | ^3.x | Reverse geocoding (city name) |
| `flutter_qiblah` | ^2.x | Qibla direction calculation |
| `flutter_compass` | ^0.x | Device compass heading |
| `flutter_local_notifications` | ^17.x | Adhan + Iqamah notifications |
| `just_audio` | ^0.x | Quran Murattal audio playback |
| `audio_service` | ^0.x | Background audio + media controls |
| `google_fonts` | ^6.x | Plus Jakarta Sans |
| `material_symbols_icons` | ^4.x | Material Symbols icon set |
| `build_runner` | ^2.x | Code generation runner |
**Quran Data Sources:**
- Arabic text + Indonesian translation: bundled as `assets/quran/quran_id.json` (local, offline)
- Audio (Murattal): streamed from `https://server6.mp3quran.net/` (Mishari Al-Afasy) or bundled short Surahs
---
## 9. Non-Functional Requirements
### 9.1 Performance
- App cold start: < 2 seconds on mid-range devices (Snapdragon 700 series / Apple A14)
- Bottom nav tab switch: < 150ms
- Prayer time calculation: < 50ms (synchronous, offline)
- Quran verse list render: use `ListView.builder` (lazy loading), never `ListView` with all children
### 9.2 Offline-First
- Core features work with no internet: Dashboard, Checklist, Dzikir, Reports, Qibla, Quran Reading, Settings
- Quran Murattal: short Surahs bundled; longer Surahs require connectivity (graceful fallback shown)
- Prayer times: cached per location+date in Hive; recalculated on location change
### 9.3 Accessibility
- Minimum touch target: 48×48dp for all interactive elements
- All icons have semantic labels (`Semantics(label: ...)`)
- Arabic text has `textDirection: TextDirection.rtl` explicitly set
- Sufficient contrast ratios for both light and dark themes (WCAG AA)
### 9.4 Dark Mode
- All screens must look correct in both light and dark mode
- No hardcoded `Colors.white` or `Colors.black` — use `AppColors` tokens only
- Theme transitions are animated (Material 3 `AnimatedTheme`)
### 9.5 Localization
- v1.0: Indonesian (id) as primary language, English (en) as secondary
- Use `flutter_localizations` + `intl` package for date/number formatting
- All UI strings in `AppLocalizations` (ARB files); no hardcoded Indonesian strings in widgets
---
## 10. Permissions
| Permission | Reason | Timing |
|---|---|---|
| `ACCESS_FINE_LOCATION` (Android) / `NSLocationWhenInUseUsageDescription` (iOS) | Prayer time calculation, Qibla direction | On first Dashboard load |
| `POST_NOTIFICATIONS` (Android 13+) | Adhan and Iqamah notifications | On Settings → Notifications first toggle |
| `SCHEDULE_EXACT_ALARM` (Android 12+) | Exact Adhan notification timing | When notification enabled |
| Background audio (iOS: `audio` background mode) | Murattal background playback | On Murattal first play |
**Permission UX:**
- Never request permission without explaining why first (show rationale bottom sheet)
- Graceful degradation: if location denied → manual city picker; if notifications denied → remind once, then respect
---
## 11. Out of Scope (v1.0)
The following features are **explicitly excluded** from v1.0 to keep scope focused:
- User accounts / cloud sync (no backend, local-only)
- Social features (sharing worship progress to social media, leaderboards)
- Full Quran audio library (only short Surahs bundled/streamed)
- Quran memorization (Hafalan) mode
- Hijri calendar widget beyond Imsakiyah
- Community / forum features
- Multi-user / family tracking
- Wear OS / watchOS companion
- Widgets (home screen app widget)
- Apple Watch prayer time complication
- In-app purchases or subscriptions
- Push notifications from a server (only local scheduled notifications)
---
*PRD v1.0 — Jamshalat Diary — March 2026*