Break up MediaDetailPagerFragment to make it easier to convert to kotlin

This commit is contained in:
Paul Hawke 2025-07-11 14:36:36 -05:00
parent 840f4fd44e
commit 4564d5570a
14 changed files with 138 additions and 127 deletions

View file

@ -22,6 +22,7 @@ import fr.free.nrw.commons.contributions.MainActivity;
import fr.free.nrw.commons.databinding.FragmentFeaturedRootBinding;
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
import fr.free.nrw.commons.media.MediaDetailPagerFragment;
import fr.free.nrw.commons.media.MediaDetailProvider;
import fr.free.nrw.commons.navtab.NavTab;
import java.util.ArrayList;
import java.util.Iterator;
@ -29,7 +30,7 @@ import timber.log.Timber;
public class BookmarkListRootFragment extends CommonsDaggerSupportFragment implements
FragmentManager.OnBackStackChangedListener,
MediaDetailPagerFragment.MediaDetailProvider,
MediaDetailProvider,
AdapterView.OnItemClickListener, CategoryImagesCallback {
private MediaDetailPagerFragment mediaDetails;

View file

@ -8,7 +8,6 @@ import android.view.Menu
import android.view.MenuItem
import android.view.View
import androidx.activity.viewModels
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
@ -22,6 +21,7 @@ import fr.free.nrw.commons.explore.categories.media.CategoriesMediaFragment
import fr.free.nrw.commons.explore.categories.parent.ParentCategoriesFragment
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.handleWebUrl
import fr.free.nrw.commons.wikidata.model.WikiSite
@ -36,7 +36,7 @@ import javax.inject.Inject
* a particular category on wikimedia commons.
*/
class CategoryDetailsActivity : BaseActivity(),
MediaDetailPagerFragment.MediaDetailProvider,
MediaDetailProvider,
CategoryImagesCallback {
private lateinit var supportFragmentManager: FragmentManager

View file

@ -43,7 +43,7 @@ import fr.free.nrw.commons.location.LatLng
import fr.free.nrw.commons.location.LocationServiceManager
import fr.free.nrw.commons.location.LocationUpdateListener
import fr.free.nrw.commons.media.MediaDetailPagerFragment
import fr.free.nrw.commons.media.MediaDetailPagerFragment.MediaDetailProvider
import fr.free.nrw.commons.media.MediaDetailProvider
import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient
import fr.free.nrw.commons.nearby.NearbyController
import fr.free.nrw.commons.nearby.NearbyNotificationCardView
@ -72,7 +72,6 @@ import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import timber.log.Timber
import java.util.Calendar
import java.util.Date
import javax.inject.Inject
import javax.inject.Named

View file

@ -5,7 +5,6 @@ import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
@ -17,10 +16,11 @@ import fr.free.nrw.commons.databinding.FragmentFeaturedRootBinding;
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
import fr.free.nrw.commons.explore.categories.media.CategoriesMediaFragment;
import fr.free.nrw.commons.media.MediaDetailPagerFragment;
import fr.free.nrw.commons.media.MediaDetailProvider;
import fr.free.nrw.commons.navtab.NavTab;
public class ExploreListRootFragment extends CommonsDaggerSupportFragment implements
MediaDetailPagerFragment.MediaDetailProvider, CategoryImagesCallback {
MediaDetailProvider, CategoryImagesCallback {
private MediaDetailPagerFragment mediaDetails;
private CategoriesMediaFragment listFragment;

View file

@ -5,7 +5,6 @@ import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
@ -17,10 +16,11 @@ import fr.free.nrw.commons.databinding.FragmentFeaturedRootBinding;
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
import fr.free.nrw.commons.explore.map.ExploreMapFragment;
import fr.free.nrw.commons.media.MediaDetailPagerFragment;
import fr.free.nrw.commons.media.MediaDetailProvider;
import fr.free.nrw.commons.navtab.NavTab;
public class ExploreMapRootFragment extends CommonsDaggerSupportFragment implements
MediaDetailPagerFragment.MediaDetailProvider, CategoryImagesCallback {
MediaDetailProvider, CategoryImagesCallback {
private MediaDetailPagerFragment mediaDetails;
private ExploreMapFragment mapFragment;

View file

@ -6,7 +6,6 @@ import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import com.jakewharton.rxbinding2.view.RxView;
@ -23,18 +22,14 @@ import fr.free.nrw.commons.explore.models.RecentSearch;
import fr.free.nrw.commons.explore.recentsearches.RecentSearchesDao;
import fr.free.nrw.commons.explore.recentsearches.RecentSearchesFragment;
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.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;
/**
@ -42,7 +37,7 @@ import timber.log.Timber;
*/
public class SearchActivity extends BaseActivity
implements MediaDetailPagerFragment.MediaDetailProvider, CategoryImagesCallback {
implements MediaDetailProvider, CategoryImagesCallback {
@Inject
RecentSearchesDao recentSearchesDao;

View file

@ -11,7 +11,6 @@ import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import com.google.android.material.snackbar.Snackbar;
import fr.free.nrw.commons.Media;
@ -24,6 +23,7 @@ import fr.free.nrw.commons.explore.depictions.child.ChildDepictionsFragment;
import fr.free.nrw.commons.explore.depictions.media.DepictedImagesFragment;
import fr.free.nrw.commons.explore.depictions.parent.ParentDepictionsFragment;
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.upload.structure.depictions.DepictModel;
import fr.free.nrw.commons.upload.structure.depictions.DepictedItem;
@ -31,16 +31,12 @@ import fr.free.nrw.commons.wikidata.WikidataConstants;
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
*/
public class WikidataItemDetailsActivity extends BaseActivity implements MediaDetailPagerFragment.MediaDetailProvider,
public class WikidataItemDetailsActivity extends BaseActivity implements MediaDetailProvider,
CategoryImagesCallback {
private FragmentManager supportFragmentManager;
private DepictedImagesFragment depictionImagesListFragment;

View file

@ -8,7 +8,7 @@ import fr.free.nrw.commons.MediaDataExtractor
import fr.free.nrw.commons.R
import fr.free.nrw.commons.category.CategoryImagesCallback
import fr.free.nrw.commons.explore.paging.BasePagingFragment
import fr.free.nrw.commons.media.MediaDetailPagerFragment.MediaDetailProvider
import fr.free.nrw.commons.media.MediaDetailProvider
import javax.inject.Inject
abstract class PageableMediaFragment :

View file

@ -0,0 +1,95 @@
package fr.free.nrw.commons.media;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentStatePagerAdapter;
import timber.log.Timber;
//FragmentStatePagerAdapter allows user to swipe across collection of images (no. of images undetermined)
class MediaDetailAdapter extends FragmentStatePagerAdapter {
final MediaDetailPagerFragment mediaDetailPagerFragment;
/**
* Keeps track of the current displayed fragment.
*/
private Fragment mCurrentFragment;
public MediaDetailAdapter(MediaDetailPagerFragment mediaDetailPagerFragment,
FragmentManager fm) {
super(fm);
this.mediaDetailPagerFragment = mediaDetailPagerFragment;
}
@Override
public Fragment getItem(int i) {
if (i == 0) {
// See bug https://code.google.com/p/android/issues/detail?id=27526
if (mediaDetailPagerFragment.getActivity() == null) {
Timber.d("Skipping getItem. Returning as activity is destroyed!");
return null;
}
mediaDetailPagerFragment.binding.mediaDetailsPager.postDelayed(
() -> mediaDetailPagerFragment.getActivity().invalidateOptionsMenu(), 5);
}
if (mediaDetailPagerFragment.isFromFeaturedRootFragment) {
return MediaDetailFragment.forMedia(mediaDetailPagerFragment.position + i,
mediaDetailPagerFragment.editable, mediaDetailPagerFragment.isFeaturedImage,
mediaDetailPagerFragment.isWikipediaButtonDisplayed);
} else {
return MediaDetailFragment.forMedia(i, mediaDetailPagerFragment.editable,
mediaDetailPagerFragment.isFeaturedImage,
mediaDetailPagerFragment.isWikipediaButtonDisplayed);
}
}
@Override
public int getCount() {
if (mediaDetailPagerFragment.getActivity() == null) {
Timber.d("Skipping getCount. Returning as activity is destroyed!");
return 0;
}
return mediaDetailPagerFragment.provider.getTotalMediaCount();
}
/**
* Get the currently displayed fragment.
*
* @return
*/
public Fragment getCurrentFragment() {
return mCurrentFragment;
}
/**
* If current fragment is of type MediaDetailFragment, return it, otherwise return null.
*
* @return MediaDetailFragment
*/
public MediaDetailFragment getCurrentMediaDetailFragment() {
if (mCurrentFragment instanceof MediaDetailFragment) {
return (MediaDetailFragment) mCurrentFragment;
}
return null;
}
/**
* Called to inform the adapter of which item is currently considered to be the "primary", that
* is the one show to the user as the current page.
*
* @param container
* @param position
* @param object
*/
@Override
public void setPrimaryItem(@NonNull final ViewGroup container, final int position,
@NonNull final Object object) {
// Update the current fragment if changed
if (getCurrentFragment() != object) {
mCurrentFragment = ((Fragment) object);
}
super.setPrimaryItem(container, position, object);
}
}

View file

@ -77,7 +77,6 @@ import fr.free.nrw.commons.CommonsApplication.Companion.instance
import fr.free.nrw.commons.Media
import fr.free.nrw.commons.MediaDataExtractor
import fr.free.nrw.commons.R
import fr.free.nrw.commons.utils.UnderlineUtils
import fr.free.nrw.commons.actions.ThanksClient
import fr.free.nrw.commons.auth.SessionManager
import fr.free.nrw.commons.auth.csrf.InvalidLoginTokenException
@ -102,7 +101,6 @@ import fr.free.nrw.commons.kvstore.JsonKvStore
import fr.free.nrw.commons.language.AppLanguageLookUpTable
import fr.free.nrw.commons.location.LocationServiceManager
import fr.free.nrw.commons.locationpicker.LocationPicker
import fr.free.nrw.commons.media.MediaDetailPagerFragment.MediaDetailProvider
import fr.free.nrw.commons.profile.ProfileActivity
import fr.free.nrw.commons.review.ReviewHelper
import fr.free.nrw.commons.settings.Prefs

View file

@ -21,11 +21,8 @@ import android.widget.Toast;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentStatePagerAdapter;
import androidx.viewpager.widget.ViewPager;
import com.google.android.material.snackbar.Snackbar;
import fr.free.nrw.commons.CommonsApplication;
@ -69,23 +66,23 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple
private static CompositeDisposable compositeDisposable = new CompositeDisposable();
private FragmentMediaDetailPagerBinding binding;
FragmentMediaDetailPagerBinding binding;
private boolean editable;
private boolean isFeaturedImage;
private boolean isWikipediaButtonDisplayed;
boolean editable;
boolean isFeaturedImage;
boolean isWikipediaButtonDisplayed;
MediaDetailAdapter adapter;
private Bookmark bookmark;
private MediaDetailProvider provider;
private boolean isFromFeaturedRootFragment;
private int position;
Bookmark bookmark;
MediaDetailProvider provider;
boolean isFromFeaturedRootFragment;
int position;
/**
* ProgressBar used to indicate the loading status of media items.
*/
private ProgressBar imageProgressBar;
ProgressBar imageProgressBar;
private ArrayList<Integer> removedItems=new ArrayList<Integer>();
ArrayList<Integer> removedItems=new ArrayList<Integer>();
public void clearRemoved(){
removedItems.clear();
@ -127,7 +124,7 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple
binding.mediaDetailsPager.addOnPageChangeListener(this);
// Initialize the ProgressBar by finding it in the layout
imageProgressBar = binding.getRoot().findViewById(R.id.itemProgressBar);
adapter = new MediaDetailAdapter(getChildFragmentManager());
adapter = new MediaDetailAdapter(this, getChildFragmentManager());
// ActionBar is now supported in both activities - if this crashes something is quite wrong
final ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
@ -589,90 +586,4 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple
provider.refreshNominatedMedia(index);
}
public interface MediaDetailProvider {
Media getMediaAtPosition(int i);
int getTotalMediaCount();
Integer getContributionStateAt(int position);
// Reload media detail fragment once media is nominated
void refreshNominatedMedia(int index);
}
//FragmentStatePagerAdapter allows user to swipe across collection of images (no. of images undetermined)
private class MediaDetailAdapter extends FragmentStatePagerAdapter {
/**
* Keeps track of the current displayed fragment.
*/
private Fragment mCurrentFragment;
public MediaDetailAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int i) {
if (i == 0) {
// See bug https://code.google.com/p/android/issues/detail?id=27526
if(getActivity() == null) {
Timber.d("Skipping getItem. Returning as activity is destroyed!");
return null;
}
binding.mediaDetailsPager.postDelayed(() -> getActivity().invalidateOptionsMenu(), 5);
}
if (isFromFeaturedRootFragment) {
return MediaDetailFragment.forMedia(position+i, editable, isFeaturedImage, isWikipediaButtonDisplayed);
} else {
return MediaDetailFragment.forMedia(i, editable, isFeaturedImage, isWikipediaButtonDisplayed);
}
}
@Override
public int getCount() {
if (getActivity() == null) {
Timber.d("Skipping getCount. Returning as activity is destroyed!");
return 0;
}
return provider.getTotalMediaCount();
}
/**
* Get the currently displayed fragment.
* @return
*/
public Fragment getCurrentFragment() {
return mCurrentFragment;
}
/**
* If current fragment is of type MediaDetailFragment, return it, otherwise return null.
* @return MediaDetailFragment
*/
public MediaDetailFragment getCurrentMediaDetailFragment() {
if (mCurrentFragment instanceof MediaDetailFragment) {
return (MediaDetailFragment) mCurrentFragment;
}
return null;
}
/**
* Called to inform the adapter of which item is currently considered to be the "primary",
* that is the one show to the user as the current page.
* @param container
* @param position
* @param object
*/
@Override
public void setPrimaryItem(@NonNull final ViewGroup container, final int position,
@NonNull final Object object) {
// Update the current fragment if changed
if(getCurrentFragment() != object) {
mCurrentFragment = ((Fragment)object);
}
super.setPrimaryItem(container, position, object);
}
}
}

View file

@ -0,0 +1,15 @@
package fr.free.nrw.commons.media;
import fr.free.nrw.commons.Media;
public interface MediaDetailProvider {
Media getMediaAtPosition(int i);
int getTotalMediaCount();
Integer getContributionStateAt(int position);
// Reload media detail fragment once media is nominated
void refreshNominatedMedia(int index);
}

View file

@ -74,6 +74,7 @@ import fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType
import fr.free.nrw.commons.location.LocationUpdateListener
import fr.free.nrw.commons.media.MediaClient
import fr.free.nrw.commons.media.MediaDetailPagerFragment
import fr.free.nrw.commons.media.MediaDetailProvider
import fr.free.nrw.commons.navtab.NavTab
import fr.free.nrw.commons.nearby.BottomSheetAdapter
import fr.free.nrw.commons.nearby.BottomSheetAdapter.ItemClickListener
@ -150,7 +151,7 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(),
LocationUpdateListener,
LocationPermissionCallback,
ItemClickListener,
MediaDetailPagerFragment.MediaDetailProvider {
MediaDetailProvider {
var binding: FragmentNearbyParentBinding? = null
val mapEventsOverlay: MapEventsOverlay = MapEventsOverlay(object : MapEventsReceiver {

View file

@ -132,7 +132,7 @@ class MediaDetailFragmentUnitTests {
private lateinit var button: Button
@Mock
private lateinit var detailProvider: MediaDetailPagerFragment.MediaDetailProvider
private lateinit var detailProvider: MediaDetailProvider
@Mock
private lateinit var applicationKvStore: JsonKvStore