Project Name: CodeTrack (or similar) Platform Targets: Android (Mobile), JVM (Windows PC) Objective: A cross-platform application to track, analyze, and visualize daily LeetCode problem-solving progress. Architecture: Clean Architecture + MVVM
- UI Framework: Jetpack Compose Multiplatform (Material 3).
- Architecture Pattern: Clean Architecture (Presentation, Domain, Data) with Unidirectional Data Flow (UDF).
- Dependency Injection: Koin (Standard for KMP, replacing Hilt).
- Local Database (Caching): Room KMP (Yes, Room now supports KMP!).
- Preferences/Settings: DataStore KMP.
- Remote Backend: Firebase via
gitlive-firebase-kotlin-sdk(Firestore for DB, Firebase Auth for login). - Asynchronous Processing: Kotlin Coroutines & StateFlow.
In a standard Compose Multiplatform project, your code will be divided into specific source sets. Here is how we will structure the separation of concerns:
commonMain(90% of the code):- UI Layer: Compose UI screens, ViewModels (using
lifecycle-viewmodel-composeKMP), UI states. - Domain Layer: Use cases (e.g.,
LogProblemUseCase,GetWeeklyStatsUseCase), Models. - Data Layer: Room Database setup, Repository interfaces, GitLive Firebase integration.
- UI Layer: Compose UI screens, ViewModels (using
androidMain(5% of the code):- Android-specific initialization (e.g., Koin Android context).
- Platform-specific Firebase initialization.
MainActivity.kt.
desktopMain(5% of the code):- JVM window configuration (window size, title, desktop icon).
- Desktop-specific Firebase REST fallbacks (if needed for Auth).
We will use a NoSQL document structure in Firestore optimized for quick reads.
- Collection:
usersDocument: {userId}-> Fields:email,joinDate,totalSolved
- Collection:
submissions(Sub-collection underusers/{userId})Document: {submissionId}-> Fields:problemId(Int)problemName(String)difficulty(String: Easy, Medium, Hard)topicTags(List: Arrays, DP, Graphs)timeTakenMinutes(Int)timestamp(Long/Date)notes(String)
To make the app snappy on both your PC and phone, we will implement an Offline-First strategy:
- Read: The UI observes a
Flowfrom the local Room Database. - Sync: When the app opens (or a swipe-to-refresh is triggered), it fetches new records from Firestore and inserts them into Room.
- Write: When you log a new LeetCode problem, the Repository writes it to Room first, and then queues a sync to Firestore.
- Setup the KMP project using the JetBrains wizard.
- Configure the GitLive Firebase SDK and Koin for dependency injection.
- Implement Firebase Auth. Senior Tip: For Desktop JVM, standard Google Sign-In is complex. Use Email/Password auth to save time, or use the REST API approach for desktop OAuth.
- Set up Room KMP (
@Database,@Dao,@Entity). - Create the
SubmissionRepositoryto handle the logic between Room and Firestore. - Write unit tests for the repository logic using mock data.
- Create the
ViewModelusing StateFlow. - Example State:
data class HomeUiState( val isLoading: Boolean = false, val todaySolvedCount: Int = 0, val recentSubmissions: List<Submission> = emptyList(), val error: String? = null )
- Dashboard Screen: A summary of today's progress, a heat map (similar to GitHub contributions), and pie charts for Easy/Medium/Hard breakdowns.
- Add Submission Screen: A form to log the problem name, URL, difficulty, time spent, and lessons learned.
- Responsive Design: Use
BoxWithConstraintsto render a navigation rail on the Windows desktop app, and a bottom navigation bar on the Android app.