From d88f03db22fcf1a861d584e9624a58f3647735fa Mon Sep 17 00:00:00 2001 From: Jason Whitmore Date: Mon, 27 Oct 2025 14:43:49 -0700 Subject: [PATCH 1/3] build.gradle.kts, libs.versions.toml: add page indicator library Before this change, the page indicator library that was used was incompatible with ViewPager2. This change adds a page indicator library under the Apache 2.0 license that works with ViewPager2. Now the project can take advantage of ViewPager2 features, such as support for RTL languages/orientations. --- app/build.gradle.kts | 1 + gradle/libs.versions.toml | 2 ++ 2 files changed, 3 insertions(+) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 41788128c7..e2b845c6a6 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -231,6 +231,7 @@ dependencies { // UI implementation("${libs.viewpagerindicator.library.get()}@aar") + implementation(libs.viewpager2indicator) implementation(libs.photoview) implementation(libs.android.sdk) implementation(libs.android.plugin.scalebar) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9a4dd53cb2..36bcd6f0bd 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -69,6 +69,7 @@ slf4jApi = "1.7.25" soloader = "0.10.5" timber = "4.7.1" uiautomator = "2.2.0" +viewpager2indicatorVersion = "1.2.3" workManager = "2.8.1" [libraries] @@ -170,6 +171,7 @@ adapterdelegates4-pagination = { module = "com.hannesdorfmann:adapterdelegates4- dexter = { module = "com.karumi:dexter", version.ref = "dexterVersion" } recyclerview-fastscroll = { module = "com.simplecityapps:recyclerview-fastscroll", version.ref = "recyclerviewFastscroll" } swipelayout-library = { module = "com.daimajia.swipelayout:library", version.ref = "swipelayout" } +viewpager2indicator = { module = "com.github.zhpanvip:viewpagerindicator", version.ref = "viewpager2indicatorVersion" } viewpagerindicator-library = { module = "fr.avianey.com.viewpagerindicator:library", version.ref = "viewpagerIndicator" } # Networking libraries From e481e5cafbc15fda6224f95b301d2790a1f87b36 Mon Sep 17 00:00:00 2001 From: Jason Whitmore Date: Mon, 27 Oct 2025 14:59:47 -0700 Subject: [PATCH 2/3] WelcomeActivity.kt, WelcomePagerAdapter.kt: change code to support RTL orientations Before this commit, the Welcome activity Kotlin code only supported LTR orientations. This commit uses ViewPager2 and a new page indicator to support both LTR and RTL orientations. The orientation is derived from the user's app language setting. --- .../fr/free/nrw/commons/WelcomeActivity.kt | 19 +++++++- .../free/nrw/commons/WelcomePagerAdapter.kt | 48 ++++++++----------- 2 files changed, 38 insertions(+), 29 deletions(-) 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 0882ba1176..af2c96016d 100644 --- a/app/src/main/java/fr/free/nrw/commons/WelcomeActivity.kt +++ b/app/src/main/java/fr/free/nrw/commons/WelcomeActivity.kt @@ -5,12 +5,16 @@ import android.content.Context import android.content.Intent import android.os.Bundle import android.view.View +import androidx.core.text.TextUtilsCompat +import com.zhpan.indicator.enums.IndicatorOrientation 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.settings.Prefs import fr.free.nrw.commons.theme.BaseActivity import fr.free.nrw.commons.utils.applyEdgeToEdgeAllInsets import fr.free.nrw.commons.utils.ConfigUtils.isBetaFlavour +import java.util.Locale class WelcomeActivity : BaseActivity() { private var binding: ActivityWelcomeBinding? = null @@ -46,7 +50,20 @@ class WelcomeActivity : BaseActivity() { val adapter = WelcomePagerAdapter() binding!!.welcomePager.adapter = adapter - binding!!.welcomePagerIndicator.setViewPager(binding!!.welcomePager) + binding!!.welcomePagerIndicator.setupWithViewPager(binding!!.welcomePager) + + //Unfortunately, setting the page indicator direction (LTR vs RTL) must be done in Kotlin + + //Assume LTR until language is checked. + var orientation = IndicatorOrientation.INDICATOR_HORIZONTAL + + val languageCode = defaultKvStore.getString(Prefs.APP_UI_LANGUAGE) + if (languageCode != null && TextUtilsCompat.getLayoutDirectionFromLocale( + Locale(languageCode)) == View.LAYOUT_DIRECTION_RTL) { + orientation = IndicatorOrientation.INDICATOR_RTL + } + + binding!!.welcomePagerIndicator.setOrientation(orientation) binding!!.finishTutorialButton.setOnClickListener { v: View? -> finishTutorial() } } diff --git a/app/src/main/java/fr/free/nrw/commons/WelcomePagerAdapter.kt b/app/src/main/java/fr/free/nrw/commons/WelcomePagerAdapter.kt index 0cb88c48bc..243c7195b6 100644 --- a/app/src/main/java/fr/free/nrw/commons/WelcomePagerAdapter.kt +++ b/app/src/main/java/fr/free/nrw/commons/WelcomePagerAdapter.kt @@ -5,59 +5,51 @@ import android.view.View import android.view.ViewGroup import android.widget.TextView import androidx.core.net.toUri -import androidx.viewpager.widget.PagerAdapter +import androidx.recyclerview.widget.RecyclerView import fr.free.nrw.commons.utils.UnderlineUtils.setUnderlinedText import fr.free.nrw.commons.utils.handleWebUrl -class WelcomePagerAdapter : PagerAdapter() { +class WelcomePagerAdapter : RecyclerView.Adapter() { /** * Gets total number of layouts * @return Number of layouts */ - override fun getCount(): Int = PAGE_LAYOUTS.size + override fun getItemCount(): Int = PAGE_LAYOUTS.size - /** - * Compares given view with provided object - * @param view Adapter view - * @param obj Adapter object - * @return Equality between view and object - */ - override fun isViewFromObject(view: View, obj: Any): Boolean = (view === obj) - - /** - * Provides a way to remove an item from container - * @param container Adapter view group container - * @param position Index of item - * @param obj Adapter object - */ - override fun destroyItem(container: ViewGroup, position: Int, obj: Any) = - container.removeView(obj as View) + override fun getItemViewType(position: Int): Int { + return position + } - override fun instantiateItem(container: ViewGroup, position: Int): Any { + override fun onCreateViewHolder(container: ViewGroup, type: Int): ViewHolder { val inflater = LayoutInflater.from(container.context) - val layout = inflater.inflate(PAGE_LAYOUTS[position], container, false) as ViewGroup + val layout = inflater.inflate(PAGE_LAYOUTS[type], container, false) + return ViewHolder(layout) + } + override fun onBindViewHolder( + holder: ViewHolder, + position: Int + ) { // If final page if (position == PAGE_LAYOUTS.size - 1) { // Add link to more information - val moreInfo = layout.findViewById(R.id.welcomeInfo) + val moreInfo = holder.itemView.findViewById(R.id.welcomeInfo) setUnderlinedText(moreInfo, R.string.welcome_help_button_text) moreInfo.setOnClickListener { handleWebUrl( - container.context, + holder.itemView.context, "https://commons.wikimedia.org/wiki/Help:Contents".toUri() ) } // Handle click of finishTutorialButton ("YES!" button) inside layout - layout.findViewById(R.id.finishTutorialButton) - .setOnClickListener { view: View? -> (container.context as WelcomeActivity).finishTutorial() } + holder.itemView.findViewById(R.id.finishTutorialButton).setOnClickListener { + view: View? -> (holder.itemView.context as WelcomeActivity).finishTutorial() } } - - container.addView(layout) - return layout } + class ViewHolder(view: View) : RecyclerView.ViewHolder(view) + companion object { private val PAGE_LAYOUTS = intArrayOf( R.layout.welcome_wikipedia, From 410520bfa51ce915c2f9507ba4ad73200cf5ef9c Mon Sep 17 00:00:00 2001 From: Jason Whitmore Date: Mon, 27 Oct 2025 15:47:18 -0700 Subject: [PATCH 3/3] activity_welcome.xml, welcome_final.xml: change xml files to support RTL Before this commit, the xml files did not support RTL orientation. This commit adds support for RTL orientation by using ViewPager2 and a new pager indicator. Other small changes also made to support RTL orientation. --- app/src/main/res/layout/activity_welcome.xml | 14 +++++++++----- app/src/main/res/layout/welcome_final.xml | 2 +- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/app/src/main/res/layout/activity_welcome.xml b/app/src/main/res/layout/activity_welcome.xml index 4cce03da62..94ceeb94c3 100644 --- a/app/src/main/res/layout/activity_welcome.xml +++ b/app/src/main/res/layout/activity_welcome.xml @@ -2,9 +2,10 @@ - - + android:layout_gravity="bottom|center_horizontal" + android:padding="@dimen/tiny_padding" + android:layout_marginBottom="10dp" + custom:vpi_slider_checked_color="@color/white" + custom:vpi_slider_radius="3dp" /> diff --git a/app/src/main/res/layout/welcome_final.xml b/app/src/main/res/layout/welcome_final.xml index 3aab675d06..1a6b2f15ff 100644 --- a/app/src/main/res/layout/welcome_final.xml +++ b/app/src/main/res/layout/welcome_final.xml @@ -67,7 +67,7 @@ android:id="@+id/welcomeInfo" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_alignParentRight="true" + android:layout_alignParentEnd="true" android:layout_alignParentBottom="true" android:layout_marginBottom="@dimen/standard_gap" android:padding="@dimen/standard_gap"