Convert ViewPagerAdapter to kotlin and enforce that all tabs must have a title that comes from strings.xml

This commit is contained in:
Paul Hawke 2025-07-04 10:08:55 -05:00
parent 45f141e2dc
commit b4c14776ee
10 changed files with 98 additions and 144 deletions

View file

@ -16,6 +16,7 @@
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="999" />
<option name="IMPORT_LAYOUT_TABLE">
<value>
<package name="" withSubpackages="true" static="false" module="true" />
<package name="" withSubpackages="true" static="true" />
<emptyLine />
<package name="" withSubpackages="true" static="false" />

View file

@ -1,68 +0,0 @@
package fr.free.nrw.commons;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import java.util.ArrayList;
import java.util.List;
/**
* This adapter will be used to display fragments in a ViewPager
*/
public class ViewPagerAdapter extends FragmentPagerAdapter {
private List<Fragment> fragmentList = new ArrayList<>();
private List<String> fragmentTitleList = new ArrayList<>();
public ViewPagerAdapter(FragmentManager manager) {
super(manager);
}
/**
* Constructs a ViewPagerAdapter with a specified Fragment Manager and Fragment resume behavior.
*
* @param manager The FragmentManager
* @param behavior An integer which represents the behavior of non visible fragments. See
* FragmentPagerAdapter.java for options.
*/
public ViewPagerAdapter(FragmentManager manager, int behavior) {
super(manager, behavior);
}
/**
* This method returns the fragment of the viewpager at a particular position
* @param position
*/
@Override
public Fragment getItem(int position) {
return fragmentList.get(position);
}
/**
* This method returns the total number of fragments in the viewpager.
* @return size
*/
@Override
public int getCount() {
return fragmentList.size();
}
/**
* This method sets the fragment and title list in the viewpager
* @param fragmentList List of all fragments to be displayed in the viewpager
* @param fragmentTitleList List of all titles of the fragments
*/
public void setTabData(List<Fragment> fragmentList, List<String> fragmentTitleList) {
this.fragmentList = fragmentList;
this.fragmentTitleList = fragmentTitleList;
}
/**
* This method returns the title of the page at a particular position
* @param position
*/
@Override
public CharSequence getPageTitle(int position) {
return fragmentTitleList.get(position);
}
}

View file

@ -0,0 +1,44 @@
package fr.free.nrw.commons
import android.content.Context
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentPagerAdapter
import java.util.Locale
/**
* This adapter will be used to display fragments in a ViewPager
*/
class ViewPagerAdapter : FragmentPagerAdapter {
private val context: Context
private var fragmentList: List<Fragment> = emptyList()
private var fragmentTitleList: List<String> = emptyList()
constructor(context: Context, manager: FragmentManager) : super(manager) {
this.context = context
}
constructor(context: Context, manager: FragmentManager, behavior: Int) : super(manager, behavior) {
this.context = context
}
override fun getItem(position: Int): Fragment = fragmentList[position]
override fun getPageTitle(position: Int): CharSequence = fragmentTitleList[position]
override fun getCount(): Int = fragmentList.size
fun setTabs(vararg titlesToFragments: Pair<Int, Fragment>) {
// Enforce that every title must come from strings.xml and all will consistently be uppercase
fragmentTitleList = titlesToFragments.map {
context.getString(it.first).uppercase(Locale.ROOT)
}
fragmentList = titlesToFragments.map { it.second }
}
companion object {
// Convenience method for Java callers, can be removed when everything is migrated
@JvmStatic
fun pairOf(first: Int, second: Fragment) = first to second
}
}

View file

@ -59,7 +59,7 @@ class CategoryDetailsActivity : BaseActivity(),
val view = binding.root
setContentView(view)
supportFragmentManager = getSupportFragmentManager()
viewPagerAdapter = ViewPagerAdapter(supportFragmentManager)
viewPagerAdapter = ViewPagerAdapter(this, supportFragmentManager)
binding.viewPager.adapter = viewPagerAdapter
binding.viewPager.offscreenPageLimit = 2
binding.tabLayout.setupWithViewPager(binding.viewPager)
@ -83,8 +83,6 @@ class CategoryDetailsActivity : BaseActivity(),
* Set the fragments according to the tab selected in the viewPager.
*/
private fun setTabs() {
val fragmentList = mutableListOf<Fragment>()
val titleList = mutableListOf<String>()
categoriesMediaFragment = CategoriesMediaFragment()
val subCategoryListFragment = SubCategoriesFragment()
val parentCategoriesFragment = ParentCategoriesFragment()
@ -99,13 +97,12 @@ class CategoryDetailsActivity : BaseActivity(),
viewModel.onCheckIfBookmarked(categoryName!!)
}
fragmentList.add(categoriesMediaFragment)
titleList.add("MEDIA")
fragmentList.add(subCategoryListFragment)
titleList.add("SUBCATEGORIES")
fragmentList.add(parentCategoriesFragment)
titleList.add("PARENT CATEGORIES")
viewPagerAdapter.setTabData(fragmentList, titleList)
viewPagerAdapter.setTabs(
R.string.title_for_media to categoriesMediaFragment,
R.string.title_for_subcategories to subCategoryListFragment,
R.string.title_for_parent_categories to parentCategoriesFragment
)
viewPagerAdapter.notifyDataSetChanged()
}

View file

@ -1,6 +1,7 @@
package fr.free.nrw.commons.explore;
import static androidx.viewpager.widget.ViewPager.SCROLL_STATE_IDLE;
import static fr.free.nrw.commons.ViewPagerAdapter.pairOf;
import android.os.Bundle;
import android.view.LayoutInflater;
@ -23,10 +24,12 @@ import fr.free.nrw.commons.kvstore.JsonKvStore;
import fr.free.nrw.commons.theme.BaseActivity;
import fr.free.nrw.commons.utils.ActivityUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import javax.inject.Inject;
import javax.inject.Named;
import kotlin.Pair;
public class ExploreFragment extends CommonsDaggerSupportFragment {
@ -70,7 +73,7 @@ public class ExploreFragment extends CommonsDaggerSupportFragment {
loadNearbyMapData();
binding = FragmentExploreBinding.inflate(inflater, container, false);
viewPagerAdapter = new ViewPagerAdapter(getChildFragmentManager(),
viewPagerAdapter = new ViewPagerAdapter(requireContext(), getChildFragmentManager(),
FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
binding.viewPager.setAdapter(viewPagerAdapter);
@ -111,9 +114,6 @@ public class ExploreFragment extends CommonsDaggerSupportFragment {
* Sets the titles in the tabLayout and fragments in the viewPager
*/
public void setTabs() {
List<Fragment> fragmentList = new ArrayList<>();
List<String> titleList = new ArrayList<>();
Bundle featuredArguments = new Bundle();
featuredArguments.putString("categoryName", FEATURED_IMAGES_CATEGORY);
@ -133,19 +133,15 @@ public class ExploreFragment extends CommonsDaggerSupportFragment {
featuredRootFragment = new ExploreListRootFragment(featuredArguments);
mobileRootFragment = new ExploreListRootFragment(mobileArguments);
mapRootFragment = new ExploreMapRootFragment(mapArguments);
fragmentList.add(featuredRootFragment);
titleList.add(getString(R.string.explore_tab_title_featured).toUpperCase(Locale.ROOT));
fragmentList.add(mobileRootFragment);
titleList.add(getString(R.string.explore_tab_title_mobile).toUpperCase(Locale.ROOT));
fragmentList.add(mapRootFragment);
titleList.add(getString(R.string.explore_tab_title_map).toUpperCase(Locale.ROOT));
((MainActivity) getActivity()).showTabs();
((BaseActivity) getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(false);
viewPagerAdapter.setTabData(fragmentList, titleList);
viewPagerAdapter.setTabs(
pairOf(R.string.explore_tab_title_featured, featuredRootFragment),
pairOf(R.string.explore_tab_title_mobile, mobileRootFragment),
pairOf(R.string.explore_tab_title_map, mapRootFragment)
);
viewPagerAdapter.notifyDataSetChanged();
}

View file

@ -1,5 +1,7 @@
package fr.free.nrw.commons.explore;
import static fr.free.nrw.commons.ViewPagerAdapter.pairOf;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
@ -26,11 +28,13 @@ import fr.free.nrw.commons.utils.FragmentUtils;
import fr.free.nrw.commons.utils.ViewUtil;
import io.reactivex.android.schedulers.AndroidSchedulers;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import kotlin.Pair;
import timber.log.Timber;
/**
@ -65,7 +69,7 @@ public class SearchActivity extends BaseActivity
binding.toolbarSearch.setNavigationOnClickListener(v->onBackPressed());
supportFragmentManager = getSupportFragmentManager();
setSearchHistoryFragment();
viewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager());
viewPagerAdapter = new ViewPagerAdapter(this, getSupportFragmentManager());
binding.viewPager.setAdapter(viewPagerAdapter);
binding.viewPager.setOffscreenPageLimit(2); // Because we want all the fragments to be alive
binding.tabLayout.setupWithViewPager(binding.viewPager);
@ -90,19 +94,15 @@ public class SearchActivity extends BaseActivity
* Sets the titles in the tabLayout and fragments in the viewPager
*/
public void setTabs() {
List<Fragment> fragmentList = new ArrayList<>();
List<String> titleList = new ArrayList<>();
searchMediaFragment = new SearchMediaFragment();
searchDepictionsFragment = new SearchDepictionsFragment();
searchCategoryFragment= new SearchCategoryFragment();
fragmentList.add(searchMediaFragment);
titleList.add(getResources().getString(R.string.search_tab_title_media).toUpperCase(Locale.ROOT));
fragmentList.add(searchCategoryFragment);
titleList.add(getResources().getString(R.string.search_tab_title_categories).toUpperCase(Locale.ROOT));
fragmentList.add(searchDepictionsFragment);
titleList.add(getResources().getString(R.string.search_tab_title_depictions).toUpperCase(Locale.ROOT));
viewPagerAdapter.setTabData(fragmentList, titleList);
viewPagerAdapter.setTabs(
pairOf(R.string.search_tab_title_media, searchMediaFragment),
pairOf(R.string.search_tab_title_categories, searchCategoryFragment),
pairOf(R.string.search_tab_title_depictions, searchDepictionsFragment)
);
viewPagerAdapter.notifyDataSetChanged();
getCompositeDisposable().add(RxSearchView.queryTextChanges(binding.searchBox)
.takeUntil(RxView.detaches(binding.searchBox))

View file

@ -1,5 +1,6 @@
package fr.free.nrw.commons.explore.depictions;
import static fr.free.nrw.commons.ViewPagerAdapter.pairOf;
import static fr.free.nrw.commons.utils.UrlUtilsKt.handleWebUrl;
import android.content.Context;
@ -31,8 +32,10 @@ import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.inject.Inject;
import kotlin.Pair;
/**
* Activity to show depiction media, parent classes and child classes of depicted items in Explore
@ -66,7 +69,7 @@ public class WikidataItemDetailsActivity extends BaseActivity implements MediaDe
setContentView(binding.getRoot());
compositeDisposable = new CompositeDisposable();
supportFragmentManager = getSupportFragmentManager();
viewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager());
viewPagerAdapter = new ViewPagerAdapter(this, getSupportFragmentManager());
binding.viewPager.setAdapter(viewPagerAdapter);
binding.viewPager.setOffscreenPageLimit(2);
binding.tabLayout.setupWithViewPager(binding.viewPager);
@ -105,8 +108,6 @@ public class WikidataItemDetailsActivity extends BaseActivity implements MediaDe
* Set the fragments according to the tab selected in the viewPager.
*/
private void setTabs() {
List<Fragment> fragmentList = new ArrayList<>();
List<String> titleList = new ArrayList<>();
depictionImagesListFragment = new DepictedImagesFragment();
ChildDepictionsFragment childDepictionsFragment = new ChildDepictionsFragment();
ParentDepictionsFragment parentDepictionsFragment = new ParentDepictionsFragment();
@ -120,13 +121,12 @@ public class WikidataItemDetailsActivity extends BaseActivity implements MediaDe
parentDepictionsFragment.setArguments(arguments);
childDepictionsFragment.setArguments(arguments);
}
fragmentList.add(depictionImagesListFragment);
titleList.add(getResources().getString(R.string.title_for_media));
fragmentList.add(childDepictionsFragment);
titleList.add(getResources().getString(R.string.title_for_child_classes));
fragmentList.add(parentDepictionsFragment);
titleList.add(getResources().getString(R.string.title_for_parent_classes));
viewPagerAdapter.setTabData(fragmentList, titleList);
viewPagerAdapter.setTabs(
pairOf(R.string.title_for_media, depictionImagesListFragment),
pairOf(R.string.title_for_subcategories, childDepictionsFragment),
pairOf(R.string.title_for_parent_categories, parentDepictionsFragment)
);
binding.viewPager.setOffscreenPageLimit(2);
viewPagerAdapter.notifyDataSetChanged();

View file

@ -11,6 +11,7 @@ import android.view.View
import android.widget.ImageView
import android.widget.TextView
import androidx.core.content.FileProvider
import androidx.core.os.bundleOf
import androidx.fragment.app.Fragment
import fr.free.nrw.commons.R
import fr.free.nrw.commons.ViewPagerAdapter
@ -71,7 +72,7 @@ class ProfileActivity : BaseActivity() {
title = userName
shouldShowContributions = intent.getBooleanExtra(KEY_SHOULD_SHOW_CONTRIBUTIONS, false)
viewPagerAdapter = ViewPagerAdapter(supportFragmentManager)
viewPagerAdapter = ViewPagerAdapter(this, supportFragmentManager)
binding.viewPager.adapter = viewPagerAdapter
binding.tabLayout.setupWithViewPager(binding.viewPager)
setTabs()
@ -83,39 +84,23 @@ class ProfileActivity : BaseActivity() {
}
private fun setTabs() {
val fragmentList = mutableListOf<Fragment>()
val titleList = mutableListOf<String>()
// Add Achievements tab
achievementsFragment = AchievementsFragment().apply {
arguments = Bundle().apply {
putString(KEY_USERNAME, userName)
}
arguments = bundleOf(KEY_USERNAME to userName)
}
fragmentList.add(achievementsFragment)
titleList.add(resources.getString(R.string.achievements_tab_title).uppercase())
// Add Leaderboard tab
leaderboardFragment = LeaderboardFragment().apply {
arguments = Bundle().apply {
putString(KEY_USERNAME, userName)
}
arguments = bundleOf(KEY_USERNAME to userName)
}
fragmentList.add(leaderboardFragment)
titleList.add(resources.getString(R.string.leaderboard_tab_title).uppercase(Locale.ROOT))
// Add Contributions tab
contributionsFragment = ContributionsFragment().apply {
arguments = Bundle().apply {
putString(KEY_USERNAME, userName)
}
}
contributionsFragment?.let {
fragmentList.add(it)
titleList.add(getString(R.string.contributions_fragment).uppercase(Locale.ROOT))
arguments = bundleOf(KEY_USERNAME to userName)
}
viewPagerAdapter.setTabData(fragmentList, titleList)
viewPagerAdapter.setTabs(
R.string.achievements_tab_title to achievementsFragment,
R.string.leaderboard_tab_title to leaderboardFragment,
R.string.contributions_fragment to contributionsFragment!!
)
viewPagerAdapter.notifyDataSetChanged()
}

View file

@ -28,8 +28,6 @@ class UploadProgressActivity : BaseActivity() {
@Inject
lateinit var contributionDao: ContributionDao
val fragmentList: MutableList<Fragment> = ArrayList()
val titleList: MutableList<String> = ArrayList()
var isPaused = true
var isPendingIconsVisible = true
var isErrorIconsVisisble = false
@ -38,7 +36,7 @@ class UploadProgressActivity : BaseActivity() {
super.onCreate(savedInstanceState)
binding = ActivityUploadProgressBinding.inflate(layoutInflater)
setContentView(binding.root)
viewPagerAdapter = ViewPagerAdapter(supportFragmentManager)
viewPagerAdapter = ViewPagerAdapter(this, supportFragmentManager)
binding.uploadProgressViewPager.setAdapter(viewPagerAdapter)
binding.uploadProgressViewPager.setId(R.id.upload_progress_view_pager)
binding.uploadProgressTabLayout.setupWithViewPager(binding.uploadProgressViewPager)
@ -81,11 +79,10 @@ class UploadProgressActivity : BaseActivity() {
pendingUploadsFragment = PendingUploadsFragment()
failedUploadsFragment = FailedUploadsFragment()
fragmentList.add(pendingUploadsFragment!!)
titleList.add(getString(R.string.pending))
fragmentList.add(failedUploadsFragment!!)
titleList.add(getString(R.string.failed))
viewPagerAdapter!!.setTabData(fragmentList, titleList)
viewPagerAdapter!!.setTabs(
R.string.pending to pendingUploadsFragment!!,
R.string.failed to failedUploadsFragment!!
)
viewPagerAdapter!!.notifyDataSetChanged()
}

View file

@ -617,6 +617,8 @@ Upload your first media by tapping on the add button.</string>
<string name="title_for_media">MEDIA</string>
<string name="title_for_child_classes">CHILD CLASSES</string>
<string name="title_for_parent_classes">PARENT CLASSES</string>
<string name="title_for_subcategories">SUBCATEGORIES</string>
<string name="title_for_parent_categories">PARENT CATEGORIES</string>
<string name="upload_nearby_place_found_title">Nearby Place Found</string>
<string name="upload_nearby_place_found_description_plural">Are these pictures of %1$s?</string>