diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 674a6473f3..32f2ee4154 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -18,12 +18,12 @@ if (isRunningOnTravisAndIsNotPRBuild) { android { namespace = "fr.free.nrw.commons" - compileSdk = 34 + compileSdk = 35 defaultConfig { applicationId = "fr.free.nrw.commons" minSdk = 21 - targetSdk = 34 + targetSdk = 35 versionCode = 1055 versionName = "5.6.1" diff --git a/app/src/main/java/fr/free/nrw/commons/AboutActivity.kt b/app/src/main/java/fr/free/nrw/commons/AboutActivity.kt index ebbb4097a0..865ad3ddb1 100644 --- a/app/src/main/java/fr/free/nrw/commons/AboutActivity.kt +++ b/app/src/main/java/fr/free/nrw/commons/AboutActivity.kt @@ -19,6 +19,7 @@ import fr.free.nrw.commons.utils.ConfigUtils.getVersionNameWithSha import fr.free.nrw.commons.utils.DialogUtil.showAlertDialog import java.util.Collections import androidx.core.net.toUri +import fr.free.nrw.commons.utils.applyEdgeToEdgeTopInsets import fr.free.nrw.commons.utils.handleWebUrl import fr.free.nrw.commons.utils.setUnderlinedText @@ -47,6 +48,7 @@ class AboutActivity : BaseActivity() { */ binding = ActivityAboutBinding.inflate(layoutInflater) val view: View = binding!!.root + applyEdgeToEdgeTopInsets(binding!!.toolbarLayout) setContentView(view) setSupportActionBar(binding!!.toolbarBinding.toolbar) diff --git a/app/src/main/java/fr/free/nrw/commons/WelcomeActivity.kt b/app/src/main/java/fr/free/nrw/commons/WelcomeActivity.kt index 439ed1e924..0882ba1176 100644 --- a/app/src/main/java/fr/free/nrw/commons/WelcomeActivity.kt +++ b/app/src/main/java/fr/free/nrw/commons/WelcomeActivity.kt @@ -9,6 +9,7 @@ import fr.free.nrw.commons.databinding.ActivityWelcomeBinding import fr.free.nrw.commons.databinding.PopupForCopyrightBinding import fr.free.nrw.commons.quiz.QuizActivity import fr.free.nrw.commons.theme.BaseActivity +import fr.free.nrw.commons.utils.applyEdgeToEdgeAllInsets import fr.free.nrw.commons.utils.ConfigUtils.isBetaFlavour class WelcomeActivity : BaseActivity() { @@ -23,6 +24,7 @@ class WelcomeActivity : BaseActivity() { public override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityWelcomeBinding.inflate(layoutInflater) + applyEdgeToEdgeAllInsets(binding!!.welcomePager.rootView) setContentView(binding!!.root) isQuiz = intent?.extras?.getBoolean("isQuiz", false) ?: false diff --git a/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.kt b/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.kt index 7a665197b3..025c101805 100644 --- a/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.kt +++ b/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.kt @@ -32,6 +32,7 @@ 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 import fr.free.nrw.commons.utils.ActivityUtils.startActivityWithFlags import fr.free.nrw.commons.utils.ConfigUtils.isBetaFlavour @@ -80,6 +81,7 @@ class LoginActivity : AccountAuthenticatorActivity() { delegate.onCreate(savedInstanceState) binding = ActivityLoginBinding.inflate(layoutInflater) + applyEdgeToEdgeAllInsets(binding!!.root) with(binding!!) { setContentView(root) 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 5b48ecd8f5..22f557bcdc 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 @@ -10,6 +10,7 @@ import android.widget.Toast import fr.free.nrw.commons.BuildConfig import fr.free.nrw.commons.R import fr.free.nrw.commons.theme.BaseActivity +import fr.free.nrw.commons.utils.applyEdgeToEdgeAllInsets import timber.log.Timber class SignupActivity : BaseActivity() { @@ -21,6 +22,7 @@ class SignupActivity : BaseActivity() { Timber.d("Signup Activity started") webView = WebView(this) + applyEdgeToEdgeAllInsets(webView!!) with(webView!!) { setContentView(this) webViewClient = MyWebViewClient() 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 c998f96ac4..fefe462a9f 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 @@ -23,6 +23,7 @@ import fr.free.nrw.commons.explore.categories.sub.SubCategoriesFragment import fr.free.nrw.commons.media.MediaDetailPagerFragment import fr.free.nrw.commons.media.MediaDetailProvider import fr.free.nrw.commons.theme.BaseActivity +import fr.free.nrw.commons.utils.applyEdgeToEdgeAllInsets import fr.free.nrw.commons.utils.handleWebUrl import fr.free.nrw.commons.wikidata.model.WikiSite import fr.free.nrw.commons.wikidata.model.page.PageTitle @@ -57,6 +58,7 @@ class CategoryDetailsActivity : BaseActivity(), binding = ActivityCategoryDetailsBinding.inflate(layoutInflater) val view = binding.root + applyEdgeToEdgeAllInsets(view) setContentView(view) supportFragmentManager = getSupportFragmentManager() viewPagerAdapter = ViewPagerAdapter(this, supportFragmentManager) 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 b9fa3e395f..5c2c44ab51 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 @@ -34,6 +34,7 @@ import fr.free.nrw.commons.quiz.QuizChecker import fr.free.nrw.commons.settings.SettingsFragment import fr.free.nrw.commons.startWelcome import fr.free.nrw.commons.theme.BaseActivity +import fr.free.nrw.commons.utils.applyEdgeToEdgeAllInsets import fr.free.nrw.commons.upload.UploadProgressActivity import fr.free.nrw.commons.upload.worker.WorkRequestHelper.Companion.makeOneTimeWorkRequest import fr.free.nrw.commons.utils.ViewUtilWrapper @@ -112,6 +113,7 @@ class MainActivity : BaseActivity(), FragmentManager.OnBackStackChangedListener public override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = MainBinding.inflate(layoutInflater) + applyEdgeToEdgeAllInsets(binding!!.root) setContentView(binding!!.root) setSupportActionBar(binding!!.toolbarBinding.toolbar) tabLayout = binding!!.fragmentMainNavTabLayout 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 7e7d7e4cda..2534b4aeb4 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 @@ -40,6 +40,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.content.ContextCompat +import androidx.core.view.ViewGroupCompat import androidx.lifecycle.ViewModelProvider import fr.free.nrw.commons.R import fr.free.nrw.commons.customselector.database.NotForUploadStatus @@ -56,6 +57,8 @@ import fr.free.nrw.commons.media.ZoomableActivity import fr.free.nrw.commons.theme.BaseActivity import fr.free.nrw.commons.upload.FileUtilsWrapper import fr.free.nrw.commons.utils.CustomSelectorUtils +import fr.free.nrw.commons.utils.applyEdgeToEdgeBottomPaddingInsets +import fr.free.nrw.commons.utils.applyEdgeToEdgeTopInsets import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -198,6 +201,9 @@ class CustomSelectorActivity : .fillMaxWidth(), ) } + ViewGroupCompat.installCompatInsetsDispatch(binding.root) + applyEdgeToEdgeTopInsets(toolbarBinding.toolbarLayout) + bottomSheetBinding.bottomLayout.applyEdgeToEdgeBottomPaddingInsets() val view = binding.root setContentView(view) diff --git a/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/FolderFragment.kt b/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/FolderFragment.kt index 6ca2b06e40..0c3c5bdd0e 100644 --- a/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/FolderFragment.kt +++ b/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/FolderFragment.kt @@ -18,6 +18,7 @@ import fr.free.nrw.commons.databinding.FragmentCustomSelectorBinding import fr.free.nrw.commons.di.CommonsDaggerSupportFragment import fr.free.nrw.commons.media.MediaClient import fr.free.nrw.commons.upload.FileProcessor +import fr.free.nrw.commons.utils.applyEdgeToEdgeBottomPaddingInsets import javax.inject.Inject /** @@ -99,6 +100,7 @@ class FolderFragment : CommonsDaggerSupportFragment() { selectorRV = binding?.selectorRv loader = binding?.loader with(binding?.selectorRv) { + this?.applyEdgeToEdgeBottomPaddingInsets() this?.layoutManager = gridLayoutManager this?.setHasFixedSize(true) this?.adapter = folderAdapter diff --git a/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/ImageFragment.kt b/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/ImageFragment.kt index 6e08e30f17..4f37106cc2 100644 --- a/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/ImageFragment.kt +++ b/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/ImageFragment.kt @@ -41,6 +41,7 @@ import fr.free.nrw.commons.media.MediaClient import fr.free.nrw.commons.theme.BaseActivity import fr.free.nrw.commons.upload.FileProcessor import fr.free.nrw.commons.upload.FileUtilsWrapper +import fr.free.nrw.commons.utils.applyEdgeToEdgeBottomPaddingInsets import io.reactivex.schedulers.Schedulers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow @@ -217,6 +218,7 @@ class ImageFragment : imageAdapter.setSingleSelection(singleSelection) gridLayoutManager = GridLayoutManager(context, getSpanCount()) with(binding?.selectorRv) { + this?.applyEdgeToEdgeBottomPaddingInsets() this?.layoutManager = gridLayoutManager this?.setHasFixedSize(true) this?.adapter = imageAdapter diff --git a/app/src/main/java/fr/free/nrw/commons/description/DescriptionEditActivity.kt b/app/src/main/java/fr/free/nrw/commons/description/DescriptionEditActivity.kt index 44cefe4d57..89d43845bc 100644 --- a/app/src/main/java/fr/free/nrw/commons/description/DescriptionEditActivity.kt +++ b/app/src/main/java/fr/free/nrw/commons/description/DescriptionEditActivity.kt @@ -7,6 +7,7 @@ import android.speech.RecognizerIntent import android.view.View import androidx.activity.result.ActivityResult import androidx.activity.result.contract.ActivityResultContracts +import androidx.core.view.WindowCompat import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import fr.free.nrw.commons.CommonsApplication @@ -20,9 +21,11 @@ import fr.free.nrw.commons.description.EditDescriptionConstants.WIKITEXT import fr.free.nrw.commons.recentlanguages.RecentLanguagesDao import fr.free.nrw.commons.settings.Prefs import fr.free.nrw.commons.theme.BaseActivity +import fr.free.nrw.commons.utils.applyEdgeToEdgeBottomInsets import fr.free.nrw.commons.upload.UploadMediaDetail import fr.free.nrw.commons.upload.UploadMediaDetailAdapter import fr.free.nrw.commons.utils.DialogUtil.showAlertDialog +import fr.free.nrw.commons.utils.applyEdgeToEdgeTopPaddingInsets import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.functions.Consumer import io.reactivex.schedulers.Schedulers @@ -87,6 +90,10 @@ class DescriptionEditActivity : super.onCreate(savedInstanceState) binding = ActivityDescriptionEditBinding.inflate(layoutInflater) + applyEdgeToEdgeBottomInsets(binding.btnEditSubmit) + WindowCompat.getInsetsController(window, window.decorView) + .isAppearanceLightStatusBars = false + binding.toolbar.applyEdgeToEdgeTopPaddingInsets() setContentView(binding.root) val bundle = intent.extras 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 4696ae8d41..32af67e950 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 @@ -24,6 +24,7 @@ import fr.free.nrw.commons.media.MediaDetailProvider import fr.free.nrw.commons.theme.BaseActivity import fr.free.nrw.commons.upload.structure.depictions.DepictModel import fr.free.nrw.commons.upload.structure.depictions.DepictedItem +import fr.free.nrw.commons.utils.applyEdgeToEdgeAllInsets import fr.free.nrw.commons.utils.handleWebUrl import fr.free.nrw.commons.wikidata.WikidataConstants import io.reactivex.android.schedulers.AndroidSchedulers @@ -55,6 +56,7 @@ class WikidataItemDetailsActivity : BaseActivity(), MediaDetailProvider, Categor super.onCreate(savedInstanceState) binding = ActivityWikidataItemDetailsBinding.inflate(layoutInflater) + applyEdgeToEdgeAllInsets(binding!!.root) setContentView(binding!!.root) supportFragmentManager = getSupportFragmentManager() viewPagerAdapter = ViewPagerAdapter(this, getSupportFragmentManager()) diff --git a/app/src/main/java/fr/free/nrw/commons/locationpicker/LocationPickerActivity.kt b/app/src/main/java/fr/free/nrw/commons/locationpicker/LocationPickerActivity.kt index a8b6ddf268..e4fedf2e42 100644 --- a/app/src/main/java/fr/free/nrw/commons/locationpicker/LocationPickerActivity.kt +++ b/app/src/main/java/fr/free/nrw/commons/locationpicker/LocationPickerActivity.kt @@ -25,6 +25,7 @@ import androidx.core.content.ContextCompat import androidx.core.content.IntentCompat import androidx.core.os.BundleCompat import androidx.core.text.HtmlCompat +import androidx.core.view.WindowCompat import com.google.android.material.floatingactionbutton.FloatingActionButton import fr.free.nrw.commons.CameraPosition import fr.free.nrw.commons.CommonsApplication @@ -44,6 +45,8 @@ import fr.free.nrw.commons.upload.mediaDetails.UploadMediaDetailFragment.Compani import fr.free.nrw.commons.upload.mediaDetails.UploadMediaDetailFragment.Companion.LAST_ZOOM import fr.free.nrw.commons.utils.DialogUtil import fr.free.nrw.commons.utils.MapUtils.ZOOM_LEVEL +import fr.free.nrw.commons.utils.applyEdgeToEdgeBottomInsets +import fr.free.nrw.commons.utils.applyEdgeToEdgeTopPaddingInsets import fr.free.nrw.commons.utils.handleGeoCoordinates import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.schedulers.Schedulers @@ -330,6 +333,9 @@ class LocationPickerActivity : BaseActivity(), LocationPermissionCallback { */ private fun getToolbarUI() { val toolbar: ConstraintLayout = findViewById(R.id.location_picker_toolbar) + WindowCompat.getInsetsController(window, window.decorView) + .isAppearanceLightStatusBars = false + toolbar.applyEdgeToEdgeTopPaddingInsets() largeToolbarText = findViewById(R.id.location_picker_toolbar_primary_text_view) smallToolbarText = findViewById(R.id.location_picker_toolbar_secondary_text_view) toolbar.setBackgroundColor(ContextCompat.getColor(this, R.color.primaryColor)) @@ -460,6 +466,7 @@ class LocationPickerActivity : BaseActivity(), LocationPermissionCallback { */ private fun addPlaceSelectedButton() { placeSelectedButton = findViewById(R.id.location_chosen_button) + applyEdgeToEdgeBottomInsets(placeSelectedButton) placeSelectedButton.setOnClickListener { placeSelected() } } 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 76975964b4..4a43bf4706 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 @@ -8,6 +8,7 @@ import android.os.Bundle import android.view.Menu import android.view.MenuItem import android.view.View +import androidx.core.view.ViewGroupCompat import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import com.google.android.material.snackbar.Snackbar @@ -19,8 +20,10 @@ import fr.free.nrw.commons.databinding.ActivityNotificationBinding import fr.free.nrw.commons.notification.models.Notification import fr.free.nrw.commons.notification.models.NotificationType import fr.free.nrw.commons.theme.BaseActivity +import fr.free.nrw.commons.utils.applyEdgeToEdgeTopInsets import fr.free.nrw.commons.utils.NetworkUtils import fr.free.nrw.commons.utils.ViewUtil +import fr.free.nrw.commons.utils.applyEdgeToEdgeBottomPaddingInsets import fr.free.nrw.commons.utils.handleWebUrl import io.reactivex.Observable import io.reactivex.android.schedulers.AndroidSchedulers @@ -56,6 +59,9 @@ class NotificationActivity : BaseActivity() { super.onCreate(savedInstanceState) isRead = intent.getStringExtra("title") == "read" binding = ActivityNotificationBinding.inflate(layoutInflater) + ViewGroupCompat.installCompatInsetsDispatch(binding.root) + applyEdgeToEdgeTopInsets(binding.toolbar.toolbar) + binding.listView.applyEdgeToEdgeBottomPaddingInsets() setContentView(binding.root) mNotificationWorkerFragment = supportFragmentManager.findFragmentByTag( tagNotificationWorkerFragment 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 d80be9ea24..c368d6cd4e 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 @@ -21,6 +21,7 @@ import fr.free.nrw.commons.databinding.ActivityProfileBinding import fr.free.nrw.commons.profile.achievements.AchievementsFragment import fr.free.nrw.commons.profile.leaderboard.LeaderboardFragment import fr.free.nrw.commons.theme.BaseActivity +import fr.free.nrw.commons.utils.applyEdgeToEdgeAllInsets import fr.free.nrw.commons.utils.DialogUtil import java.io.File import java.io.FileOutputStream @@ -61,6 +62,7 @@ class ProfileActivity : BaseActivity() { super.onCreate(savedInstanceState) binding = ActivityProfileBinding.inflate(layoutInflater) + applyEdgeToEdgeAllInsets(binding.root) setContentView(binding.root) setSupportActionBar(binding.toolbarBinding.toolbar) 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 e65b819e5a..11fd1e6a63 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,9 +3,11 @@ package fr.free.nrw.commons.quiz import android.annotation.SuppressLint import android.content.Intent import android.os.Bundle +import androidx.activity.enableEdgeToEdge import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity +import androidx.core.view.WindowCompat import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat import com.facebook.drawee.drawable.ProgressBarDrawable @@ -15,6 +17,7 @@ import fr.free.nrw.commons.databinding.ActivityQuizBinding import java.util.ArrayList import fr.free.nrw.commons.R +import fr.free.nrw.commons.utils.applyEdgeToEdgeAllInsets class QuizActivity : AppCompatActivity() { @@ -37,7 +40,11 @@ class QuizActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + enableEdgeToEdge() binding = ActivityQuizBinding.inflate(layoutInflater) + applyEdgeToEdgeAllInsets(binding.root) + WindowCompat.getInsetsController(window, window.decorView) + .isAppearanceLightStatusBars = true setContentView(binding.root) quizController.initialize(this) 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 81372b4a63..6979edd15d 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,9 +12,11 @@ import android.view.MenuItem import android.view.View import android.widget.ImageView import android.widget.TextView +import androidx.activity.enableEdgeToEdge import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity +import androidx.core.view.WindowCompat import fr.free.nrw.commons.databinding.ActivityQuizResultBinding import java.io.File @@ -22,6 +24,7 @@ import java.io.FileOutputStream import fr.free.nrw.commons.R import fr.free.nrw.commons.contributions.MainActivity +import fr.free.nrw.commons.utils.applyEdgeToEdgeAllInsets /** @@ -35,7 +38,11 @@ class QuizResultActivity : AppCompatActivity() { public override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + enableEdgeToEdge() binding = ActivityQuizResultBinding.inflate(layoutInflater) + applyEdgeToEdgeAllInsets(binding!!.root) + WindowCompat.getInsetsController(window, window.decorView) + .isAppearanceLightStatusBars = true setContentView(binding?.root) setSupportActionBar(binding?.toolbar?.toolbar) 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 20f289f8fa..42a75aeac8 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 @@ -16,6 +16,7 @@ import fr.free.nrw.commons.databinding.ActivityReviewBinding import fr.free.nrw.commons.delete.DeleteHelper import fr.free.nrw.commons.media.MediaDetailFragment import fr.free.nrw.commons.theme.BaseActivity +import fr.free.nrw.commons.utils.applyEdgeToEdgeAllInsets import fr.free.nrw.commons.utils.DialogUtil import fr.free.nrw.commons.utils.ViewUtil import io.reactivex.android.schedulers.AndroidSchedulers @@ -73,6 +74,7 @@ class ReviewActivity : BaseActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityReviewBinding.inflate(layoutInflater) + applyEdgeToEdgeAllInsets(binding.root) setContentView(binding.root) setSupportActionBar(binding.toolbarBinding?.toolbar) 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 91c88d7b0c..233e688f4e 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 @@ -4,6 +4,7 @@ import android.os.Bundle import android.view.MenuItem import fr.free.nrw.commons.databinding.ActivitySettingsBinding import fr.free.nrw.commons.theme.BaseActivity +import fr.free.nrw.commons.utils.applyEdgeToEdgeAllInsets /** @@ -21,6 +22,7 @@ class SettingsActivity : BaseActivity() { super.onCreate(savedInstanceState) binding = ActivitySettingsBinding.inflate(layoutInflater) val view = binding.root + applyEdgeToEdgeAllInsets(view) setContentView(view) setSupportActionBar(binding.toolbarBinding.toolbar) diff --git a/app/src/main/java/fr/free/nrw/commons/theme/BaseActivity.kt b/app/src/main/java/fr/free/nrw/commons/theme/BaseActivity.kt index d2d9364603..d317a7d35e 100644 --- a/app/src/main/java/fr/free/nrw/commons/theme/BaseActivity.kt +++ b/app/src/main/java/fr/free/nrw/commons/theme/BaseActivity.kt @@ -4,6 +4,7 @@ import android.content.res.Configuration import android.os.Bundle import android.util.DisplayMetrics import android.view.WindowManager +import androidx.activity.enableEdgeToEdge import javax.inject.Inject import javax.inject.Named import fr.free.nrw.commons.R @@ -36,6 +37,7 @@ abstract class BaseActivity : CommonsDaggerAppCompatActivity() { 1f ) adjustFontScale(resources.configuration, fontScale) + enableEdgeToEdge() } override fun onResume() { diff --git a/app/src/main/java/fr/free/nrw/commons/upload/UploadActivity.kt b/app/src/main/java/fr/free/nrw/commons/upload/UploadActivity.kt index 38e7dace8f..bca59428cd 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/UploadActivity.kt +++ b/app/src/main/java/fr/free/nrw/commons/upload/UploadActivity.kt @@ -38,6 +38,7 @@ import fr.free.nrw.commons.mwapi.UserClient import fr.free.nrw.commons.nearby.Place import fr.free.nrw.commons.settings.Prefs import fr.free.nrw.commons.theme.BaseActivity +import fr.free.nrw.commons.utils.applyEdgeToEdgeAllInsets import fr.free.nrw.commons.upload.ThumbnailsAdapter.OnThumbnailDeletedListener import fr.free.nrw.commons.upload.categories.UploadCategoriesFragment import fr.free.nrw.commons.upload.depicts.DepictsFragment @@ -177,6 +178,7 @@ class UploadActivity : BaseActivity(), UploadContract.View, UploadBaseFragment.C presenter?.setupBasicKvStoreFactory { BasicKvStore(this@UploadActivity, it) } _binding = ActivityUploadBinding.inflate(layoutInflater) + applyEdgeToEdgeAllInsets(_binding!!.root) setContentView(binding.root) // Overrides the back button to make sure the user is prepared to lose their progress 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 3cf9d3a656..665f106e22 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 @@ -10,6 +10,7 @@ import fr.free.nrw.commons.ViewPagerAdapter import fr.free.nrw.commons.contributions.ContributionDao import fr.free.nrw.commons.databinding.ActivityUploadProgressBinding import fr.free.nrw.commons.theme.BaseActivity +import fr.free.nrw.commons.utils.applyEdgeToEdgeAllInsets import javax.inject.Inject /** @@ -35,6 +36,7 @@ class UploadProgressActivity : BaseActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityUploadProgressBinding.inflate(layoutInflater) + applyEdgeToEdgeAllInsets(binding.root) setContentView(binding.root) viewPagerAdapter = ViewPagerAdapter(this, supportFragmentManager) binding.uploadProgressViewPager.setAdapter(viewPagerAdapter) diff --git a/app/src/main/java/fr/free/nrw/commons/utils/ConfigUtils.kt b/app/src/main/java/fr/free/nrw/commons/utils/ConfigUtils.kt index 332c8d023c..95fa62a20b 100644 --- a/app/src/main/java/fr/free/nrw/commons/utils/ConfigUtils.kt +++ b/app/src/main/java/fr/free/nrw/commons/utils/ConfigUtils.kt @@ -12,9 +12,9 @@ object ConfigUtils { val isBetaFlavour: Boolean = BuildConfig.FLAVOR == "beta" @JvmStatic - private fun Context.getVersionName(): String = + private fun Context.getVersionName(): String? = try { - packageManager.getPackageInfo(packageName, 0).versionName + packageManager.getPackageInfo(packageName, 0).versionName ?: BuildConfig.VERSION_NAME } catch (e: PackageManager.NameNotFoundException) { BuildConfig.VERSION_NAME } diff --git a/app/src/main/java/fr/free/nrw/commons/utils/EdgeToEdgeUtils.kt b/app/src/main/java/fr/free/nrw/commons/utils/EdgeToEdgeUtils.kt new file mode 100644 index 0000000000..8478f7f51f --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/utils/EdgeToEdgeUtils.kt @@ -0,0 +1,172 @@ +package fr.free.nrw.commons.utils + +import android.view.View +import android.view.ViewGroup.MarginLayoutParams +import androidx.core.view.ViewCompat +import androidx.core.view.WindowInsetsCompat +import androidx.core.view.marginBottom +import androidx.core.view.marginLeft +import androidx.core.view.marginRight +import androidx.core.view.marginTop +import androidx.core.view.updateLayoutParams +import androidx.core.view.updatePadding +import fr.free.nrw.commons.R + +/** + * Applies edge-to-edge system bar insets to a [View]’s margins using a custom adjustment block. + * + * Stores the initial margins to ensure inset calculations are additive, and applies the provided + * [block] with an [InsetsAccumulator] containing initial and system bar inset values. + * + * @param typeMask The type of window insets to apply. Defaults to [WindowInsetsCompat.Type.systemBars]. + * @param block Lambda applied to update [MarginLayoutParams] using the accumulated insets. + */ +fun View.applyEdgeToEdgeInsets( + typeMask: Int = WindowInsetsCompat.Type.systemBars(), + block: MarginLayoutParams.(InsetsAccumulator) -> Unit +) { + ViewCompat.setOnApplyWindowInsetsListener(this) { view, windowInsets -> + val insets = windowInsets.getInsets(typeMask) + + val initialTop = if (view.getTag(R.id.initial_margin_top) != null) { + view.getTag(R.id.initial_margin_top) as Int + } else { + view.setTag(R.id.initial_margin_top, view.marginTop) + view.marginTop + } + + val initialBottom = if (view.getTag(R.id.initial_margin_bottom) != null) { + view.getTag(R.id.initial_margin_bottom) as Int + } else { + view.setTag(R.id.initial_margin_bottom, view.marginBottom) + view.marginBottom + } + + val initialLeft = if (view.getTag(R.id.initial_margin_left) != null) { + view.getTag(R.id.initial_margin_left) as Int + } else { + view.setTag(R.id.initial_margin_left, view.marginLeft) + view.marginLeft + } + + val initialRight = if (view.getTag(R.id.initial_margin_right) != null) { + view.getTag(R.id.initial_margin_right) as Int + } else { + view.setTag(R.id.initial_margin_right, view.marginRight) + view.marginRight + } + + val accumulator = InsetsAccumulator( + initialTop, + insets.top, + initialBottom, + insets.bottom, + initialLeft, + insets.left, + initialRight, + insets.right + ) + + view.updateLayoutParams { + apply { block(accumulator) } + } + + WindowInsetsCompat.CONSUMED + } +} + +/** + * Applies edge-to-edge system bar insets to the top padding of the view. + * + * @param typeMask The type of window insets to apply. Defaults to [WindowInsetsCompat.Type.systemBars]. + */ +fun View.applyEdgeToEdgeTopPaddingInsets( + typeMask: Int = WindowInsetsCompat.Type.systemBars(), +) { + ViewCompat.setOnApplyWindowInsetsListener(this) { view, windowInsets -> + val insets = windowInsets.getInsets(typeMask) + + view.updatePadding( + left = insets.left, + right = insets.right, + top = insets.top + ) + + WindowInsetsCompat.CONSUMED + } +} + +/** + * Applies edge-to-edge system bar insets to the bottom padding of the view. + * + * @param typeMask The type of window insets to apply. Defaults to [WindowInsetsCompat.Type.systemBars]. + */ +fun View.applyEdgeToEdgeBottomPaddingInsets( + typeMask: Int = WindowInsetsCompat.Type.systemBars(), +) { + ViewCompat.setOnApplyWindowInsetsListener(this) { view, windowInsets -> + val insets = windowInsets.getInsets(typeMask) + + view.updatePadding( + left = insets.left, + right = insets.right, + bottom = insets.bottom + ) + + WindowInsetsCompat.CONSUMED + } +} + +/** + * Applies system bar insets to all margins (top, bottom, left, right) of the view. + * + * @param view The target view. + */ +fun applyEdgeToEdgeAllInsets(view: View) = view.applyEdgeToEdgeInsets { insets -> + leftMargin = insets.left + rightMargin = insets.right + topMargin = insets.top + bottomMargin = insets.bottom +} + +/** + * Applies system bar insets to the top and horizontal margins of the view. + * + * @param view The target view. + */ +fun applyEdgeToEdgeTopInsets(view: View) = view.applyEdgeToEdgeInsets { insets -> + leftMargin = insets.left + rightMargin = insets.right + topMargin = insets.top +} + +/** + * Applies system bar insets to the bottom and horizontal margins of the view. + * + * @param view The target view. + */ +fun applyEdgeToEdgeBottomInsets(view: View) = view.applyEdgeToEdgeInsets { insets -> + leftMargin = insets.left + rightMargin = insets.right + bottomMargin = insets.bottom +} + +/** + * Holds both initial margin values and system bar insets, providing summed values + * for each side (top, bottom, left, right) to apply in layout updates. + */ +data class InsetsAccumulator( + private val initialTop: Int, + private val insetTop: Int, + private val initialBottom: Int, + private val insetBottom: Int, + private val initialLeft: Int, + private val insetLeft: Int, + private val initialRight: Int, + private val insetRight: Int +) { + val top = initialTop + insetTop + val bottom = initialBottom + insetBottom + val left = initialLeft + insetLeft + val right = initialRight + insetRight +} \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/utils/ImageUtils.kt b/app/src/main/java/fr/free/nrw/commons/utils/ImageUtils.kt index ebff3d054f..fa538bb215 100644 --- a/app/src/main/java/fr/free/nrw/commons/utils/ImageUtils.kt +++ b/app/src/main/java/fr/free/nrw/commons/utils/ImageUtils.kt @@ -24,6 +24,7 @@ import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.CompositeDisposable import io.reactivex.schedulers.Schedulers import timber.log.Timber +import androidx.core.graphics.createBitmap /** * Created by blueSir9 on 3/10/17. @@ -307,16 +308,19 @@ object ImageUtils { * * @return */ @JvmStatic - fun addRedBorder(bitmap: Bitmap, borderSize: Int, context: Context): Bitmap { - val bmpWithBorder = Bitmap.createBitmap( - bitmap.width + borderSize * 2, - bitmap.height + borderSize * 2, - bitmap.config - ) - val canvas = Canvas(bmpWithBorder) - canvas.drawColor(ContextCompat.getColor(context, R.color.deleteRed)) - canvas.drawBitmap(bitmap, borderSize.toFloat(), borderSize.toFloat(), null) - return bmpWithBorder + fun addRedBorder(bitmap: Bitmap, borderSize: Int, context: Context): Bitmap? { + return bitmap.config?.let { config -> + val bmpWithBorder = + createBitmap( + width = bitmap.width + borderSize * 2, + height = bitmap.height + borderSize * 2, + config = config + ) + val canvas = Canvas(bmpWithBorder) + canvas.drawColor(ContextCompat.getColor(context, R.color.deleteRed)) + canvas.drawBitmap(bitmap, borderSize.toFloat(), borderSize.toFloat(), null) + return bmpWithBorder + } } /** diff --git a/app/src/main/res/layout/activity_notification.xml b/app/src/main/res/layout/activity_notification.xml index a8b60dea35..800c8aa0b3 100644 --- a/app/src/main/res/layout/activity_notification.xml +++ b/app/src/main/res/layout/activity_notification.xml @@ -35,6 +35,7 @@ android:scrollbars="vertical" android:fadeScrollbars="false" android:scrollbarThumbVertical="@color/primaryColor" + android:clipToPadding="false" android:scrollbarSize="@dimen/dimen_6"/> diff --git a/app/src/main/res/layout/fragment_custom_selector.xml b/app/src/main/res/layout/fragment_custom_selector.xml index 03381fd243..b016b6605f 100644 --- a/app/src/main/res/layout/fragment_custom_selector.xml +++ b/app/src/main/res/layout/fragment_custom_selector.xml @@ -34,6 +34,7 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/switchWidget" + android:clipToPadding="false" /> + + + + + + \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index df4b7bb43a..d26b1a62ce 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -agp = "8.9.1" +agp = "8.12.0" acra = "5.8.4" activityCompose = "1.9.3" adapterdelegates = "4.3.0" @@ -19,7 +19,7 @@ githubTripletPlay = "2.7.2" kotlinxCoroutinesRx2 = "1.8.0" osmdroidAndroid = "6.1.17" testCore = "1.4.0" -coreKtx = "1.9.0" +coreKtx = "1.16.0" coreTesting = "2.2.0" dagger = "2.23" databindingCompiler = "8.0.2" @@ -57,7 +57,7 @@ preference = "1.2.1" recyclerview = "1.2.0-alpha02" recyclerviewFastscroll = "2.0.1" retrofit = "2.8.1" -robolectric = "4.11.1" +robolectric = "4.14.1" room = "2.6.1" rules = "1.5.0" runner = "1.5.2" diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 26f6c44a24..f8f4d3f967 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Sun Apr 23 18:22:54 IST 2023 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists \ No newline at end of file