Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .idea/inspectionProfiles/Project_Default.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 19 additions & 7 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ import java.io.ByteArrayOutputStream

plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.jetbrains.kotlin.android)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.ksp)
alias(libs.plugins.kotlin.kapt)
alias(libs.plugins.kotlin.parcelize)
alias(libs.plugins.compose)
alias(libs.plugins.hilt)
}

apply(from = "$rootDir/jacoco.gradle")
Expand Down Expand Up @@ -182,9 +185,7 @@ android {
compose = true
}
buildToolsVersion = buildToolsVersion
composeOptions {
kotlinCompilerExtensionVersion = "1.5.8"
}

packaging {
jniLibs {
excludes += listOf("META-INF/androidx.*")
Expand Down Expand Up @@ -214,7 +215,14 @@ android {
}
}

composeCompiler {
enableStrongSkippingMode = true
}

dependencies {
// Feature Modules
implementation(project(":feature-profile"))

// Utils
implementation(libs.gson)
implementation(libs.okhttp)
Expand Down Expand Up @@ -280,6 +288,10 @@ dependencies {
kapt(libs.dagger.compiler)
annotationProcessor(libs.dagger.android.processor)

// Hilt
implementation(libs.hilt.android)
kapt(libs.hilt.compiler)

implementation(libs.kotlin.reflect)

//Mocking
Expand Down Expand Up @@ -335,7 +347,7 @@ dependencies {
implementation(libs.androidx.room.runtime)
implementation(libs.androidx.room.ktx)
implementation(libs.androidx.room.rxjava)
kapt(libs.androidx.room.compiler)
ksp(libs.androidx.room.compiler)

// Preferences
implementation(libs.androidx.preference)
Expand All @@ -354,8 +366,8 @@ dependencies {
//Glide
implementation(libs.glide)
annotationProcessor(libs.glide.compiler)
kaptTest(libs.androidx.databinding.compiler)
kaptAndroidTest(libs.androidx.databinding.compiler)
ksp(libs.androidx.databinding.compiler)
Copy link

Copilot AI Nov 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The databinding compiler should use kspTest configuration instead of ksp for the main source set. The original code had kaptTest and kaptAndroidTest which are test-specific. Using ksp here will apply databinding to production code unnecessarily. This line should either be removed or changed to kspTest.

Suggested change
ksp(libs.androidx.databinding.compiler)

Copilot uses AI. Check for mistakes.
kspAndroidTest(libs.androidx.databinding.compiler)

implementation(libs.coordinates2country.android) {
exclude(group = "com.google.android", module = "android")
Expand Down
4 changes: 1 addition & 3 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,13 @@

<application
android:name=".CommonsApplication"
android:appComponentFactory="commons"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:largeHeap="true"
android:requestLegacyExternalStorage="true"
android:supportsRtl="true"
android:theme="@style/LightAppTheme"
tools:ignore="GoogleAppIndexingWarning"
tools:replace="android:appComponentFactory">
tools:ignore="GoogleAppIndexingWarning">
<activity
android:name=".activity.SingleWebViewActivity"
android:exported="false" />
Expand Down
9 changes: 4 additions & 5 deletions app/src/main/java/fr/free/nrw/commons/CommonsApplication.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import android.util.Log
import androidx.multidex.MultiDexApplication
import com.facebook.drawee.backends.pipeline.Fresco
import com.facebook.imagepipeline.core.ImagePipelineConfig
import dagger.hilt.android.HiltAndroidApp
import fr.free.nrw.commons.auth.LoginActivity
import fr.free.nrw.commons.auth.SessionManager
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsTable
Expand All @@ -22,7 +23,6 @@ import fr.free.nrw.commons.concurrency.BackgroundPoolExceptionHandler
import fr.free.nrw.commons.concurrency.ThreadPoolService
import fr.free.nrw.commons.contributions.ContributionDao
import fr.free.nrw.commons.data.DBOpenHelper
import fr.free.nrw.commons.di.ApplicationlessInjection
import fr.free.nrw.commons.kvstore.JsonKvStore
import fr.free.nrw.commons.language.AppLanguageLookUpTable
import fr.free.nrw.commons.logging.FileLoggingTree
Expand Down Expand Up @@ -66,6 +66,7 @@ import javax.inject.Named
resCommentPrompt = R.string.crash_dialog_comment_prompt
)

@HiltAndroidApp
class CommonsApplication : MultiDexApplication() {

@Inject
Expand Down Expand Up @@ -99,10 +100,8 @@ class CommonsApplication : MultiDexApplication() {
instance = this
init(this)

ApplicationlessInjection
.getInstance(this)
.commonsApplicationComponent
.inject(this)
// Hilt automatically injects dependencies for @HiltAndroidApp annotated classes
// No manual injection needed

initTimber()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.viewinterop.AndroidView
import dagger.hilt.android.AndroidEntryPoint
import fr.free.nrw.commons.CommonsApplication
import fr.free.nrw.commons.CommonsApplication.ActivityLogoutListener
import fr.free.nrw.commons.R
import fr.free.nrw.commons.di.ApplicationlessInjection
import fr.free.nrw.commons.wikidata.cookies.CommonsCookieJar
import okhttp3.HttpUrl.Companion.toHttpUrl
import timber.log.Timber
Expand All @@ -41,6 +41,7 @@ import javax.inject.Inject
* SingleWebViewActivity is a reusable activity webView based on a given url(initial url) and
* closes itself when a specified success URL is reached to success url.
*/
@AndroidEntryPoint
class SingleWebViewActivity : ComponentActivity() {
@Inject
lateinit var cookieJar: CommonsCookieJar
Expand All @@ -54,10 +55,7 @@ class SingleWebViewActivity : ComponentActivity() {
finish()
return
}
ApplicationlessInjection
.getInstance(applicationContext)
.commonsApplicationComponent
.inject(this)
// Hilt automatically injects dependencies for @AndroidEntryPoint annotated classes
setCookies(url)
enableEdgeToEdge()
setContent {
Expand Down
57 changes: 31 additions & 26 deletions app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.kt
Original file line number Diff line number Diff line change
@@ -1,25 +1,24 @@
package fr.free.nrw.commons.auth

import android.accounts.AccountAuthenticatorActivity
import android.accounts.Account
import android.accounts.AccountManager
import android.app.ProgressDialog
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.view.KeyEvent
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
import android.widget.TextView
import androidx.annotation.ColorRes
import androidx.annotation.StringRes
import androidx.annotation.VisibleForTesting
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatDelegate
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.NavUtils
import androidx.core.content.ContextCompat
import androidx.core.view.WindowCompat
Expand All @@ -31,7 +30,6 @@ import fr.free.nrw.commons.auth.login.LoginClient
import fr.free.nrw.commons.auth.login.LoginResult
import fr.free.nrw.commons.contributions.MainActivity
import fr.free.nrw.commons.databinding.ActivityLoginBinding
import fr.free.nrw.commons.di.ApplicationlessInjection
import fr.free.nrw.commons.kvstore.JsonKvStore
import fr.free.nrw.commons.utils.applyEdgeToEdgeAllInsets
import fr.free.nrw.commons.utils.AbstractTextWatcher
Expand All @@ -41,13 +39,15 @@ import fr.free.nrw.commons.utils.SystemThemeUtils
import fr.free.nrw.commons.utils.ViewUtil.hideKeyboard
import fr.free.nrw.commons.utils.handleKeyboardInsets
import fr.free.nrw.commons.utils.handleWebUrl
import dagger.hilt.android.AndroidEntryPoint
import io.reactivex.disposables.CompositeDisposable
import timber.log.Timber
import java.util.Locale
import javax.inject.Inject
import javax.inject.Named

class LoginActivity : AccountAuthenticatorActivity() {
@AndroidEntryPoint
class LoginActivity : AppCompatActivity() {
@Inject
lateinit var sessionManager: SessionManager

Expand All @@ -65,22 +65,14 @@ class LoginActivity : AccountAuthenticatorActivity() {
private var progressDialog: ProgressDialog? = null
private val textWatcher = AbstractTextWatcher(::onTextChanged)
private val compositeDisposable = CompositeDisposable()
private val delegate: AppCompatDelegate by lazy {
AppCompatDelegate.create(this, null)
}
private var lastLoginResult: LoginResult? = null

public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
ApplicationlessInjection
.getInstance(this.applicationContext)
.commonsApplicationComponent
.inject(this)
// Hilt automatically injects dependencies for @AndroidEntryPoint annotated classes

val isDarkTheme = systemThemeUtils.isDeviceInNightMode()
setTheme(if (isDarkTheme) R.style.DarkAppTheme else R.style.LightAppTheme)
delegate.installViewFactory()
delegate.onCreate(savedInstanceState)

WindowCompat.getInsetsController(window, window.decorView)
.isAppearanceLightStatusBars = !isDarkTheme
Expand Down Expand Up @@ -170,7 +162,6 @@ class LoginActivity : AccountAuthenticatorActivity() {
}
override fun onPostCreate(savedInstanceState: Bundle?) {
super.onPostCreate(savedInstanceState)
delegate.onPostCreate(savedInstanceState)
}

override fun onResume() {
Expand Down Expand Up @@ -201,29 +192,21 @@ class LoginActivity : AccountAuthenticatorActivity() {
loginPassword.removeTextChangedListener(textWatcher)
loginTwoFactor.removeTextChangedListener(textWatcher)
}
delegate.onDestroy()
loginClient.cancel()
binding = null
super.onDestroy()
}

override fun onStart() {
super.onStart()
delegate.onStart()
}

override fun onStop() {
super.onStop()
delegate.onStop()
}

override fun onPostResume() {
super.onPostResume()
delegate.onPostResume()
}

override fun setContentView(view: View, params: ViewGroup.LayoutParams) {
delegate.setContentView(view, params)
}

override fun onOptionsItemSelected(item: MenuItem): Boolean {
Expand All @@ -237,6 +220,7 @@ class LoginActivity : AccountAuthenticatorActivity() {
}

override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
// if progressDialog is visible during the configuration change then store state as true else false so that
// we maintain visibility of progressDialog after configuration change
if (progressDialog != null && progressDialog!!.isShowing) {
Expand Down Expand Up @@ -398,8 +382,6 @@ class LoginActivity : AccountAuthenticatorActivity() {
startMainActivity()
}

override fun getMenuInflater(): MenuInflater =
delegate.menuInflater

@VisibleForTesting
fun askUserForTwoFactorAuth() {
Expand Down Expand Up @@ -454,10 +436,33 @@ class LoginActivity : AccountAuthenticatorActivity() {

@VisibleForTesting
fun startMainActivity() {
// Handle account authentication result for AccountManager
// Since we're now using AppCompatActivity instead of AccountAuthenticatorActivity
val accountManager = AccountManager.get(this)
val accountName = sessionManager.userName

if (accountName != null) {
val account = Account(accountName, BuildConfig.ACCOUNT_TYPE)
val intent = Intent()
intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, accountName)
intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, BuildConfig.ACCOUNT_TYPE)
setAccountAuthenticatorResult(intent.extras)
setResult(RESULT_OK, intent)
}

startActivityWithFlags(this, MainActivity::class.java, Intent.FLAG_ACTIVITY_SINGLE_TOP)
finish()
}

// Helper method to set the account authenticator result
private fun setAccountAuthenticatorResult(result: Bundle?) {
// This would be called automatically in AccountAuthenticatorActivity
// but we need to handle it manually now
result?.let {
intent.putExtras(it)
}
}

private fun showMessage(@StringRes resId: Int, @ColorRes colorResId: Int) = with(binding!!) {
errorMessage.text = getString(resId)
errorMessage.setTextColor(ContextCompat.getColor(this@LoginActivity, colorResId))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ package fr.free.nrw.commons.auth
import android.accounts.AbstractAccountAuthenticator
import android.content.Intent
import android.os.IBinder
import dagger.hilt.android.AndroidEntryPoint
import fr.free.nrw.commons.di.CommonsDaggerService

/**
* Handles the Auth service of the App, see AndroidManifests for details
* (Uses Dagger 2 as injector)
*/
@AndroidEntryPoint
class WikiAccountAuthenticatorService : CommonsDaggerService() {
private var authenticator: AbstractAccountAuthenticator? = null

Expand Down
Loading
Loading