From dc887beb59515b1aa360f7ba5dc30e10a157f580 Mon Sep 17 00:00:00 2001 From: Kota-Jagadeesh Date: Fri, 24 Apr 2026 15:56:31 +0530 Subject: [PATCH 1/4] fix: correct self upload media using uploader instead of author --- .../nrw/commons/media/MediaDetailFragment.kt | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.kt b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.kt index 1ae954293fb..0bf51a7f065 100644 --- a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.kt +++ b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.kt @@ -515,14 +515,8 @@ class MediaDetailFragment : CommonsDaggerSupportFragment(), CategoryEditHelper.C enableProgressBar() } - if (getUserName(requireContext()) != null && media != null && getUserName( - requireContext() - ) == media!!.author - ) { - binding.sendThanks.visibility = View.GONE - } else { - binding.sendThanks.visibility = View.VISIBLE - } + binding.sendThanks.visibility = + if (isOwnUpload()) View.GONE else View.VISIBLE binding.mediaDetailScrollView.viewTreeObserver.addOnGlobalLayoutListener( object : OnGlobalLayoutListener { @@ -611,6 +605,14 @@ class MediaDetailFragment : CommonsDaggerSupportFragment(), CategoryEditHelper.C ) } + private fun isOwnUpload(): Boolean { + val currentUser = getUserName(requireContext())?.trim() + val uploader = media?.user?.trim() + return !currentUser.isNullOrEmpty() && + !uploader.isNullOrEmpty() && + currentUser.equals(uploader, ignoreCase = true) + } + private fun onMediaRefreshed(media: Media) { media.categories = this.media!!.categories this.media = media @@ -630,10 +632,12 @@ class MediaDetailFragment : CommonsDaggerSupportFragment(), CategoryEditHelper.C } private fun onDeletionPageExists(deletionPageExists: Boolean) { - if (getUserName(requireContext()) == null && getUserName(requireContext()) != media!!.author) { + val currentUser = getUserName(requireContext())?.trim() + if (currentUser == null) { binding.nominateDeletion.visibility = View.GONE binding.nominatedDeletionBanner.visibility = View.GONE - } else if (deletionPageExists) { + return } + if (deletionPageExists) { if (applicationKvStore.getBoolean( String.format(NOMINATING_FOR_DELETION_MEDIA, media!!.imageUrl), false ) @@ -823,7 +827,7 @@ class MediaDetailFragment : CommonsDaggerSupportFragment(), CategoryEditHelper.C // Show author or uploader information for licensing compliance val authorName = media.getAttributedAuthor() val uploaderName = media.user - + when { !authorName.isNullOrEmpty() -> { // Show author if available @@ -1635,7 +1639,7 @@ class MediaDetailFragment : CommonsDaggerSupportFragment(), CategoryEditHelper.C @SuppressLint("StringFormatInvalid") fun onDeleteButtonClicked() { - if (getUserName(requireContext()) != null && getUserName(requireContext()) == media!!.author) { + if (isOwnUpload()) { val languageAdapter: ArrayAdapter = ArrayAdapter( requireActivity(), R.layout.simple_spinner_dropdown_list, reasonList From 17477d7133739d98b7e6486d2173f0ddd44510f9 Mon Sep 17 00:00:00 2001 From: Rohit Verma <101377978+rohit9625@users.noreply.github.com> Date: Fri, 24 Apr 2026 19:37:17 +0530 Subject: [PATCH 2/4] chore: bump target and compile SDK to API level 36 (#6868) * refactor: replace deprecated onBackPressed with OnBackPressedDispatcher Migrates back navigation logic across several activities to use the OnBackPressedDispatcher API. * chore: upgrade target and compile SDK to API 36 * fix: correct back button logic for contributions screen in MainActivity * refactor: use OnBackPressedDispatcher for fragment back navigation Migrates MediaDetailFragment, UploadCategoriesFragment, and DepictsFragment from manual OnKeyListener back button handling to the modern OnBackPressedCallback API * fix: set exported to false for DescriptionEditActivity in manifest file * test: fix unit tests --------- Co-authored-by: Nicolas Raoul --- app/build.gradle.kts | 4 +- app/src/main/AndroidManifest.xml | 2 +- .../java/fr/free/nrw/commons/AboutActivity.kt | 2 +- .../fr/free/nrw/commons/WelcomeActivity.kt | 29 +++--- .../free/nrw/commons/auth/SignupActivity.kt | 19 ++-- .../category/CategoryDetailsActivity.kt | 34 ++++--- .../nrw/commons/contributions/MainActivity.kt | 88 ++++++++++--------- .../ui/selector/CustomSelectorActivity.kt | 37 ++++---- .../nrw/commons/explore/SearchActivity.kt | 61 ++++++------- .../depictions/WikidataItemDetailsActivity.kt | 31 +++---- .../explore/media/PageableMediaFragment.kt | 2 +- .../nrw/commons/media/MediaDetailFragment.kt | 33 +++---- .../nrw/commons/media/ZoomableActivity.kt | 38 ++++---- .../nrw/commons/nearby/WikidataFeedback.kt | 2 +- .../notification/NotificationActivity.kt | 4 +- .../nrw/commons/profile/ProfileActivity.kt | 25 +++--- .../fr/free/nrw/commons/quiz/QuizActivity.kt | 38 ++++---- .../nrw/commons/quiz/QuizResultActivity.kt | 23 +++-- .../free/nrw/commons/review/ReviewActivity.kt | 32 ++++--- .../nrw/commons/settings/SettingsActivity.kt | 2 +- .../commons/upload/UploadProgressActivity.kt | 2 +- .../categories/UploadCategoriesFragment.kt | 48 +++++----- .../commons/upload/depicts/DepictsFragment.kt | 40 ++++----- .../contributions/MainActivityUnitTests.kt | 2 +- .../media/ZoomableActivityUnitTests.kt | 4 +- app/src/test/resources/robolectric.properties | 1 + 26 files changed, 304 insertions(+), 299 deletions(-) create mode 100644 app/src/test/resources/robolectric.properties diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 51141015c6f..f7111c79eab 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -19,12 +19,12 @@ if (isRunningOnTravisAndIsNotPRBuild) { android { namespace = "fr.free.nrw.commons" - compileSdk = 35 + compileSdk = 36 defaultConfig { applicationId = "fr.free.nrw.commons" minSdk = 21 - targetSdk = 35 + targetSdk = 36 versionCode = 1064 versionName = "6.5.0" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 17fad9d8175..6ea3754e525 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -66,7 +66,7 @@ android:exported="false" /> finishTutorial() } + + onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + if (binding!!.welcomePager.currentItem != 0) { + binding!!.welcomePager.setCurrentItem(binding!!.welcomePager.currentItem - 1, true) + } else { + if (defaultKvStore.getBoolean("firstrun", true)) { + finishAffinity() + } else { + isEnabled = false + onBackPressedDispatcher.onBackPressed() + isEnabled = true + } + } + } + }) } public override fun onDestroy() { @@ -57,18 +74,6 @@ class WelcomeActivity : BaseActivity() { super.onDestroy() } - override fun onBackPressed() { - if (binding!!.welcomePager.currentItem != 0) { - binding!!.welcomePager.setCurrentItem(binding!!.welcomePager.currentItem - 1, true) - } else { - if (defaultKvStore.getBoolean("firstrun", true)) { - finishAffinity() - } else { - super.onBackPressed() - } - } - } - fun finishTutorial() { defaultKvStore.putBoolean("firstrun", false) finish() diff --git a/app/src/main/java/fr/free/nrw/commons/auth/SignupActivity.kt b/app/src/main/java/fr/free/nrw/commons/auth/SignupActivity.kt index 22f557bcdce..3dd781cd75d 100644 --- a/app/src/main/java/fr/free/nrw/commons/auth/SignupActivity.kt +++ b/app/src/main/java/fr/free/nrw/commons/auth/SignupActivity.kt @@ -7,6 +7,7 @@ import android.os.Bundle import android.webkit.WebView import android.webkit.WebViewClient import android.widget.Toast +import androidx.activity.OnBackPressedCallback import fr.free.nrw.commons.BuildConfig import fr.free.nrw.commons.R import fr.free.nrw.commons.theme.BaseActivity @@ -31,14 +32,18 @@ class SignupActivity : BaseActivity() { settings.javaScriptEnabled = true loadUrl(BuildConfig.SIGNUP_LANDING_URL) } - } - override fun onBackPressed() { - if (webView!!.canGoBack()) { - webView!!.goBack() - } else { - super.onBackPressed() - } + onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + if (webView!!.canGoBack()) { + webView!!.goBack() + } else { + isEnabled = false + onBackPressedDispatcher.onBackPressed() + isEnabled = true + } + } + }) } /** diff --git a/app/src/main/java/fr/free/nrw/commons/category/CategoryDetailsActivity.kt b/app/src/main/java/fr/free/nrw/commons/category/CategoryDetailsActivity.kt index fefe462a9f8..6f33070f760 100644 --- a/app/src/main/java/fr/free/nrw/commons/category/CategoryDetailsActivity.kt +++ b/app/src/main/java/fr/free/nrw/commons/category/CategoryDetailsActivity.kt @@ -7,6 +7,7 @@ import android.os.Bundle import android.view.Menu import android.view.MenuItem import android.view.View +import androidx.activity.OnBackPressedCallback import androidx.activity.viewModels import androidx.fragment.app.FragmentManager import androidx.lifecycle.Lifecycle @@ -78,6 +79,18 @@ class CategoryDetailsActivity : BaseActivity(), } } + onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + if (supportFragmentManager.backStackEntryCount == 1) { + binding.tabLayout.visibility = View.VISIBLE + binding.viewPager.visibility = View.VISIBLE + binding.mediaContainer.visibility = View.GONE + } + isEnabled = false + onBackPressedDispatcher.onBackPressed() + isEnabled = true + } + }) } /** @@ -181,7 +194,7 @@ class CategoryDetailsActivity : BaseActivity(), */ override fun refreshNominatedMedia(index: Int) { if (supportFragmentManager.backStackEntryCount == 1) { - onBackPressed() + onBackPressedDispatcher.onBackPressed() onMediaClicked(index) } } @@ -215,7 +228,7 @@ class CategoryDetailsActivity : BaseActivity(), } android.R.id.home -> { - onBackPressed() + onBackPressedDispatcher.onBackPressed() true } else -> super.onOptionsItemSelected(item) @@ -238,23 +251,6 @@ class CategoryDetailsActivity : BaseActivity(), return super.onPrepareOptionsMenu(menu) } - /** - * This method is called on backPressed of anyFragment in the activity. - * If condition is called when mediaDetailFragment is opened. - */ - @Deprecated("This method has been deprecated in favor of using the" + - "{@link OnBackPressedDispatcher} via {@link #getOnBackPressedDispatcher()}." + - "The OnBackPressedDispatcher controls how back button events are dispatched" + - "to one or more {@link OnBackPressedCallback} objects.") - override fun onBackPressed() { - if (supportFragmentManager.backStackEntryCount == 1) { - binding.tabLayout.visibility = View.VISIBLE - binding.viewPager.visibility = View.VISIBLE - binding.mediaContainer.visibility = View.GONE - } - super.onBackPressed() - } - /** * This method is called on success of API call for Images inside a category. * The viewpager will notified that number of items have changed. diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/MainActivity.kt b/app/src/main/java/fr/free/nrw/commons/contributions/MainActivity.kt index 923fa31a93e..19a40cc87ff 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/MainActivity.kt +++ b/app/src/main/java/fr/free/nrw/commons/contributions/MainActivity.kt @@ -11,6 +11,7 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import androidx.work.ExistingWorkPolicy import com.google.android.material.bottomnavigation.BottomNavigationView +import androidx.activity.OnBackPressedCallback import fr.free.nrw.commons.R import fr.free.nrw.commons.auth.SessionManager import fr.free.nrw.commons.bookmarks.BookmarkFragment @@ -104,7 +105,7 @@ class MainActivity : BaseActivity(), FragmentManager.OnBackStackChangedListener return false } } else { - onBackPressed() + onBackPressedDispatcher.onBackPressed() showTabs() } return true @@ -156,6 +157,52 @@ after opening the app. checkAndResumeStuckUploads() } + + onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + when (activeFragment) { + ActiveFragment.CONTRIBUTIONS -> { + // Means that contribution fragment is visible + if (contributionsFragment?.backButtonClicked() != true) { + isEnabled = false + onBackPressedDispatcher.onBackPressed() + isEnabled = true + } + } + ActiveFragment.NEARBY -> { + // Means that nearby fragment is visible + if (nearbyParentFragment?.backButtonClicked() != true) { + nearbyParentFragment?.let { + supportFragmentManager.beginTransaction().remove(it).commit() + } + setSelectedItemId(NavTab.CONTRIBUTIONS.code()) + } + } + ActiveFragment.EXPLORE -> { + // Explore Fragment is visible + if(exploreFragment?.onBackPressed() != true) { + if (applicationKvStore?.getBoolean("login_skipped") == true) { + isEnabled = false + onBackPressedDispatcher.onBackPressed() + isEnabled = true + } else { + setSelectedItemId(NavTab.CONTRIBUTIONS.code()) + } + } + } + ActiveFragment.BOOKMARK -> { + // Means that bookmark fragment is visible + bookmarkFragment?.onBackPressed() + setSelectedItemId(NavTab.CONTRIBUTIONS.code()) + } + else -> { + isEnabled = false + onBackPressedDispatcher.onBackPressed() + isEnabled = true + } + } + } + }) } fun setSelectedItemId(id: Int) { @@ -374,45 +421,6 @@ after opening the app. } } - override fun onBackPressed() { - when (activeFragment) { - ActiveFragment.CONTRIBUTIONS -> { - // Means that contribution fragment is visible - if (contributionsFragment?.backButtonClicked() != true) { //If this one does not want to handle - // the back press, let the activity do so - super.onBackPressed() - } - } - ActiveFragment.NEARBY -> { - // Means that nearby fragment is visible - if (nearbyParentFragment?.backButtonClicked() != true) { - nearbyParentFragment?.let { - supportFragmentManager.beginTransaction().remove(it).commit() - } - setSelectedItemId(NavTab.CONTRIBUTIONS.code()) - } - } - ActiveFragment.EXPLORE -> { - // Explore Fragment is visible - if (exploreFragment?.onBackPressed() != true) { - if (applicationKvStore?.getBoolean("login_skipped") == true) { - super.onBackPressed() - } else { - setSelectedItemId(NavTab.CONTRIBUTIONS.code()) - } - } - } - ActiveFragment.BOOKMARK -> { - // Means that bookmark fragment is visible - bookmarkFragment?.onBackPressed() - setSelectedItemId(NavTab.CONTRIBUTIONS.code()) - } - else -> { - super.onBackPressed() - } - } - } - override fun onBackStackChanged() { //initBackButton(); } diff --git a/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/CustomSelectorActivity.kt b/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/CustomSelectorActivity.kt index 1266a11f957..9357ed8509f 100644 --- a/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/CustomSelectorActivity.kt +++ b/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/CustomSelectorActivity.kt @@ -14,6 +14,7 @@ import android.widget.Button import android.widget.ImageButton import android.widget.PopupMenu import android.widget.TextView +import androidx.activity.OnBackPressedCallback import androidx.activity.result.ActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult @@ -232,6 +233,23 @@ class CustomSelectorActivity : val lastItemId: Long = prefs.getLong(ITEM_ID, 0) lastOpenFolderName?.let { onFolderClick(lastOpenFolderId, it, lastItemId) } } + + onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + isEnabled = false + onBackPressedDispatcher.onBackPressed() + isEnabled = true + val fragment = supportFragmentManager.findFragmentById(R.id.fragment_container) + if (fragment != null && fragment is FolderFragment) { + isImageFragmentOpen = false + changeTitle(getString(R.string.custom_selector_title), 0) + } + + //hide overflow menu when not in folder + showOverflowMenu = false + setUpToolbar() + } + }) } override fun onRequestPermissionsResult( @@ -450,7 +468,7 @@ class CustomSelectorActivity : */ private fun setUpToolbar() { val back: ImageButton = findViewById(R.id.back) - back.setOnClickListener { onBackPressed() } + back.setOnClickListener { onBackPressedDispatcher.onBackPressed() } val limitError: ImageButton = findViewById(R.id.image_limit_error) limitError.visibility = View.INVISIBLE @@ -678,23 +696,6 @@ class CustomSelectorActivity : finish() } - /** - * Back pressed. - * Change toolbar title. - */ - override fun onBackPressed() { - super.onBackPressed() - val fragment = supportFragmentManager.findFragmentById(R.id.fragment_container) - if (fragment != null && fragment is FolderFragment) { - isImageFragmentOpen = false - changeTitle(getString(R.string.custom_selector_title), 0) - } - - //hide overflow menu when not in folder - showOverflowMenu = false - setUpToolbar() - } - /** * Displays a dialog explaining the upload limit warning. */ diff --git a/app/src/main/java/fr/free/nrw/commons/explore/SearchActivity.kt b/app/src/main/java/fr/free/nrw/commons/explore/SearchActivity.kt index 0d7dfd21803..2cf355b825f 100644 --- a/app/src/main/java/fr/free/nrw/commons/explore/SearchActivity.kt +++ b/app/src/main/java/fr/free/nrw/commons/explore/SearchActivity.kt @@ -6,6 +6,7 @@ import android.view.View import androidx.fragment.app.FragmentManager import com.jakewharton.rxbinding2.view.RxView import com.jakewharton.rxbinding2.widget.RxSearchView +import androidx.activity.OnBackPressedCallback import fr.free.nrw.commons.Media import fr.free.nrw.commons.R import fr.free.nrw.commons.ViewPagerAdapter @@ -55,7 +56,7 @@ class SearchActivity : BaseActivity(), MediaDetailProvider, CategoryImagesCallba title = getString(R.string.title_activity_search) setSupportActionBar(binding!!.toolbarSearch) supportActionBar!!.setDisplayHomeAsUpEnabled(true) - binding!!.toolbarSearch.setNavigationOnClickListener { onBackPressed() } + binding!!.toolbarSearch.setNavigationOnClickListener { onBackPressedDispatcher.onBackPressed() } supportFragmentManager = getSupportFragmentManager() setSearchHistoryFragment() viewPagerAdapter = ViewPagerAdapter(this, getSupportFragmentManager()) @@ -66,6 +67,33 @@ class SearchActivity : BaseActivity(), MediaDetailProvider, CategoryImagesCallba binding!!.searchBox.queryHint = getString(R.string.search_commons) binding!!.searchBox.onActionViewExpanded() binding!!.searchBox.clearFocus() + + onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + //Remove the backstack entry that gets added when share button is clicked + //fixing:https://github.com/commons-app/apps-android-commons/issues/2296 + if (supportFragmentManager!!.backStackEntryCount == 2) { + supportFragmentManager!! + .beginTransaction() + .remove(mediaDetails!!) + .commit() + supportFragmentManager!!.popBackStack() + supportFragmentManager!!.executePendingTransactions() + } + if (supportFragmentManager!!.backStackEntryCount == 1) { + // back to search so show search toolbar and hide navigation toolbar + binding!!.searchBox.visibility = View.VISIBLE //set the searchview + binding!!.tabLayout.visibility = View.VISIBLE + binding!!.viewPager.visibility = View.VISIBLE + binding!!.mediaContainer.visibility = View.GONE + } else { + binding!!.toolbarSearch.visibility = View.GONE + } + isEnabled = false + onBackPressedDispatcher.onBackPressed() + isEnabled = true + } + }) } /** @@ -153,7 +181,7 @@ class SearchActivity : BaseActivity(), MediaDetailProvider, CategoryImagesCallba */ override fun refreshNominatedMedia(index: Int) { if (getSupportFragmentManager().backStackEntryCount == 1) { - onBackPressed() + onBackPressedDispatcher.onBackPressed() onMediaClicked(index) } } @@ -202,38 +230,11 @@ class SearchActivity : BaseActivity(), MediaDetailProvider, CategoryImagesCallba //FIXME: Temporary fix for screen rotation inside media details. If we don't call onBackPressed then fragment stack is increasing every time. //FIXME: Similar issue like this https://github.com/commons-app/apps-android-commons/issues/894 // This is called on screen rotation when user is inside media details. Ideally it should show Media Details but since we are not saving the state now. We are throwing the user to search screen otherwise the app was crashing. - onBackPressed() + onBackPressedDispatcher.onBackPressed() } super.onResume() } - /** - * This method is called on backPressed of anyFragment in the activity. - * If condition is called when mediaDetailFragment is opened. - */ - override fun onBackPressed() { - //Remove the backstack entry that gets added when share button is clicked - //fixing:https://github.com/commons-app/apps-android-commons/issues/2296 - if (getSupportFragmentManager().backStackEntryCount == 2) { - supportFragmentManager!! - .beginTransaction() - .remove(mediaDetails!!) - .commit() - supportFragmentManager!!.popBackStack() - supportFragmentManager!!.executePendingTransactions() - } - if (getSupportFragmentManager().backStackEntryCount == 1) { - // back to search so show search toolbar and hide navigation toolbar - binding!!.searchBox.visibility = View.VISIBLE //set the searchview - binding!!.tabLayout.visibility = View.VISIBLE - binding!!.viewPager.visibility = View.VISIBLE - binding!!.mediaContainer.visibility = View.GONE - } else { - binding!!.toolbarSearch.visibility = View.GONE - } - super.onBackPressed() - } - /** * This method is called on click of a recent search to update query in SearchView. * @param query Recent Search Query diff --git a/app/src/main/java/fr/free/nrw/commons/explore/depictions/WikidataItemDetailsActivity.kt b/app/src/main/java/fr/free/nrw/commons/explore/depictions/WikidataItemDetailsActivity.kt index d025fdfe102..42e0747890f 100644 --- a/app/src/main/java/fr/free/nrw/commons/explore/depictions/WikidataItemDetailsActivity.kt +++ b/app/src/main/java/fr/free/nrw/commons/explore/depictions/WikidataItemDetailsActivity.kt @@ -7,6 +7,7 @@ import android.os.Bundle import android.view.Menu import android.view.MenuItem import android.view.View +import androidx.activity.OnBackPressedCallback import androidx.core.os.bundleOf import androidx.fragment.app.FragmentManager import com.google.android.material.snackbar.Snackbar @@ -69,6 +70,19 @@ class WikidataItemDetailsActivity : BaseActivity(), MediaDetailProvider, Categor supportActionBar!!.setDisplayHomeAsUpEnabled(true) setTabs() setPageTitle() + + onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + if (supportFragmentManager!!.backStackEntryCount == 1) { + binding!!.tabLayout.visibility = View.VISIBLE + binding!!.viewPager.visibility = View.VISIBLE + binding!!.mediaContainer.visibility = View.GONE + } + isEnabled = false + onBackPressedDispatcher.onBackPressed() + isEnabled = true + } + }) } /** @@ -151,19 +165,6 @@ class WikidataItemDetailsActivity : BaseActivity(), MediaDetailProvider, Categor return depictionImagesListFragment!!.getMediaAtPosition(i) } - /** - * This method is called on backPressed of anyFragment in the activity. - * If condition is called when mediaDetailFragment is opened. - */ - override fun onBackPressed() { - if (supportFragmentManager!!.backStackEntryCount == 1) { - binding!!.tabLayout.visibility = View.VISIBLE - binding!!.viewPager.visibility = View.VISIBLE - binding!!.mediaContainer.visibility = View.GONE - } - super.onBackPressed() - } - /** * This method is called on from getCount of MediaDetailPagerFragment * The viewpager will contain same number of media items as that of media elements in adapter. @@ -180,7 +181,7 @@ class WikidataItemDetailsActivity : BaseActivity(), MediaDetailProvider, Categor */ override fun refreshNominatedMedia(index: Int) { if (getSupportFragmentManager().backStackEntryCount == 1) { - onBackPressed() + onBackPressedDispatcher.onBackPressed() onMediaClicked(index) } } @@ -257,7 +258,7 @@ class WikidataItemDetailsActivity : BaseActivity(), MediaDetailProvider, Categor } android.R.id.home -> { - onBackPressed() + onBackPressedDispatcher.onBackPressed() return true } diff --git a/app/src/main/java/fr/free/nrw/commons/explore/media/PageableMediaFragment.kt b/app/src/main/java/fr/free/nrw/commons/explore/media/PageableMediaFragment.kt index e7895f68343..701cf8514f3 100644 --- a/app/src/main/java/fr/free/nrw/commons/explore/media/PageableMediaFragment.kt +++ b/app/src/main/java/fr/free/nrw/commons/explore/media/PageableMediaFragment.kt @@ -71,7 +71,7 @@ abstract class PageableMediaFragment : * @param index item position that has been nominated */ override fun refreshNominatedMedia(index: Int) { - activity?.onBackPressed() + activity?.onBackPressedDispatcher?.onBackPressed() categoryImagesCallback.onMediaClicked(index) } } diff --git a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.kt b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.kt index 0bf51a7f065..2db1d2ea530 100644 --- a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.kt +++ b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.kt @@ -61,6 +61,7 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import androidx.activity.OnBackPressedCallback import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentTransaction import androidx.fragment.app.viewModels @@ -137,6 +138,7 @@ import java.util.regex.Matcher import java.util.regex.Pattern import javax.inject.Inject import javax.inject.Named +import androidx.core.view.isVisible class MediaDetailFragment : CommonsDaggerSupportFragment(), CategoryEditHelper.Callback { private var editable: Boolean = false @@ -193,6 +195,12 @@ class MediaDetailFragment : CommonsDaggerSupportFragment(), CategoryEditHelper.C private val viewModel: MediaDetailViewModel by viewModels { mediaDetailViewModelFactory } + private val onBackPressedCallback = object : OnBackPressedCallback(false) { + override fun handleOnBackPressed() { + binding.dummyCaptionDescriptionContainer.visibility = View.GONE + } + } + private var initialListTop: Int = 0 private var _binding: FragmentMediaDetailBinding? = null @@ -336,8 +344,6 @@ class MediaDetailFragment : CommonsDaggerSupportFragment(), CategoryEditHelper.C binding.coordinateEdit.visibility = View.GONE } - handleBackEvent(view) - //set onCLick listeners binding.mediaDetailLicense.setOnClickListener { onMediaDetailLicenceClicked() } binding.mediaDetailCoordinates.setOnClickListener { onMediaDetailCoordinatesClicked() } @@ -802,6 +808,7 @@ class MediaDetailFragment : CommonsDaggerSupportFragment(), CategoryEditHelper.C override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, onBackPressedCallback) if (activity is MainActivity) { //explicitly hides the tabs when the media details screen is opened. (activity as MainActivity).hideTabs() @@ -1974,9 +1981,11 @@ class MediaDetailFragment : CommonsDaggerSupportFragment(), CategoryEditHelper.C fun showCaptionAndDescription() { if (binding.dummyCaptionDescriptionContainer.visibility == View.GONE) { binding.dummyCaptionDescriptionContainer.visibility = View.VISIBLE + onBackPressedCallback.isEnabled = true setUpCaptionAndDescriptionLayout() } else { binding.dummyCaptionDescriptionContainer.visibility = View.GONE + onBackPressedCallback.isEnabled = false } } @@ -2048,26 +2057,6 @@ class MediaDetailFragment : CommonsDaggerSupportFragment(), CategoryEditHelper.C binding.showCaptionsBinding.pbCircular.visibility = View.GONE } - /** - * Handle back event when fragment when showCaptionAndDescriptionContainer is visible - */ - private fun handleBackEvent(view: View) { - view.isFocusableInTouchMode = true - view.requestFocus() - view.setOnKeyListener(object : View.OnKeyListener { - override fun onKey(view: View, keycode: Int, keyEvent: KeyEvent): Boolean { - if (keycode == KeyEvent.KEYCODE_BACK) { - if (binding.dummyCaptionDescriptionContainer.visibility == View.VISIBLE) { - binding.dummyCaptionDescriptionContainer.visibility = - View.GONE - return true - } - } - return false - } - }) - } - interface Callback { fun nominatingForDeletion(index: Int) diff --git a/app/src/main/java/fr/free/nrw/commons/media/ZoomableActivity.kt b/app/src/main/java/fr/free/nrw/commons/media/ZoomableActivity.kt index dc6e2377844..7aa14ffaa86 100644 --- a/app/src/main/java/fr/free/nrw/commons/media/ZoomableActivity.kt +++ b/app/src/main/java/fr/free/nrw/commons/media/ZoomableActivity.kt @@ -11,6 +11,7 @@ import android.view.View import android.view.Window import android.widget.Button import android.widget.Toast +import androidx.activity.OnBackPressedCallback import androidx.core.view.WindowCompat import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsControllerCompat @@ -144,8 +145,27 @@ class ZoomableActivity : BaseActivity() { binding.topBar.applyEdgeToEdgeTopPaddingInsets(WindowInsetsCompat.Type.statusBars()) binding.btnBack.setOnClickListener { - onBackPressed() + onBackPressedDispatcher.onBackPressed() } + + onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + if (!images.isNullOrEmpty()) { + val returnIntent = Intent() + returnIntent.putParcelableArrayListExtra( + CustomSelectorConstants.NEW_SELECTED_IMAGES, + selectedImages, + ) + returnIntent.putExtra(SHOULD_REFRESH, shouldRefresh) + setResult(Activity.RESULT_OK, returnIntent) + finish() + } else { + isEnabled = false + onBackPressedDispatcher.onBackPressed() + isEnabled = true + } + } + }) prefs = applicationContext.getSharedPreferences( ImageHelper.CUSTOM_SELECTOR_PREFERENCE_KEY, @@ -720,22 +740,6 @@ class ZoomableActivity : BaseActivity() { ) } - /** - * Send selected images in fragment - */ - override fun onBackPressed() { - if (!images.isNullOrEmpty()) { - val returnIntent = Intent() - returnIntent.putParcelableArrayListExtra( - CustomSelectorConstants.NEW_SELECTED_IMAGES, - selectedImages, - ) - returnIntent.putExtra(SHOULD_REFRESH, shouldRefresh) - setResult(Activity.RESULT_OK, returnIntent) - finish() - } - super.onBackPressed() - } override fun onDestroy() { scope.cancel() diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/WikidataFeedback.kt b/app/src/main/java/fr/free/nrw/commons/nearby/WikidataFeedback.kt index cce3a37e0db..cd918f36142 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/WikidataFeedback.kt +++ b/app/src/main/java/fr/free/nrw/commons/nearby/WikidataFeedback.kt @@ -118,7 +118,7 @@ class WikidataFeedback : BaseActivity() { } override fun onSupportNavigateUp(): Boolean { - onBackPressed() + onBackPressedDispatcher.onBackPressed() return true } } \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/notification/NotificationActivity.kt b/app/src/main/java/fr/free/nrw/commons/notification/NotificationActivity.kt index 4a43bf47068..f91d6a27977 100644 --- a/app/src/main/java/fr/free/nrw/commons/notification/NotificationActivity.kt +++ b/app/src/main/java/fr/free/nrw/commons/notification/NotificationActivity.kt @@ -73,7 +73,7 @@ class NotificationActivity : BaseActivity() { } override fun onSupportNavigateUp(): Boolean { - onBackPressed() + onBackPressedDispatcher.onBackPressed() return true } @@ -193,7 +193,7 @@ class NotificationActivity : BaseActivity() { if (item.title == getString(R.string.menu_option_read)) { startYourself(this, "read") } else if (item.title == getString(R.string.menu_option_unread)) { - onBackPressed() + onBackPressedDispatcher.onBackPressed() } true } diff --git a/app/src/main/java/fr/free/nrw/commons/profile/ProfileActivity.kt b/app/src/main/java/fr/free/nrw/commons/profile/ProfileActivity.kt index 8567d37ae2c..81f4d338bf4 100644 --- a/app/src/main/java/fr/free/nrw/commons/profile/ProfileActivity.kt +++ b/app/src/main/java/fr/free/nrw/commons/profile/ProfileActivity.kt @@ -10,6 +10,7 @@ import android.view.MenuItem import android.view.View import android.widget.ImageView import android.widget.TextView +import androidx.activity.OnBackPressedCallback import androidx.core.content.FileProvider import androidx.core.os.bundleOf import androidx.fragment.app.Fragment @@ -79,10 +80,23 @@ class ProfileActivity : BaseActivity() { binding.viewPager.adapter = viewPagerAdapter binding.tabLayout.setupWithViewPager(binding.viewPager) setTabs() + + onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + if (contributionsFragment?.mediaDetailPagerFragment?.isVisible == true) { + contributionsFragment?.backButtonClicked() + binding.tabLayout.visibility = View.VISIBLE + } else { + isEnabled = false + onBackPressedDispatcher.onBackPressed() + isEnabled = true + } + } + }) } override fun onSupportNavigateUp(): Boolean { - onBackPressed() + onBackPressedDispatcher.onBackPressed() return true } @@ -187,15 +201,6 @@ class ProfileActivity : BaseActivity() { outState.putBoolean(KEY_SHOULD_SHOW_CONTRIBUTIONS, shouldShowContributions) } - override fun onBackPressed() { - if (contributionsFragment?.mediaDetailPagerFragment?.isVisible == true) { - contributionsFragment?.backButtonClicked() - binding.tabLayout.visibility = View.VISIBLE - } else { - super.onBackPressed() - } - } - fun setTabLayoutVisibility(isVisible: Boolean) { binding.tabLayout.visibility = if (isVisible) View.VISIBLE else View.GONE } diff --git a/app/src/main/java/fr/free/nrw/commons/quiz/QuizActivity.kt b/app/src/main/java/fr/free/nrw/commons/quiz/QuizActivity.kt index 11fd1e6a631..0c203212a18 100644 --- a/app/src/main/java/fr/free/nrw/commons/quiz/QuizActivity.kt +++ b/app/src/main/java/fr/free/nrw/commons/quiz/QuizActivity.kt @@ -3,6 +3,7 @@ package fr.free.nrw.commons.quiz import android.annotation.SuppressLint import android.content.Intent import android.os.Bundle +import androidx.activity.OnBackPressedCallback import androidx.activity.enableEdgeToEdge import androidx.appcompat.app.AlertDialog @@ -51,6 +52,24 @@ class QuizActivity : AppCompatActivity() { setSupportActionBar(binding.toolbar.toolbar) binding.nextButton.setOnClickListener { notKnowAnswer() } displayQuestion() + + onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + AlertDialog.Builder(this@QuizActivity) + .setTitle(getString(R.string.warning)) + .setMessage(getString(R.string.quiz_back_button)) + .setCancelable(false) + .setPositiveButton(R.string.continue_message) { dialog, _ -> + val intent = Intent(this@QuizActivity, QuizResultActivity::class.java) + dialog.dismiss() + intent.putExtra("QuizResult", score) + startActivity(intent) + } + .setNegativeButton("Cancel") { dialogInterface, _ -> dialogInterface.dismiss() } + .create() + .show() + } + }) } /** @@ -66,25 +85,6 @@ class QuizActivity : AppCompatActivity() { customAlert("Information", quiz[questionIndex].answerMessage) } - /** - * To give warning before ending quiz - */ - override fun onBackPressed() { - AlertDialog.Builder(this) - .setTitle(getString(R.string.warning)) - .setMessage(getString(R.string.quiz_back_button)) - .setCancelable(false) - .setPositiveButton(R.string.continue_message) { dialog, _ -> - val intent = Intent(this, QuizResultActivity::class.java) - dialog.dismiss() - intent.putExtra("QuizResult", score) - startActivity(intent) - } - .setNegativeButton("Cancel") { dialogInterface, _ -> dialogInterface.dismiss() } - .create() - .show() - } - /** * To display the question */ diff --git a/app/src/main/java/fr/free/nrw/commons/quiz/QuizResultActivity.kt b/app/src/main/java/fr/free/nrw/commons/quiz/QuizResultActivity.kt index 15884146d2e..670bac71d46 100644 --- a/app/src/main/java/fr/free/nrw/commons/quiz/QuizResultActivity.kt +++ b/app/src/main/java/fr/free/nrw/commons/quiz/QuizResultActivity.kt @@ -12,6 +12,7 @@ import android.view.MenuItem import android.view.View import android.widget.ImageView import android.widget.TextView +import androidx.activity.OnBackPressedCallback import androidx.activity.enableEdgeToEdge import androidx.appcompat.app.AlertDialog @@ -59,8 +60,20 @@ class QuizResultActivity : AppCompatActivity() { this, MainActivity::class.java, Intent.FLAG_ACTIVITY_CLEAR_TOP, Intent.FLAG_ACTIVITY_SINGLE_TOP ) - super.onBackPressed() + onBackPressedDispatcher.onBackPressed() } + + onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + startActivityWithFlags( + this@QuizResultActivity, MainActivity::class.java, + Intent.FLAG_ACTIVITY_CLEAR_TOP, Intent.FLAG_ACTIVITY_SINGLE_TOP + ) + isEnabled = false + onBackPressedDispatcher.onBackPressed() + isEnabled = true + } + }) } override fun onDestroy() { @@ -91,14 +104,6 @@ class QuizResultActivity : AppCompatActivity() { ) } - override fun onBackPressed() { - startActivityWithFlags( - this, MainActivity::class.java, - Intent.FLAG_ACTIVITY_CLEAR_TOP, Intent.FLAG_ACTIVITY_SINGLE_TOP - ) - super.onBackPressed() - } - /** * Starts an activity using the provided context, target class, and intent flags. * diff --git a/app/src/main/java/fr/free/nrw/commons/review/ReviewActivity.kt b/app/src/main/java/fr/free/nrw/commons/review/ReviewActivity.kt index dccb77af1eb..2787aafd9d8 100644 --- a/app/src/main/java/fr/free/nrw/commons/review/ReviewActivity.kt +++ b/app/src/main/java/fr/free/nrw/commons/review/ReviewActivity.kt @@ -9,6 +9,7 @@ import android.view.Menu import android.view.MenuItem import android.view.MotionEvent import android.view.View +import androidx.activity.OnBackPressedCallback import fr.free.nrw.commons.Media import fr.free.nrw.commons.R import fr.free.nrw.commons.auth.getUserName @@ -23,6 +24,7 @@ import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.schedulers.Schedulers import java.util.Locale import javax.inject.Inject +import androidx.core.view.isVisible class ReviewActivity : BaseActivity() { @@ -117,10 +119,22 @@ class ReviewActivity : BaseActivity() { false } } + + onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + if (binding.mediaDetailContainer.isVisible) { + binding.mediaDetailContainer.visibility = View.GONE + binding.reviewActivityContainer.visibility = View.VISIBLE + } + isEnabled = false + onBackPressedDispatcher.onBackPressed() + isEnabled = true + } + }) } override fun onSupportNavigateUp(): Boolean { - onBackPressed() + onBackPressedDispatcher.onBackPressed() return true } @@ -303,22 +317,6 @@ class ReviewActivity : BaseActivity() { } } - /** - * handle the back pressed event of this activity - * this function call every time when back button is pressed - */ - @Deprecated("This method has been deprecated in favor of using the" + - "{@link OnBackPressedDispatcher} via {@link #getOnBackPressedDispatcher()}." + - "The OnBackPressedDispatcher controls how back button events are dispatched" + - "to one or more {@link OnBackPressedCallback} objects.") - override fun onBackPressed() { - if (binding.mediaDetailContainer.visibility == View.VISIBLE) { - binding.mediaDetailContainer.visibility = View.GONE - binding.reviewActivityContainer.visibility = View.VISIBLE - } - super.onBackPressed() - } - /** * set up media detail fragment after orientation change */ diff --git a/app/src/main/java/fr/free/nrw/commons/settings/SettingsActivity.kt b/app/src/main/java/fr/free/nrw/commons/settings/SettingsActivity.kt index 233e688f4e9..922becd6bdf 100644 --- a/app/src/main/java/fr/free/nrw/commons/settings/SettingsActivity.kt +++ b/app/src/main/java/fr/free/nrw/commons/settings/SettingsActivity.kt @@ -43,7 +43,7 @@ class SettingsActivity : BaseActivity() { } override fun onSupportNavigateUp(): Boolean { - onBackPressed() + onBackPressedDispatcher.onBackPressed() return true } diff --git a/app/src/main/java/fr/free/nrw/commons/upload/UploadProgressActivity.kt b/app/src/main/java/fr/free/nrw/commons/upload/UploadProgressActivity.kt index 665f106e223..a8aa5c3ff70 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/UploadProgressActivity.kt +++ b/app/src/main/java/fr/free/nrw/commons/upload/UploadProgressActivity.kt @@ -92,7 +92,7 @@ class UploadProgressActivity : BaseActivity() { } override fun onSupportNavigateUp(): Boolean { - onBackPressed() + onBackPressedDispatcher.onBackPressed() return true } diff --git a/app/src/main/java/fr/free/nrw/commons/upload/categories/UploadCategoriesFragment.kt b/app/src/main/java/fr/free/nrw/commons/upload/categories/UploadCategoriesFragment.kt index ef4521431fb..85c0c59c45c 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/categories/UploadCategoriesFragment.kt +++ b/app/src/main/java/fr/free/nrw/commons/upload/categories/UploadCategoriesFragment.kt @@ -10,6 +10,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.Toast +import androidx.activity.OnBackPressedCallback import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity import androidx.recyclerview.widget.LinearLayoutManager @@ -65,6 +66,18 @@ class UploadCategoriesFragment : UploadBaseFragment(), CategoriesContract.View { private var binding: UploadCategoriesFragmentBinding? = null + private val onBackPressedCallback = object : OnBackPressedCallback(false) { + override fun handleOnBackPressed() { + if (media != null) { + binding?.etSearch?.clearFocus() + presenter?.clearPreviousSelection() + val mediaDetailFragment = checkNotNull(parentFragment as MediaDetailFragment?) + mediaDetailFragment.onResume() + goBackToPreviousScreen() + } + } + } + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? @@ -132,6 +145,7 @@ class UploadCategoriesFragment : UploadBaseFragment(), CategoriesContract.View { initRecyclerView() addTextChangeListenerToEtSearch() + requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, onBackPressedCallback) } private fun addTextChangeListenerToEtSearch() { @@ -359,42 +373,20 @@ class UploadCategoriesFragment : UploadBaseFragment(), CategoriesContract.View { super.onResume() if (media != null) { - binding?.etSearch?.setOnKeyListener { v: View?, keyCode: Int, event: KeyEvent? -> - if (keyCode == KeyEvent.KEYCODE_BACK) { - binding!!.etSearch.clearFocus() - presenter!!.clearPreviousSelection() - val mediaDetailFragment = - checkNotNull(parentFragment as MediaDetailFragment?) - mediaDetailFragment.onResume() - goBackToPreviousScreen() - return@setOnKeyListener true - } - false - } - - requireView().isFocusableInTouchMode = true - requireView().requestFocus() - requireView().setOnKeyListener { v: View?, keyCode: Int, event: KeyEvent -> - if (event.action == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) { - presenter!!.clearPreviousSelection() - val mediaDetailFragment = - checkNotNull(parentFragment as MediaDetailFragment?) - mediaDetailFragment.onResume() - goBackToPreviousScreen() - return@setOnKeyListener true - } - false - } - + onBackPressedCallback.isEnabled = true (requireActivity() as AppCompatActivity).supportActionBar?.hide() - if (parentFragment?.parentFragment?.parentFragment is ContributionsFragment) { ((parentFragment?.parentFragment?.parentFragment) as ContributionsFragment).binding?.cardViewNearby?.visibility = View.GONE } } } + override fun onPause() { + super.onPause() + onBackPressedCallback.isEnabled = false + } + /** * Shows the action bar while closing editing fragment */ diff --git a/app/src/main/java/fr/free/nrw/commons/upload/depicts/DepictsFragment.kt b/app/src/main/java/fr/free/nrw/commons/upload/depicts/DepictsFragment.kt index c92ac890dae..687764343c8 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/depicts/DepictsFragment.kt +++ b/app/src/main/java/fr/free/nrw/commons/upload/depicts/DepictsFragment.kt @@ -11,6 +11,7 @@ import android.view.View import android.view.ViewGroup import android.view.inputmethod.InputMethodManager import android.widget.Toast +import androidx.activity.OnBackPressedCallback import androidx.appcompat.app.AppCompatActivity import androidx.recyclerview.widget.LinearLayoutManager import com.jakewharton.rxbinding2.view.RxView @@ -84,6 +85,17 @@ class DepictsFragment : UploadBaseFragment(), DepictsContract.View { } } + private val onBackPressedCallback = object : OnBackPressedCallback(false) { + override fun handleOnBackPressed() { + if (media != null) { + binding.depictsSearch.clearFocus() + presenter.clearPreviousSelection() + updateDepicts() + goBackToPreviousScreen() + } + } + } + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? @@ -446,28 +458,7 @@ class DepictsFragment : UploadBaseFragment(), DepictsContract.View { super.onResume() if (media != null) { - binding.depictsSearch.setOnKeyListener { v: View?, keyCode: Int, event: KeyEvent? -> - if (keyCode == KeyEvent.KEYCODE_BACK) { - binding.depictsSearch.clearFocus() - presenter.clearPreviousSelection() - updateDepicts() - goBackToPreviousScreen() - return@setOnKeyListener true - } - false - } - - requireView().isFocusableInTouchMode = true - requireView().requestFocus() - requireView().setOnKeyListener { v: View?, keyCode: Int, event: KeyEvent -> - if (event.action == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) { - presenter.clearPreviousSelection() - updateDepicts() - goBackToPreviousScreen() - return@setOnKeyListener true - } - false - } + onBackPressedCallback.isEnabled = true (requireActivity() as AppCompatActivity).supportActionBar?.hide() @@ -477,6 +468,11 @@ class DepictsFragment : UploadBaseFragment(), DepictsContract.View { } } + override fun onPause() { + super.onPause() + onBackPressedCallback.isEnabled = false + } + /** * Shows the action bar while closing editing fragment */ diff --git a/app/src/test/kotlin/fr/free/nrw/commons/contributions/MainActivityUnitTests.kt b/app/src/test/kotlin/fr/free/nrw/commons/contributions/MainActivityUnitTests.kt index b3750c5f36e..0480d6139f2 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/contributions/MainActivityUnitTests.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/contributions/MainActivityUnitTests.kt @@ -159,7 +159,7 @@ class MainActivityUnitTests { @Test @Throws(Exception::class) fun testOnBackPressedCaseDefault() { - activity.onBackPressed() + activity.onBackPressedDispatcher.onBackPressed() } @Test diff --git a/app/src/test/kotlin/fr/free/nrw/commons/media/ZoomableActivityUnitTests.kt b/app/src/test/kotlin/fr/free/nrw/commons/media/ZoomableActivityUnitTests.kt index 848e0881aa5..6fca324cc12 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/media/ZoomableActivityUnitTests.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/media/ZoomableActivityUnitTests.kt @@ -133,9 +133,7 @@ class ZoomableActivityUnitTests { */ @Test fun testOnBackPressed() { - val func = activity.javaClass.getDeclaredMethod("onBackPressed") - func.isAccessible = true - func.invoke(activity) + activity.onBackPressedDispatcher.onBackPressed() } /** diff --git a/app/src/test/resources/robolectric.properties b/app/src/test/resources/robolectric.properties new file mode 100644 index 00000000000..8bfbb3c5552 --- /dev/null +++ b/app/src/test/resources/robolectric.properties @@ -0,0 +1 @@ +sdk=21 From 7472f66189188e4762c6bc4f59f304ce3b996734 Mon Sep 17 00:00:00 2001 From: VoidRaven Date: Sat, 25 Apr 2026 07:59:47 +0530 Subject: [PATCH 3/4] Merge branch 'main' into fix/self-upload-media-actions --- .../java/fr/free/nrw/commons/media/MediaDetailFragment.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.kt b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.kt index 2db1d2ea530..09b9b35faed 100644 --- a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.kt +++ b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.kt @@ -834,7 +834,7 @@ class MediaDetailFragment : CommonsDaggerSupportFragment(), CategoryEditHelper.C // Show author or uploader information for licensing compliance val authorName = media.getAttributedAuthor() val uploaderName = media.user - + when { !authorName.isNullOrEmpty() -> { // Show author if available @@ -2275,4 +2275,4 @@ fun FileUsagesContainer( } } } -} \ No newline at end of file +} From c6afe8e38415e24c128ce4b7bc15ba70092827d0 Mon Sep 17 00:00:00 2001 From: Kota-Jagadeesh Date: Sat, 25 Apr 2026 08:02:49 +0530 Subject: [PATCH 4/4] Merge branch 'main' into fix/self-upload-media-actions --- .../main/java/fr/free/nrw/commons/media/MediaDetailFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.kt b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.kt index 09b9b35faed..3f042e08d15 100644 --- a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.kt +++ b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.kt @@ -2275,4 +2275,4 @@ fun FileUsagesContainer( } } } -} +} \ No newline at end of file