mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 12:23:58 +01:00
#3810 Convert DepictedImagesFragment to use Pagination - extract common media paging methods - convert to DepictedImages to use pagination
This commit is contained in:
parent
48a4e10170
commit
181a63a233
28 changed files with 211 additions and 893 deletions
|
|
@ -1,7 +1,7 @@
|
|||
package fr.free.nrw.commons
|
||||
|
||||
import androidx.core.text.HtmlCompat
|
||||
import fr.free.nrw.commons.depictions.Media.DepictedImagesFragment.PAGE_ID_PREFIX
|
||||
import fr.free.nrw.commons.media.PAGE_ID_PREFIX
|
||||
import fr.free.nrw.commons.media.IdAndCaptions
|
||||
import fr.free.nrw.commons.media.MediaClient
|
||||
import io.reactivex.Single
|
||||
|
|
|
|||
|
|
@ -1,27 +0,0 @@
|
|||
package fr.free.nrw.commons.depictions;
|
||||
|
||||
import dagger.Binds;
|
||||
import dagger.Module;
|
||||
import fr.free.nrw.commons.depictions.Media.DepictedImagesContract;
|
||||
import fr.free.nrw.commons.depictions.Media.DepictedImagesPresenter;
|
||||
import fr.free.nrw.commons.depictions.subClass.SubDepictionListContract;
|
||||
import fr.free.nrw.commons.depictions.subClass.SubDepictionListPresenter;
|
||||
|
||||
/**
|
||||
* The Dagger Module for explore:depictions related presenters and (some other objects maybe in future)
|
||||
*/
|
||||
@Module
|
||||
public abstract class DepictionModule {
|
||||
|
||||
@Binds
|
||||
public abstract DepictedImagesContract.UserActionListener bindsDepictedImagesPresenter(
|
||||
DepictedImagesPresenter
|
||||
presenter
|
||||
);
|
||||
|
||||
@Binds
|
||||
public abstract SubDepictionListContract.UserActionListener bindsSubDepictionListPresenter(
|
||||
SubDepictionListPresenter
|
||||
presenter
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package fr.free.nrw.commons.depictions
|
||||
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import fr.free.nrw.commons.depictions.Media.DepictedImagesContract
|
||||
import fr.free.nrw.commons.depictions.Media.DepictedImagesPresenter
|
||||
import fr.free.nrw.commons.depictions.subClass.SubDepictionListContract
|
||||
import fr.free.nrw.commons.depictions.subClass.SubDepictionListPresenter
|
||||
|
||||
/**
|
||||
* The Dagger Module for explore:depictions related presenters and (some other objects maybe in future)
|
||||
*/
|
||||
@Module
|
||||
abstract class DepictionModule {
|
||||
@Binds
|
||||
abstract fun SubDepictionListPresenter.bindsSubDepictionListPresenter()
|
||||
: SubDepictionListContract.UserActionListener
|
||||
|
||||
|
||||
@Binds
|
||||
abstract fun DepictedImagesPresenter.bindsDepictedImagesContractPresenter()
|
||||
: DepictedImagesContract.Presenter
|
||||
}
|
||||
|
|
@ -1,119 +0,0 @@
|
|||
package fr.free.nrw.commons.depictions;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.facebook.drawee.view.SimpleDraweeView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import fr.free.nrw.commons.Media;
|
||||
import fr.free.nrw.commons.R;
|
||||
|
||||
/**
|
||||
* Adapter for Items in DepictionDetailsActivity
|
||||
*/
|
||||
public class GridViewAdapter extends ArrayAdapter {
|
||||
|
||||
private List<Media> data;
|
||||
|
||||
public GridViewAdapter(Context context, int layoutResourceId, List<Media> data) {
|
||||
super(context, layoutResourceId, data);
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds more item to the list
|
||||
* Its triggered on scrolling down in the list
|
||||
* @param images
|
||||
*/
|
||||
public void addItems(List<Media> images) {
|
||||
if (data == null) {
|
||||
data = new ArrayList<>();
|
||||
}
|
||||
data.addAll(images);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the first item in the new list with old list and returns true if they are same
|
||||
* Its triggered on successful response of the fetch images API.
|
||||
* @param images
|
||||
*/
|
||||
public boolean containsAll(List<Media> images){
|
||||
if (images == null || images.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
if (data == null) {
|
||||
data = new ArrayList<>();
|
||||
return false;
|
||||
}
|
||||
if (data.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
String fileName = data.get(0).getFilename();
|
||||
String imageName = images.get(0).getFilename();
|
||||
return imageName.equals(fileName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return data == null || data.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the UI for the depicted image item
|
||||
* @param position
|
||||
* @param convertView
|
||||
* @param parent
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
|
||||
if (convertView == null) {
|
||||
convertView = LayoutInflater.from(getContext()).inflate(R.layout.layout_depict_image, null);
|
||||
}
|
||||
|
||||
Media item = data.get(position);
|
||||
SimpleDraweeView imageView = convertView.findViewById(R.id.depict_image_view);
|
||||
TextView fileName = convertView.findViewById(R.id.depict_image_title);
|
||||
TextView author = convertView.findViewById(R.id.depict_image_author);
|
||||
fileName.setText(item.getDisplayTitle());
|
||||
setAuthorView(item, author);
|
||||
imageView.setImageURI(item.getThumbUrl());
|
||||
return convertView;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Media getItem(int position) {
|
||||
return data.get(position);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows author information if its present
|
||||
* @param item
|
||||
* @param author
|
||||
*/
|
||||
private void setAuthorView(Media item, TextView author) {
|
||||
if (!TextUtils.isEmpty(item.getCreator())) {
|
||||
String uploadedByTemplate = getContext().getString(R.string.image_uploaded_by);
|
||||
|
||||
String uploadedBy = String.format(Locale.getDefault(), uploadedByTemplate, item.getCreator());
|
||||
author.setText(uploadedBy);
|
||||
} else {
|
||||
author.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,98 +0,0 @@
|
|||
package fr.free.nrw.commons.depictions.Media;
|
||||
|
||||
import android.widget.ListAdapter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import fr.free.nrw.commons.BasePresenter;
|
||||
import fr.free.nrw.commons.Media;
|
||||
|
||||
/**
|
||||
* Contract with which DepictedImagesFragment and its presenter will talk to each other
|
||||
*/
|
||||
public interface DepictedImagesContract {
|
||||
|
||||
interface View {
|
||||
|
||||
/**
|
||||
* Handles the UI updates for no internet scenario
|
||||
*/
|
||||
void handleNoInternet();
|
||||
|
||||
/**
|
||||
* Handles the UI updates for a error scenario
|
||||
*/
|
||||
void initErrorView();
|
||||
|
||||
/**
|
||||
* Initializes the adapter with a list of Media objects
|
||||
*
|
||||
* @param mediaList List of new Media to be displayed
|
||||
*/
|
||||
void setAdapter(List<Media> mediaList);
|
||||
|
||||
|
||||
/**
|
||||
* Display snackbar
|
||||
*/
|
||||
void showSnackBar();
|
||||
|
||||
/**
|
||||
* Inform the view that there are no more items to be loaded for this search query
|
||||
* or reset the isLastPage for the current query
|
||||
* @param isLastPage
|
||||
*/
|
||||
void setIsLastPage(boolean isLastPage);
|
||||
|
||||
/**
|
||||
* Set visibility of progressbar depending on the boolean value
|
||||
*/
|
||||
void progressBarVisible(Boolean value);
|
||||
|
||||
/**
|
||||
* It return an instance of gridView adapter which helps in extracting media details
|
||||
* used by the gridView
|
||||
*
|
||||
* @return GridView Adapter
|
||||
*/
|
||||
ListAdapter getAdapter();
|
||||
|
||||
/**
|
||||
* adds list to adapter
|
||||
*/
|
||||
void addItemsToAdapter(List<Media> media);
|
||||
|
||||
/**
|
||||
* Sets loading status depending on the boolean value
|
||||
*/
|
||||
void setLoadingStatus(Boolean value);
|
||||
|
||||
/**
|
||||
* Handles the success scenario
|
||||
* On first load, it initializes the grid view. On subsequent loads, it adds items to the adapter
|
||||
*
|
||||
* @param collection List of new Media to be displayed
|
||||
*/
|
||||
void handleSuccess(List<Media> collection);
|
||||
|
||||
}
|
||||
|
||||
interface UserActionListener extends BasePresenter<View> {
|
||||
|
||||
/**
|
||||
* Checks for internet connection and then initializes the grid view with first 10 images of that depiction
|
||||
*/
|
||||
void initList(String entityId);
|
||||
|
||||
/**
|
||||
* Fetches more images for the item and adds it to the grid view adapter
|
||||
* @param entityId
|
||||
*/
|
||||
void fetchMoreImages(String entityId);
|
||||
|
||||
/**
|
||||
* add items to query list
|
||||
*/
|
||||
void addItemsToQueryList(List<Media> collection);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package fr.free.nrw.commons.depictions.Media
|
||||
|
||||
import fr.free.nrw.commons.Media
|
||||
import fr.free.nrw.commons.explore.SearchFragmentContract
|
||||
|
||||
/**
|
||||
* Contract with which DepictedImagesFragment and its presenter will talk to each other
|
||||
*/
|
||||
interface DepictedImagesContract {
|
||||
interface View : SearchFragmentContract.View<Media>
|
||||
interface Presenter : SearchFragmentContract.Presenter<Media>
|
||||
}
|
||||
|
|
@ -1,249 +0,0 @@
|
|||
package fr.free.nrw.commons.depictions.Media;
|
||||
|
||||
import static android.view.View.GONE;
|
||||
import static android.view.View.VISIBLE;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AbsListView;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.GridView;
|
||||
import android.widget.ListAdapter;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import dagger.android.support.DaggerFragment;
|
||||
import fr.free.nrw.commons.Media;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.depictions.GridViewAdapter;
|
||||
import fr.free.nrw.commons.depictions.WikidataItemDetailsActivity;
|
||||
import fr.free.nrw.commons.utils.NetworkUtils;
|
||||
import fr.free.nrw.commons.utils.ViewUtil;
|
||||
import java.util.List;
|
||||
import javax.inject.Inject;
|
||||
import timber.log.Timber;
|
||||
|
||||
/**
|
||||
* Fragment for showing image list after selected an item from SearchActivity In Explore
|
||||
*/
|
||||
public class DepictedImagesFragment extends DaggerFragment implements DepictedImagesContract.View {
|
||||
|
||||
|
||||
public static final String PAGE_ID_PREFIX = "M";
|
||||
@BindView(R.id.statusMessage)
|
||||
TextView statusTextView;
|
||||
@BindView(R.id.loadingImagesProgressBar)
|
||||
ProgressBar progressBar;
|
||||
@BindView(R.id.depicts_image_list)
|
||||
GridView gridView;
|
||||
@BindView(R.id.parentLayout)
|
||||
RelativeLayout parentLayout;
|
||||
@Inject
|
||||
DepictedImagesPresenter presenter;
|
||||
private GridViewAdapter gridAdapter;
|
||||
private String entityId = null;
|
||||
private boolean isLastPage;
|
||||
private boolean isLoading = true;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
View v = inflater.inflate(R.layout.fragment_depict_image, container, false);
|
||||
ButterKnife.bind(this, v);
|
||||
presenter.onAttachView(this);
|
||||
return v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
gridView.setOnItemClickListener((AdapterView.OnItemClickListener) getActivity());
|
||||
initViews();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the UI elements for the fragment
|
||||
* Setup the grid view to and scroll listener for it
|
||||
*/
|
||||
private void initViews() {
|
||||
String depictsName = getArguments().getString("wikidataItemName");
|
||||
entityId = getArguments().getString("entityId");
|
||||
if (getArguments() != null && depictsName != null) {
|
||||
initList();
|
||||
setScrollListener();
|
||||
}
|
||||
}
|
||||
|
||||
private void initList() {
|
||||
presenter.initList(entityId);
|
||||
if (!NetworkUtils.isInternetConnectionEstablished(getContext())) {
|
||||
handleNoInternet();
|
||||
} else {
|
||||
presenter.initList(entityId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the UI updates for no internet scenario
|
||||
*/
|
||||
@Override
|
||||
public void handleNoInternet() {
|
||||
progressBar.setVisibility(GONE);
|
||||
if (gridAdapter == null || gridAdapter.isEmpty()) {
|
||||
statusTextView.setVisibility(VISIBLE);
|
||||
statusTextView.setText(getString(R.string.no_internet));
|
||||
} else {
|
||||
ViewUtil.showShortSnackbar(parentLayout, R.string.no_internet);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the UI updates for a error scenario
|
||||
*/
|
||||
@Override
|
||||
public void initErrorView() {
|
||||
progressBar.setVisibility(GONE);
|
||||
if (gridAdapter == null || gridAdapter.isEmpty()) {
|
||||
statusTextView.setVisibility(VISIBLE);
|
||||
statusTextView.setText(getString(R.string.no_images_found));
|
||||
} else {
|
||||
statusTextView.setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the scroll listener for the grid view so that more images are fetched when the user scrolls down
|
||||
* Checks if the item has more images before loading
|
||||
* Also checks whether images are currently being fetched before triggering another request
|
||||
*/
|
||||
private void setScrollListener() {
|
||||
gridView.setOnScrollListener(new AbsListView.OnScrollListener() {
|
||||
@Override
|
||||
public void onScrollStateChanged(AbsListView view, int scrollState) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
|
||||
if (!isLastPage && !isLoading && (firstVisibleItem + visibleItemCount >= totalItemCount)) {
|
||||
isLoading = true;
|
||||
if (!NetworkUtils.isInternetConnectionEstablished(getContext())) {
|
||||
handleNoInternet();
|
||||
} else {
|
||||
presenter.fetchMoreImages(entityId);
|
||||
}
|
||||
}
|
||||
if (isLastPage) {
|
||||
progressBar.setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Display snackbar
|
||||
*/
|
||||
@Override
|
||||
public void showSnackBar() {
|
||||
ViewUtil.showShortSnackbar(parentLayout, R.string.error_loading_images);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set visibility of progressbar depending on the boolean value
|
||||
*/
|
||||
@Override
|
||||
public void progressBarVisible(Boolean value) {
|
||||
if (value) {
|
||||
progressBar.setVisibility(VISIBLE);
|
||||
} else {
|
||||
progressBar.setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* It return an instance of gridView adapter which helps in extracting media details
|
||||
* used by the gridView
|
||||
*
|
||||
* @return GridView Adapter
|
||||
*/
|
||||
@Override
|
||||
public ListAdapter getAdapter() {
|
||||
return gridAdapter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the adapter with a list of Media objects
|
||||
*
|
||||
* @param mediaList List of new Media to be displayed
|
||||
*/
|
||||
@Override
|
||||
public void setAdapter(List<Media> mediaList) {
|
||||
gridAdapter = new fr.free.nrw.commons.depictions.GridViewAdapter(getContext(), R.layout.layout_depict_image, mediaList);
|
||||
gridView.setAdapter(gridAdapter);
|
||||
}
|
||||
|
||||
/**
|
||||
* adds list to adapter
|
||||
*/
|
||||
@Override
|
||||
public void addItemsToAdapter(List<Media> media) {
|
||||
gridAdapter.addAll(media);
|
||||
gridAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets loading status depending on the boolean value
|
||||
*/
|
||||
@Override
|
||||
public void setLoadingStatus(Boolean value) {
|
||||
if (!value) {
|
||||
statusTextView.setVisibility(GONE);
|
||||
}
|
||||
isLoading = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inform the view that there are no more items to be loaded for this search query
|
||||
* or reset the isLastPage for the current query
|
||||
* @param isLastPage
|
||||
*/
|
||||
@Override
|
||||
public void setIsLastPage(boolean isLastPage) {
|
||||
this.isLastPage=isLastPage;
|
||||
progressBar.setVisibility(GONE);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handles the success scenario
|
||||
* On first load, it initializes the grid view. On subsequent loads, it adds items to the adapter
|
||||
*
|
||||
* @param collection List of new Media to be displayed
|
||||
*/
|
||||
@Override
|
||||
public void handleSuccess(List<Media> collection) {
|
||||
presenter.addItemsToQueryList(collection);
|
||||
if (gridAdapter == null) {
|
||||
setAdapter(collection);
|
||||
} else {
|
||||
if (gridAdapter.containsAll(collection)) {
|
||||
return;
|
||||
}
|
||||
gridAdapter.addItems(collection);
|
||||
|
||||
try {
|
||||
((WikidataItemDetailsActivity) getContext()).viewPagerNotifyDataSetChanged();
|
||||
} catch (RuntimeException e) {
|
||||
Timber.e(e);
|
||||
}
|
||||
}
|
||||
progressBar.setVisibility(GONE);
|
||||
isLoading = false;
|
||||
statusTextView.setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package fr.free.nrw.commons.depictions.Media
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import fr.free.nrw.commons.depictions.WikidataItemDetailsActivity
|
||||
import fr.free.nrw.commons.explore.media.PageableMediaFragment
|
||||
import javax.inject.Inject
|
||||
|
||||
class DepictedImagesFragment : PageableMediaFragment(), DepictedImagesContract.View {
|
||||
@Inject
|
||||
lateinit var presenter: DepictedImagesContract.Presenter
|
||||
|
||||
override val injectedPresenter: DepictedImagesContract.Presenter
|
||||
get() = presenter
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
injectedPresenter.onQueryUpdated(arguments!!.getString("entityId")!!)
|
||||
}
|
||||
|
||||
override fun onItemClicked(position: Int) {
|
||||
(activity as WikidataItemDetailsActivity).onMediaClicked(position)
|
||||
}
|
||||
|
||||
override fun notifyViewPager() {
|
||||
(activity as WikidataItemDetailsActivity).viewPagerNotifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,144 +0,0 @@
|
|||
package fr.free.nrw.commons.depictions.Media;
|
||||
|
||||
import static fr.free.nrw.commons.di.CommonsApplicationModule.IO_THREAD;
|
||||
import static fr.free.nrw.commons.di.CommonsApplicationModule.MAIN_THREAD;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import fr.free.nrw.commons.Media;
|
||||
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
||||
import fr.free.nrw.commons.media.MediaClient;
|
||||
import io.reactivex.Scheduler;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import timber.log.Timber;
|
||||
|
||||
/**
|
||||
* Presenter for DepictedImagesFragment
|
||||
*/
|
||||
public class DepictedImagesPresenter implements DepictedImagesContract.UserActionListener {
|
||||
|
||||
private static final DepictedImagesContract.View DUMMY = (DepictedImagesContract.View) Proxy
|
||||
.newProxyInstance(
|
||||
DepictedImagesContract.View.class.getClassLoader(),
|
||||
new Class[]{DepictedImagesContract.View.class},
|
||||
(proxy, method, methodArgs) -> null);
|
||||
MediaClient mediaClient;
|
||||
@Named("default_preferences")
|
||||
JsonKvStore depictionKvStore;
|
||||
private final Scheduler ioScheduler;
|
||||
private final Scheduler mainThreadScheduler;
|
||||
private DepictedImagesContract.View view = DUMMY;
|
||||
private CompositeDisposable compositeDisposable = new CompositeDisposable();
|
||||
/**
|
||||
* Wikibase enitityId for the depicted Item
|
||||
* Ex: Q9394
|
||||
*/
|
||||
private List<Media> queryList = new ArrayList<>();
|
||||
|
||||
@Inject
|
||||
public DepictedImagesPresenter(@Named("default_preferences") JsonKvStore depictionKvStore,
|
||||
MediaClient mediaClient,
|
||||
@Named(IO_THREAD) Scheduler ioScheduler,
|
||||
@Named(MAIN_THREAD) Scheduler mainThreadScheduler) {
|
||||
this.depictionKvStore = depictionKvStore;
|
||||
this.ioScheduler = ioScheduler;
|
||||
this.mainThreadScheduler = mainThreadScheduler;
|
||||
this.mediaClient = mediaClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttachView(DepictedImagesContract.View view) {
|
||||
this.view = view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetachView() {
|
||||
this.view = DUMMY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for internet connection and then initializes the grid view with first 10 images of that depiction
|
||||
*/
|
||||
@SuppressLint("CheckResult")
|
||||
@Override
|
||||
public void initList(String entityId) {
|
||||
view.setLoadingStatus(true);
|
||||
view.progressBarVisible(true);
|
||||
view.setIsLastPage(false);
|
||||
compositeDisposable.add(mediaClient.fetchImagesForDepictedItem(entityId, 0)
|
||||
.subscribeOn(ioScheduler)
|
||||
.observeOn(mainThreadScheduler)
|
||||
.subscribe(this::handleSuccess, this::handleError));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches more images for the item and adds it to the grid view adapter
|
||||
* @param entityId
|
||||
*/
|
||||
@SuppressLint("CheckResult")
|
||||
@Override
|
||||
public void fetchMoreImages(String entityId) {
|
||||
view.progressBarVisible(true);
|
||||
compositeDisposable.add(mediaClient.fetchImagesForDepictedItem(entityId, queryList.size())
|
||||
.subscribeOn(ioScheduler)
|
||||
.observeOn(mainThreadScheduler)
|
||||
.subscribe(this::handlePaginationSuccess, this::handleError));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the success scenario
|
||||
* it initializes the recycler view by adding items to the adapter
|
||||
*/
|
||||
private void handlePaginationSuccess(List<Media> media) {
|
||||
queryList.addAll(media);
|
||||
view.progressBarVisible(false);
|
||||
view.addItemsToAdapter(media);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs and handles API error scenario
|
||||
*
|
||||
* @param throwable
|
||||
*/
|
||||
public void handleError(Throwable throwable) {
|
||||
Timber.e(throwable, "Error occurred while loading images inside items");
|
||||
try {
|
||||
view.initErrorView();
|
||||
view.showSnackBar();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the success scenario
|
||||
* On first load, it initializes the grid view. On subsequent loads, it adds items to the adapter
|
||||
* @param collection List of new Media to be displayed
|
||||
*/
|
||||
public void handleSuccess(List<Media> collection) {
|
||||
if (collection == null || collection.isEmpty()) {
|
||||
if (queryList.isEmpty()) {
|
||||
view.initErrorView();
|
||||
} else {
|
||||
view.setIsLastPage(true);
|
||||
}
|
||||
} else {
|
||||
this.queryList.addAll(collection);
|
||||
view.handleSuccess(collection);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* add items to query list
|
||||
*/
|
||||
@Override
|
||||
public void addItemsToQueryList(List<Media> collection) {
|
||||
queryList.addAll(collection);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package fr.free.nrw.commons.depictions.Media
|
||||
|
||||
import fr.free.nrw.commons.Media
|
||||
import fr.free.nrw.commons.di.CommonsApplicationModule
|
||||
import fr.free.nrw.commons.explore.BaseSearchPresenter
|
||||
import io.reactivex.Scheduler
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Named
|
||||
|
||||
/**
|
||||
* Presenter for DepictedImagesFragment
|
||||
*/
|
||||
class DepictedImagesPresenter @Inject constructor(
|
||||
@Named(CommonsApplicationModule.MAIN_THREAD) mainThreadScheduler: Scheduler,
|
||||
dataSourceFactory: PageableDepictedMediaDataSource
|
||||
) : BaseSearchPresenter<Media>(mainThreadScheduler, dataSourceFactory),
|
||||
DepictedImagesContract.Presenter
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package fr.free.nrw.commons.depictions.Media
|
||||
|
||||
import fr.free.nrw.commons.Media
|
||||
import fr.free.nrw.commons.explore.LiveDataConverter
|
||||
import fr.free.nrw.commons.explore.PageableDataSource
|
||||
import fr.free.nrw.commons.explore.depictions.LoadFunction
|
||||
import fr.free.nrw.commons.media.MediaClient
|
||||
import javax.inject.Inject
|
||||
|
||||
class PageableDepictedMediaDataSource @Inject constructor(
|
||||
liveDataConverter: LiveDataConverter,
|
||||
private val mediaClient: MediaClient
|
||||
) : PageableDataSource<Media>(liveDataConverter) {
|
||||
override val loadFunction: LoadFunction<Media> = { loadSize: Int, startPosition: Int ->
|
||||
mediaClient.fetchImagesForDepictedItem(query, loadSize, startPosition).blockingGet()
|
||||
}
|
||||
}
|
||||
|
|
@ -4,20 +4,13 @@ import android.content.Context;
|
|||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
import fr.free.nrw.commons.Media;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.depictions.Media.DepictedImagesFragment;
|
||||
|
|
@ -26,11 +19,13 @@ import fr.free.nrw.commons.explore.ViewPagerAdapter;
|
|||
import fr.free.nrw.commons.media.MediaDetailPagerFragment;
|
||||
import fr.free.nrw.commons.theme.NavigationBaseActivity;
|
||||
import fr.free.nrw.commons.upload.structure.depictions.DepictedItem;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Activity to show depiction media, parent classes and child classes of depicted items in Explore
|
||||
*/
|
||||
public class WikidataItemDetailsActivity extends NavigationBaseActivity implements MediaDetailPagerFragment.MediaDetailProvider, AdapterView.OnItemClickListener {
|
||||
public class WikidataItemDetailsActivity extends NavigationBaseActivity implements MediaDetailPagerFragment.MediaDetailProvider {
|
||||
private FragmentManager supportFragmentManager;
|
||||
private DepictedImagesFragment depictionImagesListFragment;
|
||||
private MediaDetailPagerFragment mediaDetailPagerFragment;
|
||||
|
|
@ -121,11 +116,11 @@ public class WikidataItemDetailsActivity extends NavigationBaseActivity implemen
|
|||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Shows media detail fragment when user clicks on any image in the list
|
||||
*/
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
public void onMediaClicked(int position) {
|
||||
tabLayout.setVisibility(View.GONE);
|
||||
viewPager.setVisibility(View.GONE);
|
||||
mediaContainer.setVisibility(View.VISIBLE);
|
||||
|
|
@ -152,12 +147,7 @@ public class WikidataItemDetailsActivity extends NavigationBaseActivity implemen
|
|||
*/
|
||||
@Override
|
||||
public Media getMediaAtPosition(int i) {
|
||||
if (depictionImagesListFragment.getAdapter() == null) {
|
||||
// not yet ready to return data
|
||||
return null;
|
||||
} else {
|
||||
return (Media) depictionImagesListFragment.getAdapter().getItem(i);
|
||||
}
|
||||
return depictionImagesListFragment.getImageAtPosition(i);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -182,10 +172,7 @@ public class WikidataItemDetailsActivity extends NavigationBaseActivity implemen
|
|||
*/
|
||||
@Override
|
||||
public int getTotalMediaCount() {
|
||||
if (depictionImagesListFragment.getAdapter() == null) {
|
||||
return 0;
|
||||
}
|
||||
return depictionImagesListFragment.getAdapter().getCount();
|
||||
return depictionImagesListFragment.getTotalImagesCount();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ abstract class BaseSearchFragment<T> : CommonsDaggerSupportFragment(),
|
|||
|
||||
abstract val pagedListAdapter: PagedListAdapter<T, *>
|
||||
abstract val injectedPresenter: SearchFragmentContract.Presenter<T>
|
||||
abstract val emptyTemplateTextId: Int
|
||||
abstract val errorTextId: Int
|
||||
private val loadingAdapter by lazy { FooterAdapter { injectedPresenter.retryFailedRequest() } }
|
||||
private val mergeAdapter by lazy { MergeAdapter(pagedListAdapter, loadingAdapter) }
|
||||
|
|
@ -60,7 +59,6 @@ abstract class BaseSearchFragment<T> : CommonsDaggerSupportFragment(),
|
|||
injectedPresenter.onAttachView(this)
|
||||
}
|
||||
|
||||
|
||||
override fun onDetach() {
|
||||
super.onDetach()
|
||||
injectedPresenter.onDetachView()
|
||||
|
|
@ -83,10 +81,12 @@ abstract class BaseSearchFragment<T> : CommonsDaggerSupportFragment(),
|
|||
}
|
||||
|
||||
override fun showEmptyText(query: String) {
|
||||
contentNotFound.text = getString(emptyTemplateTextId, query)
|
||||
contentNotFound.text = getEmptyText(query)
|
||||
contentNotFound.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
abstract fun getEmptyText(query: String):String
|
||||
|
||||
override fun hideEmptyText() {
|
||||
contentNotFound.visibility = View.GONE
|
||||
}
|
||||
|
|
|
|||
|
|
@ -269,9 +269,7 @@ public class SearchActivity extends NavigationBaseActivity
|
|||
*/
|
||||
@Override
|
||||
public void requestMoreImages() {
|
||||
if (searchMediaFragment!=null){
|
||||
searchMediaFragment.requestMoreImages();
|
||||
}
|
||||
//unneeded
|
||||
}
|
||||
|
||||
@Override protected void onDestroy() {
|
||||
|
|
|
|||
|
|
@ -14,18 +14,14 @@ import fr.free.nrw.commons.explore.media.SearchMediaFragmentPresenter
|
|||
@Module
|
||||
abstract class SearchModule {
|
||||
@Binds
|
||||
abstract fun bindsSearchDepictionsFragmentPresenter(
|
||||
presenter: SearchDepictionsFragmentPresenter
|
||||
): SearchDepictionsFragmentContract.Presenter
|
||||
abstract fun SearchDepictionsFragmentPresenter.bindsSearchDepictionsFragmentPresenter()
|
||||
: SearchDepictionsFragmentContract.Presenter
|
||||
|
||||
@Binds
|
||||
abstract fun bindsSearchCategoriesFragmentPresenter(
|
||||
presenter: SearchCategoriesFragmentPresenter
|
||||
): SearchCategoriesFragmentContract.Presenter
|
||||
abstract fun SearchCategoriesFragmentPresenter.bindsSearchCategoriesFragmentPresenter()
|
||||
: SearchCategoriesFragmentContract.Presenter
|
||||
|
||||
@Binds
|
||||
abstract fun bindsSearchMediaFragmentPresenter(
|
||||
presenter: SearchMediaFragmentPresenter
|
||||
): SearchMediaFragmentContract.Presenter
|
||||
|
||||
abstract fun SearchMediaFragmentPresenter.bindsSearchMediaFragmentPresenter()
|
||||
: SearchMediaFragmentContract.Presenter
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,8 +13,6 @@ class SearchCategoryFragment : BaseSearchFragment<String>() {
|
|||
@Inject
|
||||
lateinit var presenter: SearchCategoriesFragmentContract.Presenter
|
||||
|
||||
override val emptyTemplateTextId: Int = R.string.categories_not_found
|
||||
|
||||
override val errorTextId: Int = R.string.error_loading_categories
|
||||
|
||||
override val injectedPresenter: SearchFragmentContract.Presenter<String>
|
||||
|
|
@ -23,4 +21,6 @@ class SearchCategoryFragment : BaseSearchFragment<String>() {
|
|||
override val pagedListAdapter by lazy {
|
||||
PagedSearchCategoriesAdapter { CategoryDetailsActivity.startYourself(context, it) }
|
||||
}
|
||||
|
||||
override fun getEmptyText(query: String) = getString(R.string.categories_not_found, query)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,8 +14,6 @@ class SearchDepictionsFragment : BaseSearchFragment<DepictedItem>(),
|
|||
@Inject
|
||||
lateinit var presenter: SearchDepictionsFragmentContract.Presenter
|
||||
|
||||
override val emptyTemplateTextId: Int = R.string.depictions_not_found
|
||||
|
||||
override val errorTextId: Int = R.string.error_loading_depictions
|
||||
|
||||
override val injectedPresenter: SearchDepictionsFragmentContract.Presenter
|
||||
|
|
@ -24,4 +22,6 @@ class SearchDepictionsFragment : BaseSearchFragment<DepictedItem>(),
|
|||
override val pagedListAdapter by lazy {
|
||||
DepictionAdapter { WikidataItemDetailsActivity.startYourself(context, it) }
|
||||
}
|
||||
|
||||
override fun getEmptyText(query: String) = getString(R.string.depictions_not_found, query)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
package fr.free.nrw.commons.explore.media
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import fr.free.nrw.commons.Media
|
||||
import fr.free.nrw.commons.R
|
||||
import fr.free.nrw.commons.explore.BaseSearchFragment
|
||||
import kotlinx.android.synthetic.main.fragment_search_paginated.*
|
||||
|
||||
|
||||
abstract class PageableMediaFragment : BaseSearchFragment<Media>() {
|
||||
override val pagedListAdapter by lazy { PagedMediaAdapter(::onItemClicked) }
|
||||
|
||||
override val errorTextId: Int = R.string.error_loading_images
|
||||
|
||||
override fun getEmptyText(query: String) = getString(R.string.no_images_found)
|
||||
|
||||
protected abstract fun onItemClicked(position: Int)
|
||||
|
||||
protected abstract fun notifyViewPager()
|
||||
|
||||
private val simpleDataObserver = SimpleDataObserver { notifyViewPager() }
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
pagedListAdapter.registerAdapterDataObserver(simpleDataObserver)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
pagedListAdapter.unregisterAdapterDataObserver(simpleDataObserver)
|
||||
}
|
||||
|
||||
fun getImageAtPosition(position: Int): Media? =
|
||||
pagedListAdapter.currentList?.get(position)?.takeIf { it.filename != null }
|
||||
.also {
|
||||
pagedListAdapter.currentList?.loadAround(position)
|
||||
paginatedSearchResultsList.scrollToPosition(position)
|
||||
}
|
||||
|
||||
fun getTotalImagesCount(): Int = pagedListAdapter.itemCount
|
||||
}
|
||||
|
|
@ -10,7 +10,7 @@ import fr.free.nrw.commons.explore.BaseViewHolder
|
|||
import fr.free.nrw.commons.explore.inflate
|
||||
import kotlinx.android.synthetic.main.layout_category_images.*
|
||||
|
||||
class SearchImagesAdapter(private val onImageClicked: (Int) -> Unit) :
|
||||
class PagedMediaAdapter(private val onImageClicked: (Int) -> Unit) :
|
||||
PagedListAdapter<Media, SearchImagesViewHolder>(object : DiffUtil.ItemCallback<Media>() {
|
||||
override fun areItemsTheSame(oldItem: Media, newItem: Media) =
|
||||
oldItem.pageId == newItem.pageId
|
||||
|
|
@ -1,57 +1,26 @@
|
|||
package fr.free.nrw.commons.explore.media
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import fr.free.nrw.commons.Media
|
||||
import fr.free.nrw.commons.R
|
||||
import fr.free.nrw.commons.explore.BaseSearchFragment
|
||||
import fr.free.nrw.commons.category.CategoryImagesCallback
|
||||
import fr.free.nrw.commons.explore.SearchActivity
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Displays the image search screen.
|
||||
*/
|
||||
class SearchMediaFragment : BaseSearchFragment<Media>(), SearchMediaFragmentContract.View {
|
||||
class SearchMediaFragment : PageableMediaFragment(), SearchMediaFragmentContract.View {
|
||||
@Inject
|
||||
lateinit var presenter: SearchMediaFragmentContract.Presenter
|
||||
|
||||
override val emptyTemplateTextId: Int = R.string.depictions_not_found
|
||||
|
||||
override val errorTextId: Int = R.string.error_loading_images
|
||||
|
||||
override val injectedPresenter: SearchMediaFragmentContract.Presenter
|
||||
get() = presenter
|
||||
|
||||
override val pagedListAdapter by lazy {
|
||||
SearchImagesAdapter {
|
||||
(context as SearchActivity?)!!.onSearchImageClicked(it)
|
||||
}
|
||||
override fun onItemClicked(position: Int) {
|
||||
(context as SearchActivity?)!!.onSearchImageClicked(position)
|
||||
}
|
||||
|
||||
private val simpleDataObserver = SimpleDataObserver { notifyViewPager() }
|
||||
|
||||
fun requestMoreImages() {
|
||||
// This functionality is replaced by a dataSetObserver and by using loadAround
|
||||
override fun notifyViewPager() {
|
||||
(activity as CategoryImagesCallback).viewPagerNotifyDataSetChanged()
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
pagedListAdapter.registerAdapterDataObserver(simpleDataObserver)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
pagedListAdapter.unregisterAdapterDataObserver(simpleDataObserver)
|
||||
}
|
||||
|
||||
private fun notifyViewPager() {
|
||||
(activity as SearchActivity).viewPagerNotifyDataSetChanged()
|
||||
}
|
||||
|
||||
fun getImageAtPosition(position: Int): Media? =
|
||||
pagedListAdapter.currentList?.get(position)?.takeIf { it.filename != null }
|
||||
.also { pagedListAdapter.currentList?.loadAround(position) }
|
||||
|
||||
fun getTotalImagesCount(): Int = pagedListAdapter.itemCount
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package fr.free.nrw.commons.media
|
|||
|
||||
import fr.free.nrw.commons.BuildConfig
|
||||
import fr.free.nrw.commons.Media
|
||||
import fr.free.nrw.commons.depictions.Media.DepictedImagesFragment.PAGE_ID_PREFIX
|
||||
import fr.free.nrw.commons.explore.media.MediaConverter
|
||||
import fr.free.nrw.commons.utils.CommonsDateUtil
|
||||
import io.reactivex.Single
|
||||
|
|
@ -13,6 +12,8 @@ import java.util.*
|
|||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
const val PAGE_ID_PREFIX = "M"
|
||||
|
||||
/**
|
||||
* Media Client to handle custom calls to Commons MediaWiki APIs
|
||||
*/
|
||||
|
|
@ -104,11 +105,18 @@ class MediaClient @Inject constructor(
|
|||
/**
|
||||
* @return list of images for a particular depict entity
|
||||
*/
|
||||
fun fetchImagesForDepictedItem(query: String, sroffset: Int): Single<List<Media>> {
|
||||
return responseToMediaList(mediaInterface.fetchImagesForDepictedItem(
|
||||
"haswbstatement:" + BuildConfig.DEPICTS_PROPERTY + "=" + query,
|
||||
sroffset.toString()
|
||||
))
|
||||
fun fetchImagesForDepictedItem(
|
||||
query: String,
|
||||
srlimit: Int,
|
||||
sroffset: Int
|
||||
): Single<List<Media>> {
|
||||
return responseToMediaList(
|
||||
mediaInterface.fetchImagesForDepictedItem(
|
||||
"haswbstatement:" + BuildConfig.DEPICTS_PROPERTY + "=" + query,
|
||||
srlimit.toString(),
|
||||
sroffset.toString()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -117,14 +117,14 @@ public interface MediaInterface {
|
|||
|
||||
/**
|
||||
* Fetches list of images from a depiction entity
|
||||
*
|
||||
* @param query depictionEntityId
|
||||
* @param query depictionEntityId
|
||||
* @param srlimit the number of items to fetch
|
||||
* @param sroffset number od depictions already fetched, this is useful in implementing pagination
|
||||
*/
|
||||
|
||||
@GET("w/api.php?action=query&format=json&formatversion=2" + //Basic parameters
|
||||
"&generator=search&gsrnamespace=6" + //Search parameters
|
||||
MEDIA_PARAMS)
|
||||
Single<MwQueryResponse> fetchImagesForDepictedItem(@Query("gsrsearch") String query, @Query("gsroffset") String sroffset);
|
||||
Single<MwQueryResponse> fetchImagesForDepictedItem(@Query("gsrsearch") String query,
|
||||
@Query("gsrlimit")String srlimit, @Query("gsroffset") String sroffset);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
package fr.free.nrw.commons.wikidata;
|
||||
|
||||
import static fr.free.nrw.commons.depictions.Media.DepictedImagesFragment.PAGE_ID_PREFIX;
|
||||
import static fr.free.nrw.commons.media.MediaClientKt.PAGE_ID_PREFIX;
|
||||
import static fr.free.nrw.commons.di.NetworkingModule.NAMED_COMMONS_CSRF;
|
||||
|
||||
import fr.free.nrw.commons.upload.UploadResult;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package fr.free.nrw.commons.wikidata;
|
||||
|
||||
import static fr.free.nrw.commons.depictions.Media.DepictedImagesFragment.PAGE_ID_PREFIX;
|
||||
|
||||
import static fr.free.nrw.commons.media.MediaClientKt.PAGE_ID_PREFIX;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
|
|
|
|||
|
|
@ -1,40 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/parentLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_below="@+id/mediaContainer"
|
||||
android:background="?attr/mainBackground"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/statusMessage"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_gravity="center"
|
||||
android:text="@string/waiting_first_sync"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/loadingImagesProgressBar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:visibility="gone" />
|
||||
|
||||
<GridView
|
||||
android:id="@+id/depicts_image_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:columnWidth="240dp"
|
||||
android:fadingEdge="none"
|
||||
android:fastScrollEnabled="true"
|
||||
android:listSelector="@null"
|
||||
android:numColumns="auto_fit"
|
||||
android:stretchMode="columnWidth" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="2dp"
|
||||
android:paddingBottom="0dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/depict_images_sequence_number"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end|bottom"
|
||||
android:textColor="#33FFFFFF"
|
||||
android:textSize="98sp"
|
||||
android:typeface="serif" />
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
android:id="@+id/depict_image_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="240dp"
|
||||
app:actualImageScaleType="centerCrop" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center|bottom"
|
||||
android:background="#AA000000"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/small_gap">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/depict_progress"
|
||||
style="@style/ProgressBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:indeterminateOnly="false"
|
||||
android:max="100"
|
||||
android:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/depict_image_title"
|
||||
style="?android:textAppearanceLarge"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="#FFFFFFFF" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/depict_image_author"
|
||||
style="?android:textAppearanceMedium"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="#FFFFFFFF" />
|
||||
</LinearLayout>
|
||||
|
||||
</FrameLayout>
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
package fr.free.nrw.commons.depictions
|
||||
|
||||
import fr.free.nrw.commons.Media
|
||||
import fr.free.nrw.commons.depictions.Media.DepictedImagesFragment
|
||||
import fr.free.nrw.commons.depictions.Media.DepictedImagesPresenter
|
||||
import fr.free.nrw.commons.kvstore.JsonKvStore
|
||||
import fr.free.nrw.commons.media.MediaClient
|
||||
import io.reactivex.Single
|
||||
import io.reactivex.schedulers.TestScheduler
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.mockito.ArgumentMatchers
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
class DepictedImagesPresenterTest {
|
||||
|
||||
@Mock
|
||||
internal lateinit var view: DepictedImagesFragment
|
||||
|
||||
lateinit var depictedImagesPresenter: DepictedImagesPresenter
|
||||
|
||||
@Mock
|
||||
lateinit var jsonKvStore: JsonKvStore
|
||||
|
||||
@Mock
|
||||
lateinit var mediaClient: MediaClient
|
||||
|
||||
lateinit var testScheduler: TestScheduler
|
||||
|
||||
val mediaList: ArrayList<Media> = ArrayList()
|
||||
|
||||
@Mock
|
||||
lateinit var mediaItem: Media
|
||||
|
||||
var testSingle: Single<List<Media>>? = null
|
||||
|
||||
|
||||
@Before
|
||||
@Throws(Exception::class)
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
testScheduler = TestScheduler()
|
||||
mediaList.add(mediaItem)
|
||||
testSingle = Single.just(mediaList)
|
||||
depictedImagesPresenter = DepictedImagesPresenter(jsonKvStore,
|
||||
mediaClient, testScheduler, testScheduler)
|
||||
depictedImagesPresenter.onAttachView(view)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun initList() {
|
||||
Mockito.`when`(
|
||||
mediaClient.fetchImagesForDepictedItem(ArgumentMatchers.anyString(),
|
||||
ArgumentMatchers.anyInt())
|
||||
).thenReturn(testSingle)
|
||||
depictedImagesPresenter.initList("rabbit")
|
||||
depictedImagesPresenter.handleSuccess(mediaList)
|
||||
verify(view)?.handleSuccess(mediaList)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package fr.free.nrw.commons.depictions.Media
|
||||
|
||||
import com.nhaarman.mockitokotlin2.mock
|
||||
import com.nhaarman.mockitokotlin2.whenever
|
||||
import fr.free.nrw.commons.media.MediaClient
|
||||
import io.reactivex.Single
|
||||
import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.hamcrest.Matchers.`is`
|
||||
import org.junit.Test
|
||||
|
||||
class PageableDepictedMediaDataSourceTest{
|
||||
@Test
|
||||
fun `loadFunction loads Media`() {
|
||||
val mediaClient = mock<MediaClient>()
|
||||
whenever(mediaClient.fetchImagesForDepictedItem("test",0,1))
|
||||
.thenReturn(Single.just(emptyList()))
|
||||
val pageableDepictedMediaDataSource = PageableDepictedMediaDataSource(mock(), mediaClient)
|
||||
pageableDepictedMediaDataSource.onQueryUpdated("test")
|
||||
assertThat(pageableDepictedMediaDataSource.loadFunction(0,1), `is`(emptyList()))
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue