mirror of
				https://github.com/commons-app/apps-android-commons.git
				synced 2025-11-04 08:43:52 +01:00 
			
		
		
		
	Merge branch 'main' into 1-issue#5829
This commit is contained in:
		
						commit
						045cfa24b3
					
				
					 25 changed files with 293 additions and 37 deletions
				
			
		| 
						 | 
				
			
			@ -50,6 +50,8 @@ dependencies {
 | 
			
		|||
    implementation "com.google.android.material:material:1.12.0"
 | 
			
		||||
    implementation 'com.karumi:dexter:5.0.0'
 | 
			
		||||
    implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
 | 
			
		||||
    implementation 'androidx.compose.ui:ui-tooling-preview'
 | 
			
		||||
    androidTestImplementation 'androidx.compose.ui:ui-test-junit4'
 | 
			
		||||
 | 
			
		||||
    // Jetpack Compose
 | 
			
		||||
    def composeBom = platform('androidx.compose:compose-bom:2024.11.00')
 | 
			
		||||
| 
						 | 
				
			
			@ -87,6 +89,8 @@ dependencies {
 | 
			
		|||
    // Dependency injector
 | 
			
		||||
    implementation "com.google.dagger:dagger-android:$DAGGER_VERSION"
 | 
			
		||||
    implementation "com.google.dagger:dagger-android-support:$DAGGER_VERSION"
 | 
			
		||||
    debugImplementation 'androidx.compose.ui:ui-tooling'
 | 
			
		||||
    debugImplementation 'androidx.compose.ui:ui-test-manifest'
 | 
			
		||||
    kapt "com.google.dagger:dagger-android-processor:$DAGGER_VERSION"
 | 
			
		||||
    kapt "com.google.dagger:dagger-compiler:$DAGGER_VERSION"
 | 
			
		||||
    annotationProcessor "com.google.dagger:dagger-android-processor:$DAGGER_VERSION"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -55,6 +55,10 @@
 | 
			
		|||
    android:theme="@style/LightAppTheme"
 | 
			
		||||
    tools:ignore="GoogleAppIndexingWarning"
 | 
			
		||||
    tools:replace="android:appComponentFactory">
 | 
			
		||||
    <activity
 | 
			
		||||
      android:name=".activity.SingleWebViewActivity"
 | 
			
		||||
      android:exported="false"
 | 
			
		||||
      android:label="@string/title_activity_single_web_view" />
 | 
			
		||||
    <activity
 | 
			
		||||
      android:name=".nearby.WikidataFeedback"
 | 
			
		||||
      android:exported="false" />
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,181 @@
 | 
			
		|||
package fr.free.nrw.commons.activity
 | 
			
		||||
 | 
			
		||||
import android.annotation.SuppressLint
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.webkit.ConsoleMessage
 | 
			
		||||
import android.webkit.WebChromeClient
 | 
			
		||||
import android.webkit.WebResourceRequest
 | 
			
		||||
import android.webkit.WebView
 | 
			
		||||
import android.webkit.WebViewClient
 | 
			
		||||
import androidx.activity.ComponentActivity
 | 
			
		||||
import androidx.activity.compose.setContent
 | 
			
		||||
import androidx.activity.enableEdgeToEdge
 | 
			
		||||
import androidx.compose.foundation.layout.fillMaxSize
 | 
			
		||||
import androidx.compose.foundation.layout.padding
 | 
			
		||||
import androidx.compose.material.icons.Icons
 | 
			
		||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
 | 
			
		||||
import androidx.compose.material3.ExperimentalMaterial3Api
 | 
			
		||||
import androidx.compose.material3.Icon
 | 
			
		||||
import androidx.compose.material3.IconButton
 | 
			
		||||
import androidx.compose.material3.Scaffold
 | 
			
		||||
import androidx.compose.material3.Text
 | 
			
		||||
import androidx.compose.material3.TopAppBar
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.runtime.mutableStateOf
 | 
			
		||||
import androidx.compose.runtime.remember
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.viewinterop.AndroidView
 | 
			
		||||
import fr.free.nrw.commons.R
 | 
			
		||||
import timber.log.Timber
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
class SingleWebViewActivity : ComponentActivity() {
 | 
			
		||||
    @OptIn(ExperimentalMaterial3Api::class)
 | 
			
		||||
    override fun onCreate(savedInstanceState: Bundle?) {
 | 
			
		||||
        super.onCreate(savedInstanceState)
 | 
			
		||||
        val url = intent.getStringExtra(VANISH_ACCOUNT_URL)
 | 
			
		||||
        val successUrl = intent.getStringExtra(VANISH_ACCOUNT_SUCCESS_URL)
 | 
			
		||||
        if (url == null || successUrl == null) {
 | 
			
		||||
            finish()
 | 
			
		||||
            return
 | 
			
		||||
        }
 | 
			
		||||
        enableEdgeToEdge()
 | 
			
		||||
        setContent {
 | 
			
		||||
            Scaffold(
 | 
			
		||||
                topBar = {
 | 
			
		||||
                    TopAppBar(
 | 
			
		||||
                        modifier = Modifier,
 | 
			
		||||
                        title = { Text(getString(R.string.vanish_account)) },
 | 
			
		||||
                        navigationIcon = {
 | 
			
		||||
                            IconButton(
 | 
			
		||||
                                onClick = {
 | 
			
		||||
                                    // Close the WebView Activity if the user taps the back button
 | 
			
		||||
                                    finish()
 | 
			
		||||
                                },
 | 
			
		||||
                            ) {
 | 
			
		||||
                                Icon(
 | 
			
		||||
                                    imageVector = Icons.AutoMirrored.Filled.ArrowBack,
 | 
			
		||||
                                    // TODO("Add contentDescription)
 | 
			
		||||
                                    contentDescription = ""
 | 
			
		||||
                                )
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    )
 | 
			
		||||
                },
 | 
			
		||||
                content = {
 | 
			
		||||
                    WebViewComponent(
 | 
			
		||||
                        url = url,
 | 
			
		||||
                        successUrl = successUrl,
 | 
			
		||||
                        onSuccess = {
 | 
			
		||||
                            // TODO Redirect the user to login screen like we do when the user logout's
 | 
			
		||||
                            finish()
 | 
			
		||||
                        },
 | 
			
		||||
                        modifier = Modifier
 | 
			
		||||
                            .fillMaxSize()
 | 
			
		||||
                            .padding(it)
 | 
			
		||||
                    )
 | 
			
		||||
                }
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param url The initial URL which we are loading in the WebView.
 | 
			
		||||
     * @param successUrl The URL that, when reached, triggers the `onSuccess` callback.
 | 
			
		||||
     * @param onSuccess A callback that is invoked when the current url of webView is successUrl.
 | 
			
		||||
     * This is used when we want to close when the webView once a success url is hit.
 | 
			
		||||
     * @param modifier An optional [Modifier] to customize the layout or appearance of the WebView.
 | 
			
		||||
     */
 | 
			
		||||
    @SuppressLint("SetJavaScriptEnabled")
 | 
			
		||||
    @Composable
 | 
			
		||||
    private fun WebViewComponent(
 | 
			
		||||
        url: String,
 | 
			
		||||
        successUrl: String,
 | 
			
		||||
        onSuccess: () -> Unit,
 | 
			
		||||
        modifier: Modifier = Modifier
 | 
			
		||||
    ) {
 | 
			
		||||
        val webView = remember { mutableStateOf<WebView?>(null) }
 | 
			
		||||
        AndroidView(
 | 
			
		||||
            modifier = modifier,
 | 
			
		||||
            factory = {
 | 
			
		||||
                WebView(it).apply {
 | 
			
		||||
                    settings.apply {
 | 
			
		||||
                        javaScriptEnabled = true
 | 
			
		||||
                        domStorageEnabled = true
 | 
			
		||||
                        javaScriptCanOpenWindowsAutomatically = true
 | 
			
		||||
 | 
			
		||||
                    }
 | 
			
		||||
                    webViewClient = object : WebViewClient() {
 | 
			
		||||
                        override fun shouldOverrideUrlLoading(
 | 
			
		||||
                            view: WebView?,
 | 
			
		||||
                            request: WebResourceRequest?
 | 
			
		||||
                        ): Boolean {
 | 
			
		||||
 | 
			
		||||
                            request?.url?.let { url ->
 | 
			
		||||
                                Timber.d("URL Loading: $url")
 | 
			
		||||
                                if (url.toString() == successUrl) {
 | 
			
		||||
                                    Timber.d("Success URL detected. Closing WebView.")
 | 
			
		||||
                                    onSuccess() // Close the activity
 | 
			
		||||
                                    return true
 | 
			
		||||
                                }
 | 
			
		||||
                                return false
 | 
			
		||||
                            }
 | 
			
		||||
                            return false
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        override fun onPageFinished(view: WebView?, url: String?) {
 | 
			
		||||
                            super.onPageFinished(view, url)
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    webChromeClient = object : WebChromeClient() {
 | 
			
		||||
                        override fun onConsoleMessage(message: ConsoleMessage): Boolean {
 | 
			
		||||
                            Timber.d("Console: ${message.message()} -- From line ${message.lineNumber()} of ${message.sourceId()}")
 | 
			
		||||
                            return true
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    loadUrl(url)
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            update = {
 | 
			
		||||
                webView.value = it
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        private const val VANISH_ACCOUNT_URL = "VanishAccountUrl"
 | 
			
		||||
        private const val VANISH_ACCOUNT_SUCCESS_URL = "vanishAccountSuccessUrl"
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Launch the WebViewActivity with the specified URL and success URL.
 | 
			
		||||
         * @param context The context from which the activity is launched.
 | 
			
		||||
         * @param url The initial URL to load in the WebView.
 | 
			
		||||
         * @param successUrl The URL that triggers the WebView to close when matched.
 | 
			
		||||
         */
 | 
			
		||||
        fun showWebView(
 | 
			
		||||
            context: Context,
 | 
			
		||||
            url: String,
 | 
			
		||||
            successUrl: String
 | 
			
		||||
        ) {
 | 
			
		||||
            val intent = Intent(
 | 
			
		||||
                context,
 | 
			
		||||
                SingleWebViewActivity::class.java
 | 
			
		||||
            ).apply {
 | 
			
		||||
                putExtra(VANISH_ACCOUNT_URL, url)
 | 
			
		||||
                putExtra(VANISH_ACCOUNT_SUCCESS_URL, successUrl)
 | 
			
		||||
            }
 | 
			
		||||
            context.startActivity(intent)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -61,16 +61,16 @@ class CoordinateEditHelper @Inject constructor(
 | 
			
		|||
    /**
 | 
			
		||||
     * Replaces new coordinates
 | 
			
		||||
     * @param media to be added
 | 
			
		||||
     * @param Latitude to be added
 | 
			
		||||
     * @param Longitude to be added
 | 
			
		||||
     * @param Accuracy to be added
 | 
			
		||||
     * @param latitude to be added
 | 
			
		||||
     * @param longitude to be added
 | 
			
		||||
     * @param accuracy to be added
 | 
			
		||||
     * @return Observable<Boolean>
 | 
			
		||||
     */
 | 
			
		||||
    private fun addCoordinates(
 | 
			
		||||
        media: Media,
 | 
			
		||||
        Latitude: String,
 | 
			
		||||
        Longitude: String,
 | 
			
		||||
        Accuracy: String
 | 
			
		||||
        latitude: String,
 | 
			
		||||
        longitude: String,
 | 
			
		||||
        accuracy: String
 | 
			
		||||
    ): Observable<Boolean>? {
 | 
			
		||||
        Timber.d("thread is coordinates adding %s", Thread.currentThread().getName())
 | 
			
		||||
        val summary = "Adding Coordinates"
 | 
			
		||||
| 
						 | 
				
			
			@ -83,9 +83,9 @@ class CoordinateEditHelper @Inject constructor(
 | 
			
		|||
                .blockingGet()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (Latitude != null) {
 | 
			
		||||
            buffer.append("\n{{Location|").append(Latitude).append("|").append(Longitude)
 | 
			
		||||
                .append("|").append(Accuracy).append("}}")
 | 
			
		||||
        if (latitude != null) {
 | 
			
		||||
            buffer.append("\n{{Location|").append(latitude).append("|").append(longitude)
 | 
			
		||||
                .append("|").append(accuracy).append("}}")
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        val editedLocation = buffer.toString()
 | 
			
		||||
| 
						 | 
				
			
			@ -141,7 +141,7 @@ class CoordinateEditHelper @Inject constructor(
 | 
			
		|||
     * @param media to be added
 | 
			
		||||
     * @param latitude to be added
 | 
			
		||||
     * @param longitude to be added
 | 
			
		||||
     * @param Accuracy to be added
 | 
			
		||||
     * @param accuracy to be added
 | 
			
		||||
     * @param result to be added
 | 
			
		||||
     * @return boolean
 | 
			
		||||
     */
 | 
			
		||||
| 
						 | 
				
			
			@ -150,7 +150,7 @@ class CoordinateEditHelper @Inject constructor(
 | 
			
		|||
        media: Media,
 | 
			
		||||
        latitude: String,
 | 
			
		||||
        longitude: String,
 | 
			
		||||
        Accuracy: String,
 | 
			
		||||
        accuracy: String,
 | 
			
		||||
        result: Boolean
 | 
			
		||||
    ): Boolean {
 | 
			
		||||
        val message: String
 | 
			
		||||
| 
						 | 
				
			
			@ -160,7 +160,7 @@ class CoordinateEditHelper @Inject constructor(
 | 
			
		|||
            media.coordinates = fr.free.nrw.commons.location.LatLng(
 | 
			
		||||
                latitude.toDouble(),
 | 
			
		||||
                longitude.toDouble(),
 | 
			
		||||
                Accuracy.toFloat()
 | 
			
		||||
                accuracy.toFloat()
 | 
			
		||||
            )
 | 
			
		||||
            title += ": " + context.getString(R.string.coordinates_edit_helper_show_edit_title_success)
 | 
			
		||||
            val coordinatesInMessage = StringBuilder()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -271,7 +271,7 @@ class CustomSelectorActivity :
 | 
			
		|||
        dialog.setCancelable(false)
 | 
			
		||||
        dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
 | 
			
		||||
        dialog.setContentView(R.layout.custom_selector_info_dialog)
 | 
			
		||||
        (dialog.findViewById(R.id.btn_ok) as Button).setOnClickListener { dialog.dismiss() }
 | 
			
		||||
        (dialog.findViewById<Button>(R.id.btn_ok))?.setOnClickListener { dialog.dismiss() }
 | 
			
		||||
        dialog.show()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -687,8 +687,8 @@ class CustomSelectorActivity :
 | 
			
		|||
        dialog.setCancelable(false)
 | 
			
		||||
        dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
 | 
			
		||||
        dialog.setContentView(R.layout.custom_selector_limit_dialog)
 | 
			
		||||
        (dialog.findViewById(R.id.btn_dismiss_limit_warning) as Button).setOnClickListener { dialog.dismiss() }
 | 
			
		||||
        (dialog.findViewById(R.id.upload_limit_warning) as TextView).text =
 | 
			
		||||
        (dialog.findViewById<Button>(R.id.btn_dismiss_limit_warning))?.setOnClickListener { dialog.dismiss() }
 | 
			
		||||
        (dialog.findViewById<TextView>(R.id.upload_limit_warning))?.text =
 | 
			
		||||
            resources.getString(
 | 
			
		||||
                R.string.custom_selector_over_limit_warning,
 | 
			
		||||
                uploadLimit,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -40,10 +40,10 @@ class QuizChecker @Inject constructor(
 | 
			
		|||
 | 
			
		||||
    private val compositeDisposable = CompositeDisposable()
 | 
			
		||||
 | 
			
		||||
    private val UPLOAD_COUNT_THRESHOLD = 5
 | 
			
		||||
    private val REVERT_PERCENTAGE_FOR_MESSAGE = "50%"
 | 
			
		||||
    private val REVERT_SHARED_PREFERENCE = "revertCount"
 | 
			
		||||
    private val UPLOAD_SHARED_PREFERENCE = "uploadCount"
 | 
			
		||||
    private val uploadCountThreshold = 5
 | 
			
		||||
    private val revertPercentageForMessage = "50%"
 | 
			
		||||
    private val revertSharedPreference = "revertCount"
 | 
			
		||||
    private val uploadSharedPreference = "uploadCount"
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initializes quiz check by calculating revert parameters and showing quiz if necessary
 | 
			
		||||
| 
						 | 
				
			
			@ -80,12 +80,12 @@ class QuizChecker @Inject constructor(
 | 
			
		|||
     */
 | 
			
		||||
    private fun setTotalUploadCount(uploadCount: Int) {
 | 
			
		||||
        totalUploadCount = uploadCount - revertKvStore.getInt(
 | 
			
		||||
            UPLOAD_SHARED_PREFERENCE,
 | 
			
		||||
            uploadSharedPreference,
 | 
			
		||||
            0
 | 
			
		||||
        )
 | 
			
		||||
        if (totalUploadCount < 0) {
 | 
			
		||||
            totalUploadCount = 0
 | 
			
		||||
            revertKvStore.putInt(UPLOAD_SHARED_PREFERENCE, 0)
 | 
			
		||||
            revertKvStore.putInt(uploadSharedPreference, 0)
 | 
			
		||||
        }
 | 
			
		||||
        isUploadCountFetched = true
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -112,10 +112,10 @@ class QuizChecker @Inject constructor(
 | 
			
		|||
     * @param revertCountFetched Count of deleted uploads
 | 
			
		||||
     */
 | 
			
		||||
    private fun setRevertParameter(revertCountFetched: Int) {
 | 
			
		||||
        revertCount = revertCountFetched - revertKvStore.getInt(REVERT_SHARED_PREFERENCE, 0)
 | 
			
		||||
        revertCount = revertCountFetched - revertKvStore.getInt(revertSharedPreference, 0)
 | 
			
		||||
        if (revertCount < 0) {
 | 
			
		||||
            revertCount = 0
 | 
			
		||||
            revertKvStore.putInt(REVERT_SHARED_PREFERENCE, 0)
 | 
			
		||||
            revertKvStore.putInt(revertSharedPreference, 0)
 | 
			
		||||
        }
 | 
			
		||||
        isRevertCountFetched = true
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -128,13 +128,13 @@ class QuizChecker @Inject constructor(
 | 
			
		|||
        setRevertCount()
 | 
			
		||||
 | 
			
		||||
        if (revertCount < 0 || totalUploadCount < 0) {
 | 
			
		||||
            revertKvStore.putInt(REVERT_SHARED_PREFERENCE, 0)
 | 
			
		||||
            revertKvStore.putInt(UPLOAD_SHARED_PREFERENCE, 0)
 | 
			
		||||
            revertKvStore.putInt(revertSharedPreference, 0)
 | 
			
		||||
            revertKvStore.putInt(uploadSharedPreference, 0)
 | 
			
		||||
            return
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (isRevertCountFetched && isUploadCountFetched &&
 | 
			
		||||
            totalUploadCount >= UPLOAD_COUNT_THRESHOLD &&
 | 
			
		||||
            totalUploadCount >= uploadCountThreshold &&
 | 
			
		||||
            (revertCount * 100) / totalUploadCount >= 50
 | 
			
		||||
        ) {
 | 
			
		||||
            callQuiz(activity)
 | 
			
		||||
| 
						 | 
				
			
			@ -149,7 +149,7 @@ class QuizChecker @Inject constructor(
 | 
			
		|||
        DialogUtil.showAlertDialog(
 | 
			
		||||
            activity,
 | 
			
		||||
            activity.getString(R.string.quiz),
 | 
			
		||||
            activity.getString(R.string.quiz_alert_message, REVERT_PERCENTAGE_FOR_MESSAGE),
 | 
			
		||||
            activity.getString(R.string.quiz_alert_message, revertPercentageForMessage),
 | 
			
		||||
            activity.getString(R.string.about_translate_proceed),
 | 
			
		||||
            activity.getString(android.R.string.cancel),
 | 
			
		||||
            { startQuizActivity(activity) },
 | 
			
		||||
| 
						 | 
				
			
			@ -161,11 +161,11 @@ class QuizChecker @Inject constructor(
 | 
			
		|||
     * Starts the quiz activity and updates preferences for revert and upload counts
 | 
			
		||||
     */
 | 
			
		||||
    private fun startQuizActivity(activity: Activity) {
 | 
			
		||||
        val newRevertSharedPrefs = revertCount + revertKvStore.getInt(REVERT_SHARED_PREFERENCE, 0)
 | 
			
		||||
        revertKvStore.putInt(REVERT_SHARED_PREFERENCE, newRevertSharedPrefs)
 | 
			
		||||
        val newRevertSharedPrefs = revertCount + revertKvStore.getInt(revertSharedPreference, 0)
 | 
			
		||||
        revertKvStore.putInt(revertSharedPreference, newRevertSharedPrefs)
 | 
			
		||||
 | 
			
		||||
        val newUploadCount = totalUploadCount + revertKvStore.getInt(UPLOAD_SHARED_PREFERENCE, 0)
 | 
			
		||||
        revertKvStore.putInt(UPLOAD_SHARED_PREFERENCE, newUploadCount)
 | 
			
		||||
        val newUploadCount = totalUploadCount + revertKvStore.getInt(uploadSharedPreference, 0)
 | 
			
		||||
        revertKvStore.putInt(uploadSharedPreference, newUploadCount)
 | 
			
		||||
 | 
			
		||||
        val intent = Intent(activity, WelcomeActivity::class.java).apply {
 | 
			
		||||
            putExtra("isQuiz", true)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,8 +30,8 @@ import fr.free.nrw.commons.contributions.MainActivity
 | 
			
		|||
class QuizResultActivity : AppCompatActivity() {
 | 
			
		||||
 | 
			
		||||
    private var binding: ActivityQuizResultBinding? = null
 | 
			
		||||
    private val NUMBER_OF_QUESTIONS = 5
 | 
			
		||||
    private val MULTIPLIER_TO_GET_PERCENTAGE = 20
 | 
			
		||||
    private val numberOfQuestions = 5
 | 
			
		||||
    private val multiplierToGetPercentage = 20
 | 
			
		||||
 | 
			
		||||
    public override fun onCreate(savedInstanceState: Bundle?) {
 | 
			
		||||
        super.onCreate(savedInstanceState)
 | 
			
		||||
| 
						 | 
				
			
			@ -67,9 +67,9 @@ class QuizResultActivity : AppCompatActivity() {
 | 
			
		|||
     */
 | 
			
		||||
    @SuppressLint("StringFormatInvalid", "SetTextI18n")
 | 
			
		||||
    fun setScore(score: Int) {
 | 
			
		||||
        val scorePercent = score * MULTIPLIER_TO_GET_PERCENTAGE
 | 
			
		||||
        val scorePercent = score * multiplierToGetPercentage
 | 
			
		||||
        binding?.resultProgressBar?.progress = scorePercent
 | 
			
		||||
        binding?.tvResultProgress?.text = "$score / $NUMBER_OF_QUESTIONS"
 | 
			
		||||
        binding?.tvResultProgress?.text = "$score / $numberOfQuestions"
 | 
			
		||||
        val message = resources.getString(R.string.congratulatory_message_quiz, "$scorePercent%")
 | 
			
		||||
        binding?.congratulatoryMessage?.text = message
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,6 +3,7 @@ package fr.free.nrw.commons.settings
 | 
			
		|||
object Prefs {
 | 
			
		||||
    const val DEFAULT_LICENSE = "defaultLicense"
 | 
			
		||||
    const val MANAGED_EXIF_TAGS = "managed_exif_tags"
 | 
			
		||||
    const val VANISHED_ACCOUNT = "vanishAccount"
 | 
			
		||||
    const val DESCRIPTION_LANGUAGE = "languageDescription"
 | 
			
		||||
    const val APP_UI_LANGUAGE = "appUiLanguage"
 | 
			
		||||
    const val KEY_THEME_VALUE = "appThemePref"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,6 +19,7 @@ import android.widget.TextView
 | 
			
		|||
import androidx.activity.result.ActivityResultLauncher
 | 
			
		||||
import androidx.activity.result.contract.ActivityResultContracts.RequestMultiplePermissions
 | 
			
		||||
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
 | 
			
		||||
import androidx.appcompat.app.AlertDialog
 | 
			
		||||
import androidx.preference.ListPreference
 | 
			
		||||
import androidx.preference.MultiSelectListPreference
 | 
			
		||||
import androidx.preference.Preference
 | 
			
		||||
| 
						 | 
				
			
			@ -34,6 +35,7 @@ import com.karumi.dexter.listener.PermissionRequest
 | 
			
		|||
import com.karumi.dexter.listener.multi.MultiplePermissionsListener
 | 
			
		||||
import fr.free.nrw.commons.R
 | 
			
		||||
import fr.free.nrw.commons.Utils
 | 
			
		||||
import fr.free.nrw.commons.activity.SingleWebViewActivity
 | 
			
		||||
import fr.free.nrw.commons.campaigns.CampaignView
 | 
			
		||||
import fr.free.nrw.commons.contributions.ContributionController
 | 
			
		||||
import fr.free.nrw.commons.contributions.MainActivity
 | 
			
		||||
| 
						 | 
				
			
			@ -48,6 +50,7 @@ import fr.free.nrw.commons.recentlanguages.RecentLanguagesDao
 | 
			
		|||
import fr.free.nrw.commons.upload.LanguagesAdapter
 | 
			
		||||
import fr.free.nrw.commons.utils.DialogUtil
 | 
			
		||||
import fr.free.nrw.commons.utils.PermissionUtils
 | 
			
		||||
import fr.free.nrw.commons.utils.StringUtil
 | 
			
		||||
import fr.free.nrw.commons.utils.ViewUtil
 | 
			
		||||
import java.util.Locale
 | 
			
		||||
import javax.inject.Inject
 | 
			
		||||
| 
						 | 
				
			
			@ -71,6 +74,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
 | 
			
		|||
    @Inject
 | 
			
		||||
    lateinit var locationManager: LocationServiceManager
 | 
			
		||||
 | 
			
		||||
    private var vanishAccountPreference: Preference? = null
 | 
			
		||||
    private var themeListPreference: ListPreference? = null
 | 
			
		||||
    private var descriptionLanguageListPreference: Preference? = null
 | 
			
		||||
    private var appUiLanguageListPreference: Preference? = null
 | 
			
		||||
| 
						 | 
				
			
			@ -79,6 +83,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
 | 
			
		|||
    private var recentLanguagesTextView: TextView? = null
 | 
			
		||||
    private var separator: View? = null
 | 
			
		||||
    private var languageHistoryListView: ListView? = null
 | 
			
		||||
 | 
			
		||||
    private lateinit var inAppCameraLocationPermissionLauncher: ActivityResultLauncher<Array<String>>
 | 
			
		||||
    private val GET_CONTENT_PICKER_HELP_URL = "https://commons-app.github.io/docs.html#get-content"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -114,6 +119,26 @@ class SettingsFragment : PreferenceFragmentCompat() {
 | 
			
		|||
        themeListPreference = findPreference(Prefs.KEY_THEME_VALUE)
 | 
			
		||||
        prepareTheme()
 | 
			
		||||
 | 
			
		||||
        vanishAccountPreference = findPreference(Prefs.VANISHED_ACCOUNT)
 | 
			
		||||
        vanishAccountPreference?.setOnPreferenceClickListener {
 | 
			
		||||
            AlertDialog.Builder(requireContext())
 | 
			
		||||
                .setTitle(R.string.account_vanish_request_confirm_title)
 | 
			
		||||
                .setMessage(StringUtil.fromHtml(getString(R.string.account_vanish_request_confirm)))
 | 
			
		||||
                .setNegativeButton(R.string.cancel){ dialog,_ ->
 | 
			
		||||
                    dialog.dismiss()
 | 
			
		||||
                }
 | 
			
		||||
                .setPositiveButton(R.string.vanish_account) { dialog, _ ->
 | 
			
		||||
                    SingleWebViewActivity.showWebView(
 | 
			
		||||
                        context = requireActivity(),
 | 
			
		||||
                        url = VANISH_ACCOUNT_URL,
 | 
			
		||||
                        successUrl = VANISH_ACCOUNT_SUCCESS_URL
 | 
			
		||||
                    )
 | 
			
		||||
                    dialog.dismiss()
 | 
			
		||||
                }
 | 
			
		||||
                .show()
 | 
			
		||||
            true
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        val multiSelectListPref: MultiSelectListPreference? = findPreference(
 | 
			
		||||
            Prefs.MANAGED_EXIF_TAGS
 | 
			
		||||
        )
 | 
			
		||||
| 
						 | 
				
			
			@ -484,7 +509,10 @@ class SettingsFragment : PreferenceFragmentCompat() {
 | 
			
		|||
        editor.apply()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Suppress("LongLine")
 | 
			
		||||
    companion object {
 | 
			
		||||
        private const val VANISH_ACCOUNT_URL = "https://meta.m.wikimedia.org/wiki/Special:Contact/accountvanishapps"
 | 
			
		||||
        private const val VANISH_ACCOUNT_SUCCESS_URL = "https://meta.m.wikimedia.org/wiki/Special:GlobalVanishRequest/vanished"
 | 
			
		||||
        /**
 | 
			
		||||
         * Create Locale based on different types of language codes
 | 
			
		||||
         * @param languageCode
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -875,4 +875,6 @@
 | 
			
		|||
  <string name="usages_on_commons_heading">كومنز</string>
 | 
			
		||||
  <string name="usages_on_other_wikis_heading">مواقع ويكي أخرى</string>
 | 
			
		||||
  <string name="file_usages_container_heading">حالات استخدام الملف</string>
 | 
			
		||||
  <string name="caption">الشرح</string>
 | 
			
		||||
  <string name="caption_copied_to_clipboard">تم نسخ التسمية التوضيحية إلى الحافظة</string>
 | 
			
		||||
</resources>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -529,4 +529,6 @@
 | 
			
		|||
  <string name="uploads">আপলোড</string>
 | 
			
		||||
  <string name="pending">অমীমাংসিত</string>
 | 
			
		||||
  <string name="failed">ব্যর্থ হয়েছে</string>
 | 
			
		||||
  <string name="caption">ক্যাপশন</string>
 | 
			
		||||
  <string name="caption_copied_to_clipboard">ক্যাপশন ক্লিপবোর্ডে অনুলিপি করা হয়েছে</string>
 | 
			
		||||
</resources>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -814,4 +814,6 @@
 | 
			
		|||
  <string name="usages_on_other_wikis_heading">Andre wikier</string>
 | 
			
		||||
  <string name="bullet_point">•</string>
 | 
			
		||||
  <string name="file_usages_container_heading">Filanvendelser</string>
 | 
			
		||||
  <string name="caption">Billedtekst</string>
 | 
			
		||||
  <string name="caption_copied_to_clipboard">Billedtekst kopieret til udklipsholder</string>
 | 
			
		||||
</resources>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -32,6 +32,7 @@
 | 
			
		|||
* Orikrin1998
 | 
			
		||||
* Paraboule
 | 
			
		||||
* Patrick Star
 | 
			
		||||
* Pols12
 | 
			
		||||
* Robins7
 | 
			
		||||
* Sherbrooke
 | 
			
		||||
* SleaY
 | 
			
		||||
| 
						 | 
				
			
			@ -852,4 +853,6 @@
 | 
			
		|||
  <string name="usages_on_other_wikis_heading">Autres wikis</string>
 | 
			
		||||
  <string name="bullet_point">•</string>
 | 
			
		||||
  <string name="file_usages_container_heading">Utilisations du fichier</string>
 | 
			
		||||
  <string name="caption">Légende</string>
 | 
			
		||||
  <string name="caption_copied_to_clipboard">Légende copiée dans le presse-papier</string>
 | 
			
		||||
</resources>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -358,4 +358,5 @@
 | 
			
		|||
  <string name="custom_selector_delete_folder">फ़ोल्डर हटाएँ</string>
 | 
			
		||||
  <string name="custom_selector_delete">हटाएँ</string>
 | 
			
		||||
  <string name="custom_selector_cancel">रद्द करें</string>
 | 
			
		||||
  <string name="caption">कैप्शन</string>
 | 
			
		||||
</resources>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -773,4 +773,6 @@
 | 
			
		|||
  <string name="usages_on_commons_heading">Commons</string>
 | 
			
		||||
  <string name="usages_on_other_wikis_heading">Altri wiki</string>
 | 
			
		||||
  <string name="file_usages_container_heading">Utilizzi del file</string>
 | 
			
		||||
  <string name="caption">Didascalia</string>
 | 
			
		||||
  <string name="caption_copied_to_clipboard">Didascalia copiata negli appunti</string>
 | 
			
		||||
</resources>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<!-- Authors:
 | 
			
		||||
* GilPe
 | 
			
		||||
* Les Meloures
 | 
			
		||||
* Robby
 | 
			
		||||
* Soued031
 | 
			
		||||
| 
						 | 
				
			
			@ -532,4 +533,6 @@
 | 
			
		|||
  <string name="error_while_loading">Feeler beim Lueden</string>
 | 
			
		||||
  <string name="usages_on_commons_heading">Commons</string>
 | 
			
		||||
  <string name="usages_on_other_wikis_heading">Aner Wikien</string>
 | 
			
		||||
  <string name="caption">Beschrëftung</string>
 | 
			
		||||
  <string name="caption_copied_to_clipboard">Text an den Tëschespäicher kopéiert</string>
 | 
			
		||||
</resources>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -810,4 +810,6 @@
 | 
			
		|||
  <string name="usages_on_other_wikis_heading">Други викија</string>
 | 
			
		||||
  <string name="bullet_point">•</string>
 | 
			
		||||
  <string name="file_usages_container_heading">Употреби на податотеката</string>
 | 
			
		||||
  <string name="caption">Толкување</string>
 | 
			
		||||
  <string name="caption_copied_to_clipboard">Толкувањето е ставено во меѓускладот</string>
 | 
			
		||||
</resources>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -160,7 +160,7 @@
 | 
			
		|||
  <string name="navigation_item_upload">ਚੜ੍ਹਾਉ</string>
 | 
			
		||||
  <string name="navigation_item_nearby">ਨੇੜੇ-ਤੇੜੇ</string>
 | 
			
		||||
  <string name="navigation_item_about">ਬਾਰੇ</string>
 | 
			
		||||
  <string name="navigation_item_settings">ਸੈਟਿੰਗਾਂ</string>
 | 
			
		||||
  <string name="navigation_item_settings">ਤਰਜੀਹਾਂ</string>
 | 
			
		||||
  <string name="navigation_item_feedback">ਸੁਝਾਅ</string>
 | 
			
		||||
  <string name="navigation_item_logout">ਬਾਹਰ ਆਉ</string>
 | 
			
		||||
  <string name="navigation_item_info">ਸਿਖਲਾਈ</string>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -806,4 +806,6 @@
 | 
			
		|||
  <string name="usages_on_other_wikis_heading">Àutre wiki</string>
 | 
			
		||||
  <string name="bullet_point">•</string>
 | 
			
		||||
  <string name="file_usages_container_heading">Usagi dl\'archivi</string>
 | 
			
		||||
  <string name="caption">Legenda</string>
 | 
			
		||||
  <string name="caption_copied_to_clipboard">Legenda copià an sla taulëtta</string>
 | 
			
		||||
</resources>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -217,6 +217,7 @@
 | 
			
		|||
  <string name="next">Čuovvovaš</string>
 | 
			
		||||
  <string name="title_page_bookmarks_pictures">Govat</string>
 | 
			
		||||
  <string name="title_page_bookmarks_locations">Sajit</string>
 | 
			
		||||
  <string name="title_page_bookmarks_categories">Kategoriijat</string>
 | 
			
		||||
  <string name="provider_bookmarks">Girjemearkkat</string>
 | 
			
		||||
  <string name="provider_bookmarks_location">Girjemearkkat</string>
 | 
			
		||||
  <string name="no_categories_selected">Ii oktage kategoriija leat válljejuvvon</string>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -277,4 +277,5 @@
 | 
			
		|||
  <string name="custom_selector_delete">مٹاؤ</string>
 | 
			
		||||
  <string name="custom_selector_cancel">منسوخ</string>
 | 
			
		||||
  <string name="usages_on_commons_heading">کامنز</string>
 | 
			
		||||
  <string name="caption">عنوان</string>
 | 
			
		||||
</resources>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -743,4 +743,6 @@
 | 
			
		|||
  <string name="failed">Није успело</string>
 | 
			
		||||
  <string name="green_pin">Ово место већ има слику</string>
 | 
			
		||||
  <string name="grey_pin">Проверавање да ли ово место има слику.</string>
 | 
			
		||||
  <string name="caption">Поднапис</string>
 | 
			
		||||
  <string name="caption_copied_to_clipboard">Поднапис копиран</string>
 | 
			
		||||
</resources>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -860,6 +860,11 @@ Upload your first media by tapping on the add button.</string>
 | 
			
		|||
  <string name="usages_on_other_wikis_heading">Other wikis</string>
 | 
			
		||||
  <string name="bullet_point">•</string>
 | 
			
		||||
  <string name="file_usages_container_heading">File usages</string>
 | 
			
		||||
  <string name="title_activity_single_web_view">SingleWebViewActivity</string>
 | 
			
		||||
  <string name="account">Account</string>
 | 
			
		||||
  <string name="vanish_account">Vanish Account</string>
 | 
			
		||||
  <string name="account_vanish_request_confirm_title">Vanish account warning</string>
 | 
			
		||||
  <string name="account_vanish_request_confirm"><![CDATA[Vanishing is a <b>last resort</b> and should <b>only be used when you wish to stop editing forever</b> and also to hide as many of your past associations as possible.<br/><br/>Account deletion on Wikimedia Commons is done by changing your account name to make it so others cannot recognize your contributions in a process called account vanishing. <b>Vanishing does not guarantee complete anonymity or remove contributions to the projects</b>.]]></string>
 | 
			
		||||
  <string name="caption">Caption</string>
 | 
			
		||||
  <string name="caption_copied_to_clipboard">Caption copied to clipboard</string>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -129,4 +129,14 @@
 | 
			
		|||
          android:title="@string/send_log_file" />
 | 
			
		||||
 | 
			
		||||
    </PreferenceCategory>
 | 
			
		||||
 | 
			
		||||
    <PreferenceCategory
 | 
			
		||||
      android:title="@string/account">
 | 
			
		||||
 | 
			
		||||
        <Preference
 | 
			
		||||
          android:key="vanishAccount"
 | 
			
		||||
          app:singleLineTitle="false"
 | 
			
		||||
          android:title="@string/vanish_account"/>
 | 
			
		||||
 | 
			
		||||
    </PreferenceCategory>
 | 
			
		||||
</PreferenceScreen>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue