= **[[https://phabricator.wikimedia.org/T415272 | Modularization + Jetpack Compose in Commons Android App]]** =
**Contributor Name:** [[https://www.linkedin.com/in/owmdubey/ | Owm Dubey]]
**Contributor Email:** owmdubey163@gmail.com
**Contributor Github:** [[https://github.com/Roniscend | Roniscend]]
**Location** : India (UTC +5:30)
**Expected Project Size:** 350 hours
**Mentors:**
* [[https://phabricator.wikimedia.org/p/Neeldoshii/ | Neel Doshi]]
* [[https://phabricator.wikimedia.org/p/Kaartic/ | Kaartic]]
---
== 1. About Me ==
I am a sophomore pursuing a B.E. in Computer Science Engineering in Bangalore, India. I have a strong interest in **Android Development** and **Open Source Contribution**. My focus is on building scalable and well-architected mobile applications using **Kotlin/Java** and the latest Android Development Technologies.
I have a strong reason to be a part of the **Modularization and Jetpack Compose Initiative** because the application's legacy **MVP architecture** is becoming increasingly difficult to scale and maintain. The application needs a modernization effort in its architecture from the legacy MVP architecture to the latest and greatest **MVVM architecture** and, more specifically, converting the application's **XML-based view hierarchy** to the latest **Jetpack Compose UI**.
The Modularization and Jetpack Compose Initiative is a great move in the direction of making the Wikimedia Commons application more scalable and efficient. I would love the opportunity to contribute to this project and work on making the application's architecture more scalable and efficient by identifying the architectural challenges in the application's legacy MVP architecture and migrating the application's XML-based UI to the latest Jetpack Compose UI.
== 2. Past Experiences ==
Over the past few months I have been actively contributing the **Commons Application Project**. At the time of writing this proposal, I have a total of **13 PR's** with **3 merged** and 10 currently open and a total of **12 Issues Created**.
Beyond open-source, I've also worked as an **Android developer Intern** at LettrBlack, where I have architected an Android application using **MVVM** and **Clean Architecture**. I implemented the entire data layer including **Repository patterns** and **Room persistence** while ensuring a reactive UI layer with **StateFlow**.
=== 2.1 Notable Projects ===
* **[[https://github.com/Roniscend/SafarLink | SafarLink]] :** A unified platform that compares ride and delivery services in real time and simplifies booking through intelligent deep linking and automated cross-app navigation
* **[[https://github.com/Roniscend/Atkit | Atkit]] :** Atkit is Kotlin based Android camera app built with **MVVM** and **Jetpack Compose** featuring **CameraX** integration,smart search , adaptive theming,and efficient Session- based photo management for oral health imaging
* **[[https://github.com/Roniscend/Survey | Survey]] :** A modern Android survey application developed using **Kotlin** and **Jetpack Compose**,implementing **MVVM** architecture for efficient collection management and persistence of user responses through a scalable and intuitive UI.
* **[[https://github.com/Roniscend/Moment.ly | Moment.ly]] :** A feature rich Android social media app using **Firebase Authentication** and **Firestore** with a dynamic scrolling feed and declarative UI in **Jetpack Compose**
== 3. Prior contributions ==
| Repository | Pull Request | Issue Solved | Description | Status |
| ----- | ----- | ----- | ----- | ----- |
| commons-app/apps-android-commons | [[https://github.com/commons-app/apps-android-commons/pull/6663 | #6663]] | [[https://github.com/commons-app/apps-android-commons/issues/6662 | #6662]] | Fix password toggle reset on rotation. | **Merged** |
| commons-app/apps-android-commons | [[https://github.com/commons-app/apps-android-commons/pull/6681 | #6681]] | [[https://github.com/commons-app/apps-android-commons/issues/6678 | #6678]] | Persist 2FA visibility across configuration changes | **Merged** |
| commons-app/apps-android-commons | [[https://github.com/commons-app/apps-android-commons/pull/6665 | #6665]] | [[https://github.com/commons-app/apps-android-commons/issues/6650 | #6650]] | Fix SVG decoding in upload flow | Open |
| commons-app/apps-android-commons | [[https://github.com/commons-app/apps-android-commons/pull/6679 | #6679]] | [[https://github.com/commons-app/apps-android-commons/issues/6669 | #6669]] | Resolve login password toggle desync issue | Open |
| commons-app/apps-android-commons | [[https://github.com/commons-app/apps-android-commons/pull/6666 | #6666]] | [[https://github.com/commons-app/apps-android-commons/issues/6674 | #6674]] | Enhance character rendering in Nearby list | Open |
| commons-app/apps-android-commons | [[https://github.com/commons-app/apps-android-commons/pull/6685 | #6685]] | [[https://github.com/commons-app/apps-android-commons/issues/6676 | #6676]] | Handle configuration changes in Place selector | Open |
| commons-app/apps-android-commons | [[https://github.com/commons-app/apps-android-commons/pull/6682 | #6682]] | [[https://github.com/commons-app/apps-android-commons/issues/6677 | #6677]] | Improve login network error user feedback | Open |
| commons-app/apps-android-commons | [[https://github.com/commons-app/apps-android-commons/pull/6737 | #6737]] | [[https://github.com/commons-app/apps-android-commons/issues/6699 | #6699]] | Fixed FAB layout and distortion issues | **Merged** |
| commons-app/apps-android-commons | [[https://github.com/commons-app/apps-android-commons/pull/6753 | #6753]] | [[https://github.com/commons-app/apps-android-commons/issues/6700 | #6700]] | Validated fragment behavior on configuration changes | Open |
| commons-app/apps-android-commons | [[https://github.com/commons-app/apps-android-commons/pull/6740 | #6740]] | [[https://github.com/commons-app/apps-android-commons/issues/6701 | #6701]] | Verified keyboard visibility issue fixed in landscape | Open |
| organicmaps/organicmaps | [[https://github.com/organicmaps/organicmaps/pull/11983 | #11983]] | [[https://github.com/organicmaps/organicmaps/issues/11938 | #11938]] | Fix SplashActivity navigation race condition crash | **Merged** |
| organicmaps/organicmaps | [[https://github.com/organicmaps/organicmaps/pull/12008 | #12008]] | [[https://github.com/organicmaps/organicmaps/issues/10835 | #10835]] | Preserve native debug symbols for readable crashes | **Merged** |
| organicmaps/organicmaps | [[https://github.com/organicmaps/organicmaps/pull/12032 | #12032]] | | Pass specific login error codes to Android layer | **Merged** |
| organicmaps/organicmaps | [[https://github.com/organicmaps/organicmaps/pull/12079 | #12079]] | [[https://github.com/organicmaps/organicmaps/issues/11945 | #11945]] | Optimize layout updates during window inset changes | **Merged** |
| organicmaps/organicmaps | [[https://github.com/organicmaps/organicmaps/pull/12098 | #12098]] | [[https://github.com/organicmaps/organicmaps/issues/12091 | #12091]] | Ensure legacy Android 5 icon compatibility | **Merged** |
| organicmaps/organicmaps | [[https://github.com/organicmaps/organicmaps/pull/12000 | #12000]] | [[https://github.com/organicmaps/organicmaps/issues/11424 | #11424]] | Migrate navbar to AndroidX Edge-to-Edge API | **Merged** |
| organicmaps/organicmaps | [[https://github.com/organicmaps/organicmaps/pull/12006 | #12006]] | [[https://github.com/organicmaps/organicmaps/issues/11668 | #11668]] | Persist login error dialog across configuration changes | **Approved** |
| organicmaps/organicmaps | [[https://github.com/organicmaps/organicmaps/pull/12140 | #12140]] | [[https://github.com/organicmaps/organicmaps/issues/12132 | #12132]] | Fix OpenStreetMap search URL parsing | Open |
| organicmaps/organicmaps | [[https://github.com/organicmaps/organicmaps/pull/12077 | #12077]] | [[https://github.com/organicmaps/organicmaps/issues/12044 | #12044]] | Refactor opening hours layout for readability | Open |
== 4. Commitments during GSoC ==
I have no prior commitments during the GSoC period and I'll be able to work **35-45 hours per week** solely on completing this project.
---
= Project Idea =
== 5. Abstract ==
This project proposes a comprehensive **architectural revamp** of the Android application to resolve technical debt and mitigate the risks associated with its outdated, tightly coupled codebase. Currently, the **legacy architecture** bottlenecks feature development, complicates testing and creates a high barrier to entry for new contributors.
The core objective of this proposal is twofold: achieving **complete modularization** of the app and migrating **at least 40% of the legacy XML UI to Jetpack Compose**.
By dismantling the **monolithic structure** into **highly cohesive**, feature based modules following strict **Clean Architecture principles**, the project will drastically improve separation of concerns, gradle build times, and isolated testability. Concurrently, migrating key user flows to **Jetpack Compose** integrated with the industry **standard Navigation 3 API** will establish a **Unidirectional Data Flow(UDF)** using a **modern MVVM pattern** and reactive state observation.
The modernization effort will directly benefit end-users by delivering a highly stable, crash resilient app with a refreshed interface. Furthermore, it ensures long term scalability by providing volunteer contributors with a clean, standard compliant codebase that significantly accelerates onboarding and future development.
== 6. Implementation Details ==
=== 6.1 Dependency Injection ===
| Current State | Target State |
| ----- | ----- |
| legacy **Dagger 2** with AndroidInjectionModule and dagger-android | **Hilt** modern DI |
**Problem Areas:**
* Uses dagger android deprecated with **AndroidInjector**, **DispatchingAndroidInjector**, **HasSupportFragmentInjector**
* Complex Dagger setup with **ApplicationlessInjection**, **CommonsDaggerAppCompatActivity**, **CommonDaggerSupportFragment**
* Manual component builders **ActivityBuilderModule**, **FragmentBuilderModule** requiring every Activity/Fragment to be registered.
**Files to update(eg.):** CommonsApplicationComponent.kt
```kotlin
@Component(
modules = [
CommonsApplicationModule::class,
NetworkingModule::class,
AndroidInjectionModule::class,
AndroidSupportInjectionModule::class,
ActivityBuilderModule::class,
FragmentBuilderModule::class,
// ...
]
)
```
**Migration Path:** The migration from legacy **Dagger 2** to **Hilt** focuses on replacing manual component management with Hilt's standard annotations. By annotating the Application class with **@HiltAndroidApp** and UI components with **@AndroidEntryPoint**, you eliminate the need for **ActivityBuilderModule**, **FragmentBuilderModule**, and custom base classes like **CommonsDaggerAppCompatActivity**. This transition simplifies the dependency graph, removes significant boilerplate code, and enables the use of **@HiltViewModel** for modern architecture.
**Dagger The Tangled Web**
**{F73438057, layout=center, size=full}**
---
**Hilt The Magic Annotation**
**{F73438829, layout=center, size=full}**
| Feature | Legacy State | Target State |
| ----- | ----- | ----- |
| App Setup | Manual @Component & AndroidInjectionModule | **@HiltAndroidApp** |
| UI Injection | @ContributesAndroidInjector in modules | **@AndroidEntryPoint** |
| Base Classes | DaggerAppCompatActivity/ Fragment | Standard AppCompatActivity/Fragment |
| ViewModels | Manual Factory/Provider injection | **@HiltViewModel** |
=== 6.2 Architecture Pattern ===
| Current State | Target State |
| ----- | ----- |
| **MVP**(Model View Presenter) | **MVVM**(Model View ViewModel + Stateflow) |
The migration to **MVVM** focuses on the complete elimination of the legacy **MVP infrastructure**, specifically removing the **BasePresenter.kt** interface and all associated **Contract.kt** files such as **ContributionsContract.kt**, **ContributionsListContract.kt**, and **PagingContract.kt**.
By removing these contracts and over **30+ Presenter files**, we are transitioning from an imperative, interface-driven architecture to a modern reactive approach. This allows us to move logic into **lifecycle-aware ViewModels** that utilize **StateFlow** to emit updates. This shift effectively eliminates the high boilerplate of the contract based pattern and ensures the application handles configuration changes natively via viewModel.
When a configuration change triggers the recreation of the UI, The new Activity requests ViewModel via **ViewModelProvider**. Because Android framework preserves the **ViewModelStore** across these lifecycle events, ViewModelProvider retrieves the exact same ViewModel instance rather than instantiating a new one. **ViewModelScope** remains active and StateFlow retains its latest state. The newly initialized UI reconnects to the existing flow, ensuring a seamless transition without data loss.
| Feature | MVP | MVVM |
| ----- | ----- | ----- |
| State handling | Manual updates via View Interfaces | **Reactive streams using State Flow** |
| Lifecycle | Presenters must be manually cleared | **Viewmodels are lifecycle aware** |
| Logic | Tight coupling(Presenter & View) | **Decoupled** (Viewmodel emits View observes) |
| Boilerplate | More(Contract Interfaces for every screen) | **Less** |
**Example:**
Legacy Pattern PagingContract.kt
```kotlin
interface PagingContract {
interface View<T> {
fun showSnackbar()
fun observePagingResults (searchResults: LiveData<...>)
}
interface Presenter<T>: BasePresenter<View<T>> {
//
}
}
```
**Updated Code:**
1. ViewModel
```kotlin
@HiltViewModel
class PagingViewModel @Inject constructor(
private val repository: Paging Repository
): ViewModel() {
private val _uiState = MutableStateFlow<PagingState> (PagingState.Idle)
val uiState: StateFlow<PagingState> = _uiState.asStateFlow()
val pagingResults: Flow<PagingData<T>> = repository.getResults()
.cachedIn(viewModelScope)
fun handleAction() {
// Implementation
}
}
```
2. UI State
```kotlin
sealed class PagingState {
object Idle: PagingState()
object Loading: PagingState()
data class Error (val message: String): PagingState()
}
```
3. View
```kotlin
@AndroidEntryPoint
class PagingFragment: Fragment (R.layout.fragment_paging) {
private val viewModel: PagingViewModel by viewModels()
override fun onViewCreated (view: View, savedInstanceState: Bundle?) {
super.onViewCreated (view, savedInstanceState)
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle (Lifecycle.State.STARTED) {
viewModel.pagingResults.collectLatest { pagedData ->
adapter.submitData (pagedData)
}
}
}
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle (Lifecycle.State.STARTED) {
viewModel.uiState.collect { state ->
when (state) {
is PagingState. Error -> {
Snackbar.make(view, state.message, Snackbar.LENGTH_LONG).show()
}
PagingState. Loading -> {
// Handle loading state
}
else -> { }
}
}
}
}
}
}
```
=== 6.3 Reactive Programming ===
| Current Status | Target Status |
| ----- | ----- |
| **RxJava2(Observable, Single, Competable, CompositeDisposable)** | **Kotlin Coroutines + Flow** |
A critical priority of this modernization is overhauling the asynchronous execution model across 40+ legacy files, transitioning from **RxJava2 (Observable, Single, Completable)** to **Kotlin Coroutines and Flow**. The codebase currently relies on manual thread scheduling (**Schedulers.io()**, **AndroidSchedulers.mainThread()**) and error-prone lifecycle management via **CompositeDisposable**.
By adopting structured concurrency, we will replace complex RxJava chains and outdated **callback interfaces** (e.g., LoginCallback in LoginClient.kt) with sequential, readable suspend functions. This shift eliminates the need for manual disposal management; instead, **viewModelScope and lifecycleScope** will automatically handle coroutine cancellation when the UI is destroyed, drastically reducing boilerplate and the risk of memory leaks. Finally, background processing will be unified by migrating any remaining RxWorker implementations to **native CoroutineWorker classes**.
| Migration Area | Current | Target | Affected files |
| ----- | ----- | ----- | ----- |
| Lifecycle Management | Composite Disposable | **ViewModelScope** | 40+ Presenter files(eg. ContributionsListPresenter.kt) |
| Thread Switching | Schedulers.io(), AndroidSchedulers.mainThread() | **Dispatchers.IO, Dispatchers.Main ,withContext()** | Presenters, ViewModels, Repository layers |
| Network return Types | Observable<T>,Single<T>, Completable | **Suspend functions or Flow<T>(streams)** | All Retrofit API interface |
| Data Operators | subscribeOn(), observeOn(), flatMap() | **Standard Kotlin Flow operators(map, flatMapLatest)** | Repository and Data layers |
**Example: ContributionsListPresenter.kt**
RxJava2
```kotlin
@Inject
@Named (CommonsApplicationModule.IO_THREAD)
private val ioThreadScheduler: Scheduler
private val composite Disposable = Composite Disposable()
fun loadContributions() {
composite Disposable.add(
repository.getContributions()
.subscribeOn(ioThreadScheduler)
.observeOn (Android Schedulers.mainThread())
.subscribe({ result ->
// Handle result
}, { error ->
// Handle error
})
)
}
```
Coroutines
```kotlin
@Inject
@IoDispatcher
private val ioDispatcher: CoroutineDispatcher
fun loadContributions() {
viewModelScope.launch(ioDispatcher) {
try {
val result = repository.getContributions()
} catch (e: Exception) {
// Handle error
}
}
}
```
=== 6.4 Navigation ===
To modernize the application's routing we will migrate from **manual fragment transactions** to the industry standard **Android Navigation 3 API**. Currently the MainActivity relies heavily on boilerplate code, using **FragmentTransaction.replace()** and **custom enums(NavTab, NavTabLoggedOut)** to manage bottom tab states. By adopting this modern approach, we will define all application destinations and routing logic within a centralized Navigation Graph.
A NavController will then be utilized within a **NavHostFragment** to trigger transitions and manage the back stack automatically. This eliminates the need for manual intent - based Activity routing, ensures type safe argument passing, and significantly reduces the complexity of handling fragment lifecycles.
| Migration | Current | Target |
| ----- | ----- | ----- |
| Routing Mechanism | Manual (FragmentTransactions.replace()) | Centralized Navigation Graph & NavController |
| Tab Management | Custom NavTab & NavTabLoggedOut enums | BottomNavigationView.setupWithNavController() |
| Data Passing | Manual Bundle creation and Intent extras| Type safe Kotlin DSL routing |
=== 6.5 UI Layer ===
The UI layer is currently in a transitional state , relying on over **100+ XML layout files** and **ViewBinding** , with only partial Jetpack Compose adoption in specific areas like **SingleWebViewActivity** and **MediaDetailFragment**. The primary objective for this phase is to achieve a minimum of **40% Jetpack Compose coverage** across the application's UI.
We will systematically replace high priority legacy XML layouts and ViewBinding implementations with modern **@Composable functions**. Since the application will utilize the standard **Android Navigation 3 API** , the migrated Compose screens will be integrated as Fragment destinations using **ComposeView**. This approach guarantees smooth interoperability between the newly built Compose UI.
To guarantee smooth performance for the UI after migrating to Compose, **Baseline Profiles** will be used to pre-compile the new UI components and prevent frame drops on the first launch.
| Migration Area | Current State | Target State |
| ----- | ----- | ----- |
| UI Framework | 100+ XML layouts + viewbinding | Minimum 40% Jetpack Compose coverage |
| Custom Views | Legacy views like NavtabLayout | Compose Material 3 Adaptive library |
| Screen Hosting | Standard XML inflated Fragments | `@Composable` functions hosted via `ComposeView` |
**Priority 1: Screens That Already Use Compose**
The codebase already has partial Compose adoption. These screens should be completed first since the infrastructure is already in place:
| Screen | Current State | Rationale |
| ----- | ----- | ----- |
| `WelcomeScreen.kt` | Already fully Compose (`@Composable` pages: `WelcomeDoUploadPage`, `WelcomeDontUploadPage`, etc.) | Already done. Only needs cleanup and theme token alignment with `:core:ui`. |
| `BookmarkCategoriesFragment.kt` | Already uses `ComposeView` | Already hybrid. Extend to cover the remaining bookmark tabs. |
| `MediaDetailFragment.kt` | Partially Compose (`fileUsagesComposeView`) | Already hosts a `ComposeView`. Incrementally migrate remaining XML sections of this fragment. |
| `SingleWebViewActivity.kt` | Already `@Composable` | Almost done |
**Priority 2: High-Value, Low-Complexity Migrations**
These screens are **state-heavy but structurally simple**, making them ideal Compose candidates:
| Screen | Files | Why Migrate? |
| ----- | ----- | ----- |
| **Auth Flow** (`LoginActivity.kt`, `SignupActivity.kt`) | 6 files | Highly state-dependent (Loading -> Error -> 2FA -> Success). Compose's declarative `when(state)` pattern is a massive upgrade over the current imperative XML toggle logic. Low user traffic = low regression risk. |
| **Profile / Achievements** (`ProfileActivity.kt`) | 1 file + 2 subdirs (`achievements/`, `leaderboard/`) | Simple data-display screens. `LazyColumn` for leaderboard lists is a direct, clean replacement for `RecyclerView`. |
| **Notifications** (`NotificationActivity.kt`) | 8 files | A straightforward list screen. Perfect candidate for `LazyColumn` + `StateFlow`. |
| **Settings** (`SettingsActivity.kt`, `SettingsFragment.kt`) | 3 files | `SettingsFragment` is large but is mostly a `PreferenceFragmentCompat`. Can be incrementally wrapped in `ComposeView` for custom preference items. |
| **About** (`AboutActivity.kt`) | 1 file | Static content screen. Trivial to port. |
**Priority 3: High-Impact, Medium-Complexity Migrations**
These are the **core user-facing screens** where Compose delivers the biggest performance and UX gains:
| Screen | Files | Why Migrate? |
| ----- | ----- | ----- |
| **Contributions List** (`ContributionsListFragment.kt`, `ContributionsFragment.kt`) | 22 files total | The most visible screen in the app. Currently uses legacy `RecyclerView` + Fresco `SimpleDraweeView` for image loading. Migrating to Compose `LazyColumn` + Paging 3 `collectAsLazyPagingItems()` + Coil `AsyncImage` will dramatically improve scroll performance and drop legacy layout inflation entirely. |
| **Explore / Search** (`ExploreFragment.kt`, `SearchActivity.kt`) | 6 files + 7 subdirs | Paging-heavy search results. Same `LazyColumn` + Paging 3 benefits as Contributions. |
**Which stable screens should be kept as XML (Hybrid Approach)?**
These screens are **massive**, **deeply intertwined**, or **Java-heavy**. Rewriting them in Compose during GSoC introduces **unacceptable regression risk**. They will be modularized to **MVVM** but will strictly retain their **XML ViewBinding**:
| Screen | Files | Why Keep as XML? |
| ----- | ----- | ----- |
| **Upload Wizard** (`UploadActivity.kt`) | 43 files + 6 subdirs | This is the **single most critical feature** in the app it's how users contribute media to Wikimedia Commons. With deeply coupled MVP presenters (`UploadPresenter.kt`, `UploadContract.kt`), `FragmentStatePagerAdapter`, multi-step wizard logic, and complex **Camera/Location/EXIF integrations**, rewriting this to Compose is extremely high risk. It will be extracted to **`:feature:upload`** and migrated to **MVVM**, but the XML stays. |
| **Nearby Map** (`NearbyController.java`, `NearbyParentFragment`) | 19 files + 4 subdirs | Still primarily written in **Java** (not even Kotlin). Tightly coupled to the native **Osmdroid C++** map rendering engine. Compose has no mature Osmdroid wrapper. Rewriting this means rewriting the entire map interaction layer. Extract to **`:feature:nearby`**, convert Java -> Kotlin, migrate to **MVVM**, but keep XML. |
| **Review** (`ReviewActivity.kt`, `ReviewImageFragment.kt`) | 9 files | A mature, stable peer-review flow with custom **`ViewPager`** swiping logic. Low user complaints, no architectural benefit from Compose migration. Keep as XML. |
| **Custom Selector** (`CustomSelectorActivity.kt`) | - | Already uses **`@Composable`** partially Hybrid state. Keep the existing XML shell and expand Compose incrementally. |
| **Location Picker** (`LocationPickerActivity.kt`) | - | Tightly bound to **Mapbox/Osmdroid native views**. Cannot be ported to Compose without a compatible map composable. Keep as XML. |
=== 6.6 State Management ===
| Current State | Target State |
| ----- | ----- |
| LiveData+RxJava+Callbacks | StateFlow + Shared Flow Kotlin Flow |
The application's current state management is fragmented , relying on a mixture of **LiveData**, **RxJava observables** and **manual callback interfaces** to push updates to the UI via the standard observer pattern. To unify the architecture and fully support the planned Jetpack Compose migration, we will transition entirely to **Kotlin's StateFlow and SharedFlow**. This modernization replaces lifecycle bound LiveData with reactive Flowstreams which are inherently more flexible and integrate seamlessly with Compose via **collectAsState()**.
Furthermore , tightly coupled callback interfaces will be eliminated in favor of SharedFlow to handle one time UI events such as **Snackbars,toast messages , or navigation triggers** safely and efficiently without holding duplicate state.
| Migration | Current | Target |
| ----- | ----- | ----- |
| UI State Holding | LiveData & Mutable Live Data | StateFlow & MutableState Flow |
| One Time Events | Manual Callback interface | Shared Flow |
| Compose integration | observeAsState() or manual wrappers | Native collectAsState() |
=== 6.7 Background Work & Threading ===
The application's background work and threading are currently managed through a mix of legacy systems, including **RxJava Schedulers**, a **custom ThreadPoolService.kt** for thread pool management, and remnants of deprecated **AsyncTask implementations**. To standardize asynchronous operations and ensure resource safety, we will migrate entirely to **Kotlin Coroutines**.
By adopting **Coroutines**, we will leverage **structured concurrency** to tie background work directly to the lifecycle of the UI components via **viewModelScope and lifecycleScope**. This eliminates the need for manual thread management and custom services, guaranteeing that ongoing tasks are automatically canceled when the associated screen is destroyed thereby preventing memory leaks and application crashes.
| Migration | Current State | Target State |
| ----- | ----- | ----- |
| Concurrency Framework | RxJava + Custom Thread Pools + AsyncTask | Kotlin Coroutines |
| Thread Switching | Schedulers.io(),AndroidSchedulers.mainThread() | Dispatchers.IO, Dispatchers.Main |
| Lifecycle Safety | Manual cancellation | Structured Concurrency (viewmodelScope) |
| Custom Services | ThreadPoolService.kt | Native Coroutine Dispatchers |
=== 6.8 Image Loading ===
The application currently relies on Facebook's **Fresco** library for image loading, which requires heavy, explicit initialization in CommonsApplication.kt and the use of custom SimpleaDraweeView components within XML layouts. To align with our Kotlin first architecture and the ongoing Jetpack Compose migration, we will replace **Fresco** with **Coil (Coroutine Image Loader)**.
The migration process involves completely removing Com.facebook.drawee.backends.pipeline. **Fresco** and its Image PipelineConfig from the application class, taking advantage of **Coil's** lightweight, automatic initialization. In the UI layer, legacy SimpleDraweeView XML tags will be replaced with standard ImageView components utilizing **Coil's** load() extension function, while newly built Compose screens will natively adopt **Coil's** AsyncImage composable. Finally all **Fresco** artifacts will be stripped from the build.gradle dependencies, which will significantly reduce the final APK size as **Coil** is a very lightweight library.
=== 6.9 Pagination ===
The application currently utilizes the legacy **Paging 2 library**, relying on **DataSource**, **PagedList**, and **LivePagedListBuilder** to handle data pagination in classes such as ContributionsListPresenter.kt. To modernize the data layer and ensure seamless compatibility with Jetpack Compose, we will migrate to the **Paging 3 library**.
This transition involves replacing the legacy **DataSource** components with **PagingSource** and swapping the **LivePagedListBuilder** for the modern **Pager API**, which emits paginated data as a continuous **Kotlin Flow<PagingData>**. This upgrade not only provides robust error handling and loading state management natively but also enables direct integration with Compose lists such as **LazyColumn** and **LazyVerticalGrid** using the paging compose artifact.
To modernize the data layer and fully support Jetpack Compose, we will migrate from Paging 2 to **Paging 3** targeting legacy files like Contributions List Presenter.kt. The outdated **DataSource** and **LivePagedListBuilder** components will be replaced with the modern **PagingSource** and **Pager APIs**. Instead of exposing a LiveData stream of PagedList objects, the new architecture will emit a continuous **Kotlin Flow<PagingData>**. This Coroutine native approach integrates seamlessly with the updated architecture and allows Compose UI components such as **LazyColumn** and **LazyVerticalGrid** to efficiently consume and display paginated data using the paging compose library.
=== 6.10 Network Layer ===
To completely modernize the network layer targeting legacy files like **LoginInterface.kt**, we will transition from **Retrofit with RxJava callbacks** to **Coroutine based suspend functions**, eliminating **callback hell** and ensuring **type-safe and efficient data parsing**.
To guarantee robust network execution, inconsistent try-catch blocks will be standardized globally using a **custom Retrofit CallAdapter**, and manual retry logic will be centralized into an **OkHttp RetryInterceptor**, alongside new certificate pinning for enhanced security.
Finally, we will establish a **true offline first architecture** by abstracting raw Retrofit calls behind a Repository pattern emitting **Kotlin Flow**, utilize a **Flow-based NetworkBoundResource** rather than relying solely on the basic OkHttp cache.
**Legacy API Pattern:**
LoginInterface.kt
```kotlin
interface LoginInterface {
@GET("?format=json&formatversion=2&errorformat=plaintext")
@Headers("Cache-Control: no-cache")
fun getLogin Token(): Call<MwQueryResponse?>
}
```
**Legacy RxJava Network Pattern:**
SessionManager.kt
```kotlin
fun logout(): Completable = Completable.fromObservable(
Observable.empty<Any>()
.doOnComplete {
removeAccount()
currentAccount = null
}
)
```
**Modern Network Architecture:**
```kotlin
interface LoginApi {
@GET("login")
suspend fun login (@Body request: LoginRequest): Result<LoginResponse>
}
class LoginRepository @Inject constructor(
private val api: LoginApi,
private val db: UserDao
) {
// The CallAdapter makes api.login return a Result automatically
fun login(request: LoginRequest): Flow<Result<User>> = flow {
emit(Result.Loading)
val result = api.login(request)
if (result is Result. Success) {
db.saveUser(result.data.toEntity())
}
emit(result)
}
}
```
=== 6.11 Data Storage ===
To completely overhaul the storage layer, we will replace legacy **SharedPreferences (BasicKvStore.kt)** and the Gson based **JsonKvStore** with **Jetpack DataStore (Preferences and Proto)** for type safe key value management.
For structured data, we will finalize a migration to **Room**, fully deprecating both the legacy **SQLiteOpenHelper (DBOpenHelper.java)** and the custom **ContentProviders** used for bookmarks in favor of a standard **Room** and Repository pattern.
| Migration | Current | Target |
| ----- | ----- | ----- |
| Relational Database | Room | Room(Retained, updated for Coroutines/Flow) |
| Key-Value Preferences | Custom JsonKvStore | Jetpack DataStore |
| Execution Context | Synchronous / Custom Threads | Asynchronous (Coroutines & Flow) |
=== 6.12 Security Hardening ===
To fortify the application's security posture, several critical vulnerabilities within the legacy architecture will be systematically addressed. First, we will eliminate the potentially insecure practice of storing account passwords in **AccountManager**, transitioning to a token only authentication model secured by **Jetpack EncryptedSharedPreferences**.
At the network level, **OkHttp CertificatePinner** will be implemented to prevent Man in the middle (MITM) attacks. To protect the application from reverse engineering, we will remove legacy Don't obfuscate **ProGuard** rules and fully enable **R8 obfuscation**. Finally, runtime security will be enhanced by integrating the **RootBeer** library to detect compromised device environments, and **Flag Secure** will be applied to the window flags of sensitive screens.
=== 6.13 Testing ===
To ensure long term stability, the legacy testing infrastructure will undergo a comprehensive modernization. We will migrate the unit test stack from **JUnit 4** and **PowerMock** to a modern setup utilizing **JUnit 5, MockK**, and either **Turbine** or **kotlinx-coroutines-test**, as **Turbine** is third party library and older but still google recommends it for precise Coroutine Flow validation.
For UI and integration testing, the custom Dagger mock setup will be replaced by **HiltTestApplication**, transitioning to a hybrid of **Compose Testing** and **Espresso**. Finally, to prevent future UI and edge case regressions, we will introduce **Compose Screenshot Testing** tool for automated screenshot testing alongside **Kotlin Test** for property based coverage.
**Legacy Test Pattern:**
TestCommonsApplication.kt
```kotlin
class TestCommonsApplication: Application() {
private var mockApplicationComponent: CommonsApplication Component? = null
// Complex manual mock setup
}
class MockCommonsApplicationModule (appContext: Context): CommonsApplicationModule (appContext) {
// mock
}
val defaultSharedPreferences: JsonKvStore = mock() // Mockito
```
**Legacy UI Test Pattern:**
MainActivityTest.kt
```kotlin
@RunWith(AndroidJUnit4::class) // OLD API
class MainActivityTest {
@get: Rule
var activityRule: ActivityTestRule<LoginActivity> = ActivityTestRule (LoginActivity::class.java) // Deprecated
// Manual login helpers
private lateinit var defaultKvStore: JsonKvStore
}
```
**Compose UI Test**
```kotlin
@HiltAndroidTest
class MainScreenTest {
@get: Rule
val hiltRule = HiltAndroidRule(this)
@get: Rule
val composeTestRule = createAndroidComposeRule<MainActivity>()
@Test
fun bottomNavigation_switches Tabs() {
composeTestRule
.onNodeWithText("Contributions")
.performClick()
composeTestRule
.onNodeWithTag("contributions_list")
.assertIsDisplayed()
}
}
```
**Modern Test Architecture**
```kotlin
@ExtendWith(MockKExtension::class)
class LoginViewModelTest {
@MockK
private lateinit var repository: LoginRepository
private lateinit var viewModel: LoginViewModel
private val testDispatcher = UnconfinedTestDispatcher()
@BeforeEach
fun setup() {
Dispatchers.setMain (testDispatcher)
viewModel = LoginViewModel (repository)
}
@Test
fun `login emits loading then success` () = runTest {
coEvery { repository.login(any()) } returns flow {
emit(Result.Success (User("test")))
}
viewModel.login("user", "pass").test {
assertEquals (LoginUiState. Loading, awaitItem())
assertEquals (LoginUiState. Success, awaitItem())
awaitComplete()
}
}
}
```
=== 6.14 Uncoupling the Monolith ===
The current architecture of **commons-app** heavily centralizes logic into the :app module, which drastically impairs scalability and increases build times. For example, UploadActivity.kt currently operates as a massive class that directly **@Injects** sweeping, cross-domain dependencies like **UserClient (Network), JsonKvStore (Database), and LocationServiceManager (Hardware)** straight into the Activity layer. Furthermore, ActivityBuilderModule.kt binds over 24 different Activities into one massive global Dagger graph. This architecture exponentially inflates incremental Gradle build times, prevents compilation avoidance, and creates tight coupling across unrelated feature boundaries.
My Implementation Strategy: To permanently resolve this technical debt and modernize the compilation pipeline, I will architect a strict Domain driven multi module directed acyclic graph (DAG) based on the following pillars:
Strict Encapsulation (Vertical Layering): Feature modules (e.g., **:feature:upload, :feature:nearby)** will enforce Kotlin's internal visibility modifiers for their localized MVVM infrastructure. *UploadActivity** will be stripped of its direct Network and Hardware injections. It will instead rely purely on an **UploadViewModel** that communicates exclusively through abstract domain interfaces (e.g., UserRepository), entirely blinding the UI to how data is retrieved.
Module-Scoped DI & Horizontal Compilation Avoidance: By replacing the bloated multiple activities **ActivityBuilderModule** with strictly scoped **@HiltAndroidApp** component hierarchies, and extracting **:core:network** (MediaWiki APIs) and **:core:database **(Room DAOs) into isolated horizontal layer modules, we clear the compilation bottleneck.
Decoupling Transitive Dependencies : Currently, the :app monolith globally bundles massive libraries like Fresco, Glide, RxJava, and Osmdroid. This forces lightweight text-only features to compile heavy C++ map and image rendering libraries. In the new DAG architecture, dependencies will be strictly hidden. For instance, libs.osmdroid.android will exist only inside :feature:nearby using Gradle's implementation keyword (rather than api), physically preventing it from leaking into the broader application. This eliminates class-path collisions and drastically reduces the compiled APK footprint.
**Before (The Monolithic Dagger Tangle)**
**{F73770184, layout=center, size=full}**
---
**After (True Clean Architecture via Dependency Inversion)**
**{F73775520, layout=center, size=full}**
== Proposed Module Structure ==
To execute this architecture, the monolithic `:app` folder will be dismantled into the following cohesive Gradle modules:
**1. Core Modules (Horizontal Infrastructure):** These modules form the backbone of the application and do not depend on any specific UI feature.
* `:core:domain` (Pure Kotlin. Holds Entities, Result wrappers, and Repository Interfaces).
* `:core:network` (Retrofit, OkHttp, MediaWiki API endpoints).
* `:core:database` (Room DAOs, Jetpack DataStore preferences).
* `:core:ui` (Jetpack Compose Material 3 tokens, theme, and reusable common components).
* `:core:testing` (Hilt test rules, MockK extensions for shared module testing).
**2. Feature Modules (Vertical Flows):** These modules encapsulate distinct user flows. By using Gradle's `implementation` keyword, their massive 3rd-party dependencies (like Fresco or Osmdroid) remain physically isolated and cannot leak into the broader application.
* `:feature:auth` (Login, 2FA, Signup UI flows).
* `:feature:contributions` (The MVVM paged list of user contributions).
* `:feature:explore` (Search and categories).
* `:feature:nearby` (The osmdroid map rendering UI).
* `:feature:upload` (The Upload Wizard flow).
**How will multi-modules NOT increase maintenance overhead?**
**1. Gradle Convention Plugins (`build-logic`)**
The #1 cause of multi-module nightmare is duplicated `build.gradle.kts` boilerplate. I will create a `build-logic/` included build with Kotlin DSL convention plugins:
build-logic/
├── convention/
│ ├── src/main/kotlin/
│ │ ├── commons.android.application.gradle.kts
│ │ ├── commons.android.feature.gradle.kts -> For feature modules
│ │ ├── commons.android.library.gradle.kts -> For core modules
│ │ └── commons.android.compose.gradle.kts -> Compose compiler config
**Result:** Creating a new module requires exactly **one line** in its `build.gradle.kts`:
`plugins { id("commons.android.feature") }`
All `compileSdk`, `minSdk`, Hilt, Compose compiler, and test dependency configurations are inherited automatically. Zero duplication, zero version conflicts.
**2. Version Catalog (`libs.versions.toml`)**
The project already uses a Version Catalog. All library versions will be centralized here. Upgrading a library (e.g., Retrofit) means changing **one line** in `libs.versions.toml`, and it propagates to every module automatically.
**3. `:core:domain` as the Single Source of Truth**
All inter-module communication goes through pure Kotlin interfaces in `:core:domain`. A feature module **cannot** directly depend on another feature module. This means:
* Changing `:feature:upload` internals **cannot** break `:feature:contributions`.
* A small bug fix in one feature module **only recompiles that module**, not the entire app.
**4. Strict Dependency Rules in `settings.gradle.kts`**
I will enforce dependency direction using Gradle's `api` vs `implementation`:
* Feature modules use `implementation` for `:core:network`, `:core:database` -> changes in data layer do NOT trigger feature recompilation.
* Only `:core:domain` is exposed via `api` -> the public contract never leaks implementation details.
**5. CI Enforcement**
A simple Gradle task (or a lint rule) can be added to CI that **fails the build** if any `:feature:*` module directly depends on another `:feature:*` module, preventing developers from accidentally introducing circular dependencies.
== 7. Timeline ==
**GSoC Timeline**
**{F73438062, layout=center, size=full}**
=== 7.1 Week-Wise Distribution ===
**Community Bonding Period**
**Phase1: Foundation & Infrastructure**
| Timeframe | Description | Est. Hours |
|---|---|---|
| **Week 1** | **Gradle Hilt Configuration & Core DI Migration** | **45 Hrs** |
| Subtask 1.1 | Initialize `@HiltAndroidApp` in `CommonsHiltApplication` and completely strip legacy Dagger `AppComponent` initialization and `HasSupportFragmentInjector` implementations. | 10 Hrs |
| Subtask 1.2 | Refactor `ActivityBuilderModule` & `FragmentBuilderModule`. Replace manual `AndroidInjection.inject(this)` calls with `@AndroidEntryPoint` and validate legacy ViewModel injections. | 15 Hrs |
| Subtask 1.3 | Resolve DI-related test regressions. Implement `@HiltAndroidTest` via a newly created `TestCommonsApplication` and configure a `CustomTestRunner` for robust Hilt UI testing. | 20 Hrs |
| **Week 2** | **DataStore & Async Foundations** | **45 Hrs** |
| Subtask 2.1 | Configure Hilt `DataStoreModule` and `Proto` schemas to globally provide `DataStore<Preferences>`. | 15 Hrs |
| Subtask 2.2 | Migrate standard key-value preferences from legacy `BasicKvStore` to Jetpack `DataStore`. | 15 Hrs |
| Subtask 2.3 | Deprecate `JsonKvStore` and refactor classes like `SessionManager` to emit `Flow<T>`, simultaneously establishing and injecting centralized Coroutine infrastructure. | 15 Hrs |
| **Week 3** | **Core Modularization & RxJava to Coroutines** | **45 Hrs** |
| Subtask 3.1 | Set up a `build-logic` module utilizing Gradle Convention Plugins (Version Catalogs) to centralize dependency management across all future modules. | 15 Hrs |
| Subtask 3.2 | Establish foundational core modules (`:core:network`, `:core:database`, `:core:utils`, `:core:ui`) and migrate the modernized components into these strict boundaries. | 15 Hrs |
| Subtask 3.3 | Implement `CommonsCoroutineScope` for centralized, lifecycle-aware coroutine management. Migrate `ContributionsRepository` from RxJava to Kotlin `Flow` with zero UI layer disruption. | 15 Hrs |
**Phase 2: Architecture & Navigation**
| Timeframe | Description | Est. Hours |
|---|---|---|
| **Week 4** | **Hybrid UI Migration: MVP -> MVVM** | **45 Hrs** |
| Subtask 4.1 | Refactor `ContributionsFragment` to MVVM. Embed `@Composable` `ContributionsScreen` via `ComposeView(DisposeOnViewTreeLifecycleDestroyed)` and observe UI states using `collectAsStateWithLifecycle()`. | 15 Hrs |
| Subtask 4.2 | Migrate `ExploreFragment` to MVVM and implement Jetpack Compose interoperability for the UI layer. | 15 Hrs |
| Subtask 4.3 | Execute the complex `NearbyParentFragment` MVVM migration. Integrate all newly refactored hybrid Fragments into `MainActivity`. | 15 Hrs |
| **Week 5** | **Navigation 3 API, Paging 3 Migration & Core UI** | **45 Hrs** |
| Subtask 5.1 | Migrate `ContributionsListPresenter` to `ContributionsViewModel`. Define `nav_graph.xml` to centralize all UI destinations (`ContributionsFragment`, `NearbyParentFragment`, `UploadActivity`) using the industry standard Navigation 3 API. | 15 Hrs |
| Subtask 5.2 | Migrate legacy Paging 2 `DataSource` to Paging 3 `PagingSource` returning isolated `Flow<PagingData>`. Configure `NavHostFragment` and initialize the `NavController` within `MainActivity` to manage the application’s hybrid backstack. | 20 Hrs |
| Subtask 5.3 | Create the `:core:ui` module establishing foundational Material 3 Compose tokens (`CommonsTypography`, `CommonsColors`). Replace legacy `NavTab` routing by binding `BottomNavigationView` directly to the `NavController` (`setupWithNavController`). Concurrently implement explicit deep link routing for external media and notifications. | 10 Hrs |
| **Week 6** | **Network Modernization & Core Feature Extraction** | **45 Hrs** |
| Subtask 6.1 | Initialize `Kotlin Serialization` and establish a `NetworkResult` sealed interface to standardize API response states. Extract the `:feature:auth` module and verify Gradle Single Responsibility constraints (it cannot access anything but `:core:domain`). | 15 Hrs |
| Subtask 6.2 | Refactor Retrofit interfaces, replacing `RxJava Observable` returns with Coroutine `suspend` functions mapped to `Flow` in repositories. Extract the `:feature:contributions` module. | 15 Hrs |
| Subtask 6.3 | Extract the highly stable `UploadActivity` logic into the `:feature:upload` module while strictly keeping its XML layout intact, ensuring all modernized network responses route correctly through the new module boundaries. | 15 Hrs |
**Phase 3: UI Modernization & Feature Modules**
| **Week 7** | **Core UI Module, MD3 System & Compose Integration** | **45 Hrs** |
| Subtask 7.1 | Establish an independent `:core:ui` module to centralize the Jetpack Compose design system. Implement a complete Material Design 3 theme (responsive light/dark schemes, `CommonsTypography`, `CommonsShapes`), and embed `ComposeView` into the `ContributionsFragment` layout. | 10 Hrs |
| Subtask 7.2 | Build a highly reusable Compose component library utilizing the new MD3 tokens. Rewrite the main contribution list rendering (`RecyclerView` equivalent) purely in Compose utilizing `LazyColumn` and `collectAsLazyPagingItems()`. | 20 Hrs |
| Subtask 7.3 | Concurrently migrate legacy image loading to Coil. Strip Fresco XML definitions and implement lightweight Coil `AsyncImage` composables to deeply optimize the image rendering pipeline. | 15 Hrs |
| **Week 8** | **Advanced Feature Extraction & Dependency Resolution** | **45 Hrs** |
| Subtask 8.1 | Extract the Explore screen into a standalone `:feature:explore` module, leveraging Convention Plugins to enforce a strict dependency graph that relies only on `:core:domain` (for business logic) and `:core:ui` (for design system tokens), ensuring the feature remains completely decoupled from data implementation details. | 15 Hrs |
| Subtask 8.2 | Refactor the Nearby map functionality into a standalone `:feature:nearby` module, establishing a decoupled dependency graph that only uses `:core:domain` to avoid circular dependencies. | 15 Hrs |
| Subtask 8.3 | Extract the logic into a standalone `:feature:contributions` module, utilizing Convention Plugins to segregate the legacy logic from the core data layer. Concurrently establish strict inter-module navigation graphs and dependency rules within `settings.gradle.kts` to prevent circular dependencies. | 15 Hrs |
| **Week 9** | **Compose UI Migrations: Upload, Media & Nearby** | **45 Hrs** |
| Subtask 9.1 | Refactor `UploadActivity` into a Compose-based multi-step wizard. Route the sub-flows strictly utilizing the Android Navigation Component. | 15 Hrs |
| Subtask 9.2 | Migrate the complex, data-dense UI of `MediaDetailFragment` entirely to Jetpack Compose. | 15 Hrs |
| Subtask 9.3 | Refactor `NearbyParentFragment`, replacing legacy map implementations with Compose-compatible rendering. | 15 Hrs |
| **Week 10** | **Remaining Screens & Polish** | **45 Hrs** |
| Subtask 10.1 | Refactor `ProfileActivity` to Compose, fully migrating the interactive achievements and leaderboard UI components. | 25 Hrs |
| Subtask 10.2 | Migrate `SettingsActivity` and `AboutActivity` to Compose-based screens. | 10 Hrs |
| Subtask 10.3 | Refactor the final remaining screens `ReviewActivity` and `NotificationActivity`. Execute a final codebase sweep to systematically delete most of the deprecated XML layouts. | 10 Hrs |
| **Week 11** | **Modern Testing Stack & Coroutine Unit Testing** | **45 Hrs** |
| Subtask 11.1 | Setup the modern testing stack: JUnit 5, MockK, and either Turbine or `kotlinx-coroutines-test`, fully replacing legacy JUnit 4 and Mockito dependencies across the project. | 20 Hrs |
| Subtask 11.2 | Implement ViewModel unit tests utilizing `runTest`, `StandardTestDispatcher`, and `kotlin-coroutines-test` to validate sequential `StateFlow` emissions. | 25 Hrs |
| **Week 12** | **End-to-End Testing, Community Feedback & Final Documentation** | **45 Hrs** |
| Subtask 12.1 | Conduct final end-to-end testing across the entire application to resolve all remaining bugs and ensure absolute stability before the final submission. | 20 Hrs |
| Subtask 12.2 | Conduct a feedback round from early adopters and community members; work on follow-up issues or PRs based on that feedback to ensure production readiness. | 15 Hrs |
| Subtask 12.3 | Prepare the final blog post summarizing the project outcomes, architectural shifts, and future directions for the Wikimedia Commons app. Submit final work product. | 10 Hrs |
== 8. What motivates me to work with Wikimedia for GSOC ==
The Wikimedia Commons Android app is a **cornerstone** of the open knowledge ecosystem, empowering millions to enrich one of the world's largest freely licensed media repositories. Contributing to this mission through Google Summer of Code is a unique privilege to build software that democratizes information globally.
Beyond its impact, the Commons app is backed by a vibrant engineering community.Collaborating in this environment presents an ideal opportunity to master **large scale open source development**,adhere to rigorous code quality standards, and collectively maintain software that operates at a massive scale.
The proposed initiative **Modularization and Jetpack Compose migration** is critical overcoming the technical friction inherent in the app's legacy architecture. Currently, the **heavily coupled monolithic structure** complicates dependency management, hinders isolated testing, and inflates Gradle build times.
By decoupling the codebase into high cohesive,feature based modules,we can enforce strict architectural boundaries.. This restructuring will cleanly separate the presentation,domain, and data layers,optimizing parallel build execution and paving the way for a more **robust Clean Architecture implementation.**
Simultaneously, migrating the presentation layer to Jetpack Compose will fundamentally modernize the **application's UI paradigm.** Transitioning away from **imperative XML layouts and state-heavy view controllers** to a declarative framework allows us to enforce a **Unidirectional Data Flow(UDF)**.
Crucially,this migration will overhaul the app's routing architecture. By phasing out manual Fragment transactions, we will integrate the modern **Android Navigation API**.Adopting this industry standard moves the app toward a highly stable **single -activity architecture** with a **centralized NavHost**.
This provides robust, type safe argument passing and completely eliminates the lifecycle related crashes and state loss exceptions notoriously associated with complex Fragment backstacks. Furthermore, Compose will allow us to build a reusable, modular design system that guarantees visual consistency across the app.
The downstream impact of these architectural shifts is profound. For the developer community, feature isolation and a standardized navigation component dramatically lower the cognitive load for new contributors and enable highly targeted, reliable unit and UI testing without bringing up the entire application graph.
For the end users, a modernized UI ensures a more performant fluid, and crash resilient experience. I am eager to drive this modernization forward, delivering scalable, maintainable and contributor-friendly platform that strengthens **Wikimedia's mission of global collaboration.**
== 9. Career Goals ==
As an Android developer, my primary goal is to **master the Android SDK, multithreading,** and related technologies while building a strong portfolio of projects that includes **personal applications, open-source contributions**, and projects developed through academic or professional work.
I have also explored **AOSP** to understand the deeper internals of the Android platform and continue to actively contribute to open-source projects as part of my growth as a developer.
As I gain more experience, I aim to strengthen my expertise in UI/UX design alongside enterprise-scale mobile application development and gradually move into leadership roles. Being largely self taught, open source has played a crucial role in my learning journey, and I hope to give back to the community by sharing knowledge through technical blogs, tutorials, speaking engagements, and continued open-source contributions.
== 10. Previous Participation in GSoC ==
No, this is my first participation in Google Summer of Code
== 11. Application to Multiple Orgs ==
I will be applying only to Wikimedia for this year's GSoC