Repository navigation
Rewrite to Kotlin + MVVM + Room with Material 3 redesign - #1
Merged
Merged
Conversation
Full architectural overhaul of the app. Replaces the Java/SQLite prototype with a clean MVVM stack and a Material 3 user interface, plus adds onboarding, dashboard, PDF export, JSON backup/restore, theme toggle, and Google Books ISBN auto-fill. Architecture - Single-Activity host (MainActivity) + Navigation Component graph for Dashboard, Library, Detail, Add/Edit, Settings. Auth + Onboarding live in their own activities. - Repository pattern between ViewModels and Room. Reactive reads via Flow/StateFlow. - Hand-rolled ServiceLocator for DI; ViewModelFactory wires constructors. Data layer - Room database with UserEntity + BookEntity (cover URI, status, rating, progress, notes, dateAdded, lastModified). DAOs use suspend + Flow. - PreferencesManager: typed wrapper around SharedPreferences for session, theme, last-used sort/filter. - Salted SHA-256 password hashing replaces plaintext storage. UI - Material 3 theme tokens (light + dark) with brand palette and typed text styles. - Onboarding (3-slide ViewPager2 with dot indicators), Login/Register with inline validation, Dashboard with status breakdown + recent rail, Library with search / sort / filter (persisted) and swipe-to-delete + Snackbar UNDO, Detail with rating + reading progress + Share, Add/Edit form with cover picker and ISBN auto-fill, Settings with theme toggle + PDF export + JSON backup/restore + sign-out. - 25+ Material vector icons and gradient drawables. Features - Cover image picker via the modern Photo Picker (no permission on Android 13+); bytes copied to internal storage so they survive app restarts. - Reading status (Want / Reading / Finished) with progress tracking (current / total pages) for "Currently Reading" books. - 5-star rating with sortable ranking on the dashboard average. - Sort by title / date / rating; filter by reading status; preferences persisted. - PDF export via platform PdfDocument API (no third-party PDF lib). - JSON backup/restore via org.json, written through MediaStore on Q+, FileProvider on older devices. - Google Books ISBN auto-fill: pre-populates title, author, year, category, and page count from a 10/13-digit ISBN. Network done with HttpURLConnection only — no new dependencies. User-typed input is preserved (never overwritten). - Theme toggle: System / Light / Dark. AppCompatDelegate-driven. - Splash screen with brand gradient (no white flash on cold launch). Tooling - Kotlin 2.0.21, AGP 8.11, Gradle 8.13, JDK 17. compileSdk=35, minSdk=21, targetSdk=34. - ViewBinding, KSP, Navigation Safe Args, Coil 2.7. - Coroutines + Flow. lifecycle-runtime-ktx for repeatOnLifecycle. Testing - 8 unit-test classes covering PasswordHasher, enum storage values, both repos, all ViewModels (auth/list/edit), and the Google Books parser. JUnit + MockK + Turbine + kotlinx-coroutines-test. Project hygiene - LICENSE (MIT) added. - GitHub Actions CI: build + unit tests + debug APK artifact on every push/PR. - screenshots/ directory with capture instructions for the README placeholders. - .gitignore extended to exclude Claude session metadata and keystore files. - README rewritten with architecture diagram, full feature list, tech stack table, module map, test inventory, screenshots placeholders, and roadmap. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
`android.util.Patterns.EMAIL_ADDRESS` is a static field that's null in JVM unit tests — the Android stub jar doesn't initialize it, and AGP's `isReturnDefaultValues = true` only handles method calls, not field access. That made every UserRepository test that exercised the register() path NPE before even reaching the assertion. Switching to a hand-rolled Kotlin Regex makes the validation work identically on the device and in JVM tests, with no extra dependency. Pattern is practical RFC 5322-ish — sufficient to bounce obvious typos at the form layer and matches the spirit of what `Patterns.EMAIL_ADDRESS` does anyway. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Safe Args' XML parser requires the L suffix for long defaultValues: error: Failed to parse defaultValue '0' as long The earlier audit "fix" that stripped the suffix was wrong. The original defaultValue="0L" was correct. Reverting to that form. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…, silence Room warning
Three fixes surfaced by running ./gradlew testDebugUnitTest assembleDebug locally
against AGP 8.11.0 / Gradle 8.13 / JDK 21 (Android Studio jbr):
1. mipmap-anydpi/ic_launcher{,_round}.xml moved to mipmap-anydpi-v26/
AAPT rejects <adaptive-icon> on minSdk 21 unless the resource is gated by the
v26 qualifier — adaptive icons are an API 26+ feature. The v26 qualifier tells
the resource system to only use these XMLs on Android 8+, while older devices
keep falling back to the raster mipmap-*dpi/*.webp variants.
2. testImplementation org.json:json:20240303
GoogleBooksParser uses org.json.JSONObject. On-device that's the platform impl,
but the JVM unit-test android.jar stub leaves it unimplemented, so calls
silently returned defaults and the parser always emitted null. Adding the
reference impl as a test dep makes the parser execute the same code path in
tests as on a real device.
3. exportSchema = false on the Room database
The "Schema export directory was not provided" warning is noisy and we don't
ship a v2 schema yet. Comment in the source explains how to flip it back on.
Verification: 51/51 unit tests pass; assembleDebug produces a valid app-debug.apk.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
SultanZhalifa
added a commit
that referenced
this pull request
Oct 12, 2026
Rewrite to Kotlin + MVVM + Room with Material 3 redesign
SultanZhalifa
added a commit
that referenced
this pull request
Oct 12, 2026
Rewrite to Kotlin + MVVM + Room with Material 3 redesign
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Full architectural overhaul of the app. Replaces the Java/SQLite prototype with a clean MVVM stack and a Material 3 user interface, plus adds onboarding, dashboard, PDF export, JSON backup/restore, theme toggle, and Google Books ISBN auto-fill.
Architecture
Data layer
UI
Features
Tooling
Testing
Project hygiene