mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 20:33:53 +01:00
#3822 Convert SubCategoryImagesListFragment to use Pagination - convert parent categories - delete list fragment - creat base class to support continuation requests in clients
This commit is contained in:
parent
5b87ed569c
commit
0f091600e8
30 changed files with 188 additions and 410 deletions
|
|
@ -140,9 +140,6 @@ public class BookmarksActivity extends NavigationBaseActivity
|
|||
return adapter.getMediaAdapter().getCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestMoreImages() { }
|
||||
|
||||
@Override
|
||||
public void onMediaClicked(int position) {
|
||||
//TODO use with pagination
|
||||
|
|
|
|||
|
|
@ -7,15 +7,14 @@ import javax.inject.Singleton
|
|||
|
||||
const val CATEGORY_PREFIX = "Category:"
|
||||
const val SUB_CATEGORY_CONTINUATION_PREFIX = "sub_category_"
|
||||
const val PARENT_CATEGORY_CONTINUATION_PREFIX = "parent_category_"
|
||||
|
||||
/**
|
||||
* Category Client to handle custom calls to Commons MediaWiki APIs
|
||||
*/
|
||||
@Singleton
|
||||
class CategoryClient @Inject constructor(private val categoryInterface: CategoryInterface) {
|
||||
|
||||
private val continuationStore: MutableMap<String, Map<String, String>?> = mutableMapOf()
|
||||
private val continuationExists: MutableMap<String, Boolean> = mutableMapOf()
|
||||
class CategoryClient @Inject constructor(private val categoryInterface: CategoryInterface) :
|
||||
ContinuationClient<MwQueryResponse, String>() {
|
||||
|
||||
/**
|
||||
* Searches for categories containing the specified string.
|
||||
|
|
@ -28,9 +27,7 @@ class CategoryClient @Inject constructor(private val categoryInterface: Category
|
|||
@JvmOverloads
|
||||
fun searchCategories(filter: String?, itemLimit: Int, offset: Int = 0):
|
||||
Single<List<String>> {
|
||||
return responseToCategoryName(
|
||||
categoryInterface.searchCategories(filter, itemLimit, offset)
|
||||
)
|
||||
return responseMapper(categoryInterface.searchCategories(filter, itemLimit, offset))
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -44,7 +41,7 @@ class CategoryClient @Inject constructor(private val categoryInterface: Category
|
|||
@JvmOverloads
|
||||
fun searchCategoriesForPrefix(prefix: String?, itemLimit: Int, offset: Int = 0):
|
||||
Single<List<String>> {
|
||||
return responseToCategoryName(
|
||||
return responseMapper(
|
||||
categoryInterface.searchCategoriesForPrefix(prefix, itemLimit, offset)
|
||||
)
|
||||
}
|
||||
|
|
@ -56,18 +53,11 @@ class CategoryClient @Inject constructor(private val categoryInterface: Category
|
|||
* @param categoryName Category name as defined on commons
|
||||
* @return Observable emitting the categories returned. If our search yielded "Category:Test", "Test" is emitted.
|
||||
*/
|
||||
fun getSubCategoryList(categoryName: String?): Single<List<String>> {
|
||||
val key = "$SUB_CATEGORY_CONTINUATION_PREFIX$categoryName"
|
||||
return if (hasMorePagesFor(key)) {
|
||||
responseToCategoryName(
|
||||
categoryInterface.getSubCategoryList(
|
||||
categoryName,
|
||||
continuationStore[key] ?: emptyMap()
|
||||
),
|
||||
key
|
||||
fun getSubCategoryList(categoryName: String): Single<List<String>> {
|
||||
return continuationRequest(SUB_CATEGORY_CONTINUATION_PREFIX, categoryName) {
|
||||
categoryInterface.getSubCategoryList(
|
||||
categoryName, it
|
||||
)
|
||||
} else {
|
||||
Single.just(emptyList())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -78,29 +68,27 @@ class CategoryClient @Inject constructor(private val categoryInterface: Category
|
|||
* @param categoryName Category name as defined on commons
|
||||
* @return
|
||||
*/
|
||||
fun getParentCategoryList(categoryName: String?): Single<List<String>> {
|
||||
return responseToCategoryName(categoryInterface.getParentCategoryList(categoryName))
|
||||
fun getParentCategoryList(categoryName: String): Single<List<String>> {
|
||||
return continuationRequest(PARENT_CATEGORY_CONTINUATION_PREFIX, categoryName) {
|
||||
categoryInterface.getParentCategoryList(categoryName, it)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal function to reduce code reuse. Extracts the categories returned from MwQueryResponse.
|
||||
*
|
||||
* @param responseObservable The query response observable
|
||||
* @return Observable emitting the categories returned. If our search yielded "Category:Test", "Test" is emitted.
|
||||
*/
|
||||
private fun responseToCategoryName(
|
||||
responseObservable: Single<MwQueryResponse>,
|
||||
key: String? = null
|
||||
fun resetSubCategoryContinuation(category: String) {
|
||||
resetContinuation(SUB_CATEGORY_CONTINUATION_PREFIX, category)
|
||||
}
|
||||
|
||||
fun resetParentCategoryContinuation(category: String) {
|
||||
resetContinuation(PARENT_CATEGORY_CONTINUATION_PREFIX, category)
|
||||
}
|
||||
|
||||
override fun responseMapper(
|
||||
networkResult: Single<MwQueryResponse>,
|
||||
key: String?
|
||||
): Single<List<String>> {
|
||||
return responseObservable
|
||||
return networkResult
|
||||
.map {
|
||||
if (key != null) {
|
||||
continuationExists[key] =
|
||||
it.continuation()?.let { continuation ->
|
||||
continuationStore[key] = continuation
|
||||
true
|
||||
} ?: false
|
||||
}
|
||||
handleContinuationResponse(it.continuation(), key)
|
||||
it.query()?.pages() ?: emptyList()
|
||||
}
|
||||
.map {
|
||||
|
|
@ -108,10 +96,4 @@ class CategoryClient @Inject constructor(private val categoryInterface: Category
|
|||
}
|
||||
}
|
||||
|
||||
private fun hasMorePagesFor(key: String) = continuationExists[key] ?: true
|
||||
|
||||
fun resetSubCategoryContinuation(category: String) {
|
||||
continuationExists.remove("$SUB_CATEGORY_CONTINUATION_PREFIX$category")
|
||||
continuationStore.remove("$SUB_CATEGORY_CONTINUATION_PREFIX$category")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import fr.free.nrw.commons.R;
|
|||
import fr.free.nrw.commons.Utils;
|
||||
import fr.free.nrw.commons.explore.ViewPagerAdapter;
|
||||
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.theme.NavigationBaseActivity;
|
||||
|
|
@ -71,23 +72,20 @@ public class CategoryDetailsActivity extends NavigationBaseActivity
|
|||
List<String> titleList = new ArrayList<>();
|
||||
categoriesMediaFragment = new CategoriesMediaFragment();
|
||||
SubCategoriesFragment subCategoryListFragment = new SubCategoriesFragment();
|
||||
SubCategoryListFragment parentCategoryListFragment = new SubCategoryListFragment();
|
||||
ParentCategoriesFragment parentCategoriesFragment = new ParentCategoriesFragment();
|
||||
categoryName = getIntent().getStringExtra("categoryName");
|
||||
if (getIntent() != null && categoryName != null) {
|
||||
Bundle arguments = new Bundle();
|
||||
arguments.putString("categoryName", categoryName);
|
||||
categoriesMediaFragment.setArguments(arguments);
|
||||
subCategoryListFragment.setArguments(arguments);
|
||||
Bundle parentCategoryArguments = new Bundle();
|
||||
parentCategoryArguments.putString("categoryName", categoryName);
|
||||
parentCategoryArguments.putBoolean("isParentCategory", true);
|
||||
parentCategoryListFragment.setArguments(parentCategoryArguments);
|
||||
parentCategoriesFragment.setArguments(arguments);
|
||||
}
|
||||
fragmentList.add(categoriesMediaFragment);
|
||||
titleList.add("MEDIA");
|
||||
fragmentList.add(subCategoryListFragment);
|
||||
titleList.add("SUBCATEGORIES");
|
||||
fragmentList.add(parentCategoryListFragment);
|
||||
fragmentList.add(parentCategoriesFragment);
|
||||
titleList.add("PARENT CATEGORIES");
|
||||
viewPagerAdapter.setTabData(fragmentList, titleList);
|
||||
viewPagerAdapter.notifyDataSetChanged();
|
||||
|
|
@ -133,7 +131,6 @@ public class CategoryDetailsActivity extends NavigationBaseActivity
|
|||
*/
|
||||
public static void startYourself(Context context, String categoryName) {
|
||||
Intent intent = new Intent(context, CategoryDetailsActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||
intent.putExtra("categoryName", categoryName);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
|
|
@ -212,12 +209,4 @@ public class CategoryDetailsActivity extends NavigationBaseActivity
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called when viewPager has reached its end.
|
||||
* Fetches more images using search query and adds it to the grid view and viewpager adapter
|
||||
*/
|
||||
@Override
|
||||
public void requestMoreImages() {
|
||||
//unneeded
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -187,15 +187,6 @@ public class CategoryImagesActivity
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called when viewPager has reached its end.
|
||||
* Fetches more images using search query and adds it to the gridView and viewpager adapter
|
||||
*/
|
||||
@Override
|
||||
public void requestMoreImages() {
|
||||
//unneeded
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMediaClicked(int position) {
|
||||
// this class is unused and will be deleted
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ package fr.free.nrw.commons.category;
|
|||
|
||||
public interface CategoryImagesCallback {
|
||||
void viewPagerNotifyDataSetChanged();
|
||||
void requestMoreImages();
|
||||
void onMediaClicked(int position);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,8 @@ public interface CategoryInterface {
|
|||
@QueryMap(encoded = true) Map<String, String> continuation);
|
||||
|
||||
@GET("w/api.php?action=query&format=json&formatversion=2"
|
||||
+ "&generator=categories&prop=info&gcllimit=500")
|
||||
Single<MwQueryResponse> getParentCategoryList(@Query("titles") String categoryName);
|
||||
+ "&generator=categories&prop=info&gcllimit=50")
|
||||
Single<MwQueryResponse> getParentCategoryList(@Query("titles") String categoryName,
|
||||
@QueryMap(encoded = true) Map<String, String> continuation);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
package fr.free.nrw.commons.category
|
||||
|
||||
import io.reactivex.Single
|
||||
|
||||
|
||||
abstract class ContinuationClient<Network, Domain> {
|
||||
private val continuationStore: MutableMap<String, Map<String, String>?> = mutableMapOf()
|
||||
private val continuationExists: MutableMap<String, Boolean> = mutableMapOf()
|
||||
|
||||
private fun hasMorePagesFor(key: String) = continuationExists[key] ?: true
|
||||
fun continuationRequest(
|
||||
prefix: String,
|
||||
name: String,
|
||||
requestFunction: (Map<String, String>) -> Single<Network>
|
||||
): Single<List<Domain>> {
|
||||
val key = "$prefix$name"
|
||||
return if (hasMorePagesFor(key)) {
|
||||
responseMapper(requestFunction(continuationStore[key] ?: emptyMap()), key)
|
||||
} else {
|
||||
Single.just(emptyList())
|
||||
}
|
||||
}
|
||||
|
||||
abstract fun responseMapper(networkResult: Single<Network>, key: String?=null): Single<List<Domain>>
|
||||
|
||||
fun handleContinuationResponse(continuation:Map<String,String>?, key:String?){
|
||||
if (key != null) {
|
||||
continuationExists[key] =
|
||||
continuation?.let { continuation ->
|
||||
continuationStore[key] = continuation
|
||||
true
|
||||
} ?: false
|
||||
}
|
||||
}
|
||||
|
||||
protected fun resetContinuation(prefix: String, category: String) {
|
||||
continuationExists.remove("$prefix$category")
|
||||
continuationStore.remove("$prefix$category")
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,154 +0,0 @@
|
|||
package fr.free.nrw.commons.category;
|
||||
|
||||
|
||||
import static android.view.View.GONE;
|
||||
import static android.view.View.VISIBLE;
|
||||
import static fr.free.nrw.commons.category.CategoryClientKt.CATEGORY_PREFIX;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
|
||||
import fr.free.nrw.commons.explore.categories.search.SearchCategoriesAdapter;
|
||||
import fr.free.nrw.commons.utils.NetworkUtils;
|
||||
import fr.free.nrw.commons.utils.ViewUtil;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import java.util.List;
|
||||
import javax.inject.Inject;
|
||||
import kotlin.Unit;
|
||||
import timber.log.Timber;
|
||||
|
||||
/**
|
||||
* Displays the category search screen.
|
||||
*/
|
||||
|
||||
public class SubCategoryListFragment extends CommonsDaggerSupportFragment {
|
||||
|
||||
@BindView(R.id.imagesListBox)
|
||||
RecyclerView categoriesRecyclerView;
|
||||
@BindView(R.id.imageSearchInProgress)
|
||||
ProgressBar progressBar;
|
||||
@BindView(R.id.imagesNotFound)
|
||||
TextView categoriesNotFoundView;
|
||||
|
||||
private String categoryName = null;
|
||||
@Inject CategoryClient categoryClient;
|
||||
|
||||
private SearchCategoriesAdapter categoriesAdapter;
|
||||
private boolean isParentCategory = true;
|
||||
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
|
||||
View rootView = inflater.inflate(R.layout.fragment_browse_image, container, false);
|
||||
ButterKnife.bind(this, rootView);
|
||||
categoryName = getArguments().getString("categoryName");
|
||||
isParentCategory = getArguments().getBoolean("isParentCategory");
|
||||
initSubCategoryList();
|
||||
if (getActivity().getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT){
|
||||
categoriesRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
}
|
||||
else{
|
||||
categoriesRecyclerView.setLayoutManager(new GridLayoutManager(getContext(), 2));
|
||||
}
|
||||
categoriesAdapter = new SearchCategoriesAdapter(item->{
|
||||
Intent intent = new Intent(getContext(), CategoryDetailsActivity.class);
|
||||
intent.putExtra("categoryName", item);
|
||||
getContext().startActivity(intent);
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
categoriesRecyclerView.setAdapter(categoriesAdapter);
|
||||
return rootView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for internet connection and then initializes the recycler view with all(max 500) categories of the searched query
|
||||
* Clearing categoryAdapter every time new keyword is searched so that user can see only new results
|
||||
*/
|
||||
public void initSubCategoryList() {
|
||||
categoriesNotFoundView.setVisibility(GONE);
|
||||
if (!NetworkUtils.isInternetConnectionEstablished(getContext())) {
|
||||
handleNoInternet();
|
||||
return;
|
||||
}
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
if (isParentCategory) {
|
||||
compositeDisposable.add(categoryClient.getParentCategoryList(
|
||||
CATEGORY_PREFIX +categoryName)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(this::handleSuccess, this::handleError));
|
||||
} else {
|
||||
compositeDisposable.add(categoryClient.getSubCategoryList(
|
||||
CATEGORY_PREFIX +categoryName)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(this::handleSuccess, this::handleError));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handles the success scenario
|
||||
* it initializes the recycler view by adding items to the adapter
|
||||
* @param subCategoryList
|
||||
*/
|
||||
private void handleSuccess(List<String> subCategoryList) {
|
||||
if (subCategoryList == null || subCategoryList.isEmpty()) {
|
||||
initEmptyView();
|
||||
}
|
||||
else {
|
||||
progressBar.setVisibility(View.GONE);
|
||||
categoriesAdapter.addAll(subCategoryList);
|
||||
categoriesAdapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs and handles API error scenario
|
||||
* @param throwable
|
||||
*/
|
||||
private void handleError(Throwable throwable) {
|
||||
if (!isParentCategory){
|
||||
Timber.e(throwable, "Error occurred while loading queried subcategories");
|
||||
ViewUtil.showShortSnackbar(categoriesRecyclerView,R.string.error_loading_categories);
|
||||
}else {
|
||||
Timber.e(throwable, "Error occurred while loading queried parentcategories");
|
||||
ViewUtil.showShortSnackbar(categoriesRecyclerView,R.string.error_loading_categories);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the UI updates for a empty results scenario
|
||||
*/
|
||||
private void initEmptyView() {
|
||||
progressBar.setVisibility(GONE);
|
||||
categoriesNotFoundView.setVisibility(VISIBLE);
|
||||
if (!isParentCategory){
|
||||
categoriesNotFoundView.setText(getString(R.string.no_subcategory_found));
|
||||
}else {
|
||||
categoriesNotFoundView.setText(getString(R.string.no_parentcategory_found));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the UI updates for no internet scenario
|
||||
*/
|
||||
private void handleNoInternet() {
|
||||
progressBar.setVisibility(GONE);
|
||||
ViewUtil.showShortSnackbar(categoriesRecyclerView, R.string.no_internet);
|
||||
}
|
||||
}
|
||||
|
|
@ -51,9 +51,6 @@ class ContributionBoundaryCallback @Inject constructor(
|
|||
* Fetches contributions using the MediaWiki API
|
||||
*/
|
||||
fun fetchContributions() {
|
||||
if (mediaClient.doesMediaListForUserHaveMorePages(sessionManager.userName!!).not()) {
|
||||
return
|
||||
}
|
||||
compositeDisposable.add(
|
||||
mediaClient.getMediaListForUser(sessionManager.userName!!)
|
||||
.map { mediaList: List<Media?> ->
|
||||
|
|
|
|||
|
|
@ -4,15 +4,15 @@ import dagger.Module;
|
|||
import dagger.android.ContributesAndroidInjector;
|
||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsFragment;
|
||||
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesFragment;
|
||||
import fr.free.nrw.commons.category.SubCategoryListFragment;
|
||||
import fr.free.nrw.commons.contributions.ContributionsFragment;
|
||||
import fr.free.nrw.commons.contributions.ContributionsListFragment;
|
||||
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.search.SearchCategoryFragment;
|
||||
import fr.free.nrw.commons.explore.categories.sub.SubCategoriesFragment;
|
||||
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.explore.categories.search.SearchCategoryFragment;
|
||||
import fr.free.nrw.commons.explore.depictions.search.SearchDepictionsFragment;
|
||||
import fr.free.nrw.commons.explore.media.SearchMediaFragment;
|
||||
import fr.free.nrw.commons.explore.recentsearches.RecentSearchesFragment;
|
||||
|
|
@ -29,7 +29,7 @@ import fr.free.nrw.commons.upload.mediaDetails.UploadMediaDetailFragment;
|
|||
/**
|
||||
* This Class Represents the Module for dependency injection (using dagger)
|
||||
* so, if a developer needs to add a new Fragment to the commons app
|
||||
* then that must be mentioned here to inject the dependencies
|
||||
* then that must be mentioned here to inject the dependencies
|
||||
*/
|
||||
@Module
|
||||
@SuppressWarnings({"WeakerAccess", "unused"})
|
||||
|
|
@ -50,9 +50,6 @@ public abstract class FragmentBuilderModule {
|
|||
@ContributesAndroidInjector
|
||||
abstract DepictedImagesFragment bindDepictedImagesFragment();
|
||||
|
||||
@ContributesAndroidInjector
|
||||
abstract SubCategoryListFragment bindSubCategoryListFragment();
|
||||
|
||||
@ContributesAndroidInjector
|
||||
abstract SearchMediaFragment bindBrowseImagesListFragment();
|
||||
|
||||
|
|
@ -103,4 +100,7 @@ public abstract class FragmentBuilderModule {
|
|||
|
||||
@ContributesAndroidInjector
|
||||
abstract SubCategoriesFragment bindSubCategoriesFragment();
|
||||
|
||||
@ContributesAndroidInjector
|
||||
abstract ParentCategoriesFragment bindParentCategoriesFragment();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -161,16 +161,6 @@ public class ExploreActivity
|
|||
super.onBackPressed();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method is called when viewPager has reached its end.
|
||||
* Fetches more images and adds them to the recycler view and viewpager adapter
|
||||
*/
|
||||
@Override
|
||||
public void requestMoreImages() {
|
||||
//unneeded
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called onClick of media inside category featured images or mobile uploads.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -264,14 +264,6 @@ public class SearchActivity extends NavigationBaseActivity
|
|||
viewPager.requestFocus();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called when viewPager has reached its end.
|
||||
* Fetches more images using search query and adds it to the recycler view and viewpager adapter
|
||||
*/
|
||||
@Override
|
||||
public void requestMoreImages() {
|
||||
//unneeded
|
||||
}
|
||||
|
||||
@Override protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ import dagger.Binds
|
|||
import dagger.Module
|
||||
import fr.free.nrw.commons.explore.categories.media.CategoryMediaPresenter
|
||||
import fr.free.nrw.commons.explore.categories.media.CategoryMediaPresenterImpl
|
||||
import fr.free.nrw.commons.explore.categories.parent.ParentCategoriesPresenter
|
||||
import fr.free.nrw.commons.explore.categories.parent.ParentCategoriesPresenterImpl
|
||||
import fr.free.nrw.commons.explore.categories.sub.SubCategoriesPresenter
|
||||
import fr.free.nrw.commons.explore.categories.sub.SubCategoriesPresenterImpl
|
||||
|
||||
|
|
@ -18,4 +20,8 @@ abstract class CategoriesModule {
|
|||
@Binds
|
||||
abstract fun SubCategoriesPresenterImpl.bindsSubCategoriesPresenter()
|
||||
: SubCategoriesPresenter
|
||||
|
||||
@Binds
|
||||
abstract fun ParentCategoriesPresenterImpl.bindsParentCategoriesPresenter()
|
||||
: ParentCategoriesPresenter
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package fr.free.nrw.commons.explore.categories.search
|
||||
package fr.free.nrw.commons.explore.categories
|
||||
|
||||
import fr.free.nrw.commons.R
|
||||
import fr.free.nrw.commons.category.CategoryDetailsActivity
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package fr.free.nrw.commons.explore.categories.search
|
||||
package fr.free.nrw.commons.explore.categories
|
||||
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package fr.free.nrw.commons.explore.categories.parent
|
||||
|
||||
import fr.free.nrw.commons.category.CategoryClient
|
||||
import fr.free.nrw.commons.explore.paging.LiveDataConverter
|
||||
import fr.free.nrw.commons.explore.paging.PageableBaseDataSource
|
||||
import javax.inject.Inject
|
||||
|
||||
class PageableParentCategoriesDataSource @Inject constructor(
|
||||
liveDataConverter: LiveDataConverter,
|
||||
val categoryClient: CategoryClient
|
||||
) : PageableBaseDataSource<String>(liveDataConverter) {
|
||||
|
||||
override val loadFunction = { loadSize: Int, startPosition: Int ->
|
||||
if (startPosition == 0) {
|
||||
categoryClient.resetParentCategoryContinuation(query)
|
||||
}
|
||||
categoryClient.getParentCategoryList(query).blockingGet()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package fr.free.nrw.commons.explore.categories.parent
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import fr.free.nrw.commons.R
|
||||
import fr.free.nrw.commons.category.CATEGORY_PREFIX
|
||||
import fr.free.nrw.commons.explore.categories.PageableCategoryFragment
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
class ParentCategoriesFragment : PageableCategoryFragment() {
|
||||
|
||||
@Inject
|
||||
lateinit var presenter: ParentCategoriesPresenter
|
||||
|
||||
override val injectedPresenter
|
||||
get() = presenter
|
||||
|
||||
override fun getEmptyText(query: String) = getString(R.string.no_parentcategory_found)
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
onQueryUpdated("$CATEGORY_PREFIX${arguments!!.getString("categoryName")!!}")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package fr.free.nrw.commons.explore.categories.parent
|
||||
|
||||
import fr.free.nrw.commons.di.CommonsApplicationModule
|
||||
import fr.free.nrw.commons.explore.paging.BasePagingPresenter
|
||||
import fr.free.nrw.commons.explore.paging.PagingContract
|
||||
import io.reactivex.Scheduler
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Named
|
||||
|
||||
|
||||
interface ParentCategoriesPresenter : PagingContract.Presenter<String>
|
||||
|
||||
class ParentCategoriesPresenterImpl @Inject constructor(
|
||||
@Named(CommonsApplicationModule.MAIN_THREAD) mainThreadScheduler: Scheduler,
|
||||
dataSourceFactory: PageableParentCategoriesDataSource
|
||||
) : BasePagingPresenter<String>(mainThreadScheduler, dataSourceFactory),
|
||||
ParentCategoriesPresenter
|
||||
|
|
@ -5,7 +5,7 @@ import fr.free.nrw.commons.explore.paging.LiveDataConverter
|
|||
import fr.free.nrw.commons.explore.paging.PageableBaseDataSource
|
||||
import javax.inject.Inject
|
||||
|
||||
class PageableCategoriesDataSource @Inject constructor(
|
||||
class PageableSearchCategoriesDataSource @Inject constructor(
|
||||
liveDataConverter: LiveDataConverter,
|
||||
val categoryClient: CategoryClient
|
||||
) : PageableBaseDataSource<String>(liveDataConverter) {
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
package fr.free.nrw.commons.explore.categories.search
|
||||
|
||||
import fr.free.nrw.commons.upload.categories.BaseDelegateAdapter
|
||||
|
||||
|
||||
class SearchCategoriesAdapter(onCateoryClicked: (String) -> Unit) : BaseDelegateAdapter<String>(
|
||||
searchCategoryDelegate(
|
||||
onCateoryClicked
|
||||
),
|
||||
areItemsTheSame = { oldItem, newItem -> oldItem == newItem }
|
||||
)
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
package fr.free.nrw.commons.explore.categories.search
|
||||
|
||||
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateLayoutContainer
|
||||
import fr.free.nrw.commons.R
|
||||
import fr.free.nrw.commons.category.CATEGORY_PREFIX
|
||||
import kotlinx.android.synthetic.main.item_recent_searches.*
|
||||
|
||||
|
||||
fun searchCategoryDelegate(onCategoryClicked: (String) -> Unit) =
|
||||
adapterDelegateLayoutContainer<String, String>(R.layout.item_recent_searches) {
|
||||
containerView.setOnClickListener { onCategoryClicked(item) }
|
||||
bind {
|
||||
textView1.text = item.substringAfter(CATEGORY_PREFIX)
|
||||
}
|
||||
}
|
||||
|
|
@ -11,6 +11,6 @@ interface SearchCategoriesFragmentPresenter : PagingContract.Presenter<String>
|
|||
|
||||
class SearchCategoriesFragmentPresenterImpl @Inject constructor(
|
||||
@Named(CommonsApplicationModule.MAIN_THREAD) mainThreadScheduler: Scheduler,
|
||||
dataSourceFactory: PageableCategoriesDataSource
|
||||
dataSourceFactory: PageableSearchCategoriesDataSource
|
||||
) : BasePagingPresenter<String>(mainThreadScheduler, dataSourceFactory),
|
||||
SearchCategoriesFragmentPresenter
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
package fr.free.nrw.commons.explore.categories.search
|
||||
|
||||
import fr.free.nrw.commons.R
|
||||
import fr.free.nrw.commons.category.CategoryDetailsActivity
|
||||
import fr.free.nrw.commons.explore.paging.BasePagingFragment
|
||||
import fr.free.nrw.commons.explore.categories.PageableCategoryFragment
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -4,8 +4,7 @@ import android.os.Bundle
|
|||
import android.view.View
|
||||
import fr.free.nrw.commons.R
|
||||
import fr.free.nrw.commons.category.CATEGORY_PREFIX
|
||||
import fr.free.nrw.commons.explore.categories.search.PageableCategoryFragment
|
||||
import fr.free.nrw.commons.explore.paging.PagingContract
|
||||
import fr.free.nrw.commons.explore.categories.PageableCategoryFragment
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
|
|
@ -13,7 +12,7 @@ class SubCategoriesFragment : PageableCategoryFragment() {
|
|||
|
||||
@Inject lateinit var presenter: SubCategoriesPresenter
|
||||
|
||||
override val injectedPresenter: PagingContract.Presenter<String>
|
||||
override val injectedPresenter
|
||||
get() = presenter
|
||||
|
||||
override fun getEmptyText(query: String) = getString(R.string.no_subcategory_found)
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ 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.category.CategoryImagesCallback;
|
||||
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;
|
||||
|
|
@ -26,7 +27,8 @@ 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 {
|
||||
public class WikidataItemDetailsActivity extends NavigationBaseActivity implements MediaDetailPagerFragment.MediaDetailProvider,
|
||||
CategoryImagesCallback {
|
||||
private FragmentManager supportFragmentManager;
|
||||
private DepictedImagesFragment depictionImagesListFragment;
|
||||
private MediaDetailPagerFragment mediaDetailPagerFragment;
|
||||
|
|
@ -73,13 +75,13 @@ public class WikidataItemDetailsActivity extends NavigationBaseActivity implemen
|
|||
* This method is called on success of API call for featured Images.
|
||||
* The viewpager will notified that number of items have changed.
|
||||
*/
|
||||
@Override
|
||||
public void viewPagerNotifyDataSetChanged() {
|
||||
if (mediaDetailPagerFragment !=null){
|
||||
mediaDetailPagerFragment.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This activity contains 3 tabs and a viewpager. This method is used to set the titles of tab,
|
||||
* Set the fragments according to the tab selected in the viewPager.
|
||||
|
|
|
|||
|
|
@ -14,9 +14,7 @@ import kotlinx.android.synthetic.main.fragment_search_paginated.*
|
|||
abstract class PageableMediaFragment : BasePagingFragment<Media>(), MediaDetailProvider {
|
||||
|
||||
override val pagedListAdapter by lazy {
|
||||
PagedMediaAdapter {
|
||||
categoryImagesCallback.onMediaClicked(it)
|
||||
}
|
||||
PagedMediaAdapter(categoryImagesCallback::onMediaClicked)
|
||||
}
|
||||
|
||||
override val errorTextId: Int = R.string.error_loading_images
|
||||
|
|
@ -30,9 +28,8 @@ abstract class PageableMediaFragment : BasePagingFragment<Media>(), MediaDetailP
|
|||
categoryImagesCallback = (context as CategoryImagesCallback)
|
||||
}
|
||||
|
||||
private val simpleDataObserver = SimpleDataObserver {
|
||||
categoryImagesCallback.viewPagerNotifyDataSetChanged()
|
||||
}
|
||||
private val simpleDataObserver =
|
||||
SimpleDataObserver { categoryImagesCallback.viewPagerNotifyDataSetChanged() }
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package fr.free.nrw.commons.media
|
|||
|
||||
import fr.free.nrw.commons.BuildConfig
|
||||
import fr.free.nrw.commons.Media
|
||||
import fr.free.nrw.commons.category.ContinuationClient
|
||||
import fr.free.nrw.commons.explore.media.MediaConverter
|
||||
import fr.free.nrw.commons.utils.CommonsDateUtil
|
||||
import io.reactivex.Single
|
||||
|
|
@ -24,14 +25,10 @@ class MediaClient @Inject constructor(
|
|||
private val pageMediaInterface: PageMediaInterface,
|
||||
private val mediaDetailInterface: MediaDetailInterface,
|
||||
private val mediaConverter: MediaConverter
|
||||
) {
|
||||
) : ContinuationClient<MwQueryResponse, Media>() {
|
||||
|
||||
fun getMediaById(id: String) =
|
||||
responseToMediaList(mediaInterface.getMediaById(id)).map { it.first() }
|
||||
|
||||
//OkHttpJsonApiClient used JsonKvStore for this. I don't know why.
|
||||
private val continuationStore: MutableMap<String, Map<String, String>?> = mutableMapOf()
|
||||
private val continuationExists: MutableMap<String, Boolean> = mutableMapOf()
|
||||
responseMapper(mediaInterface.getMediaById(id)).map { it.first() }
|
||||
|
||||
/**
|
||||
* Checks if a page exists on Commons
|
||||
|
|
@ -62,18 +59,8 @@ class MediaClient @Inject constructor(
|
|||
* @return
|
||||
*/
|
||||
fun getMediaListFromCategory(category: String): Single<List<Media>> {
|
||||
val key = "$CATEGORY_CONTINUATION_PREFIX$category"
|
||||
return if (hasMorePagesFor(key)) {
|
||||
responseToMediaList(
|
||||
mediaInterface.getMediaListFromCategory(
|
||||
category,
|
||||
10,
|
||||
continuationStore[key] ?: emptyMap()
|
||||
),
|
||||
key
|
||||
)
|
||||
} else {
|
||||
Single.just(emptyList())
|
||||
return continuationRequest(CATEGORY_CONTINUATION_PREFIX, category) {
|
||||
mediaInterface.getMediaListFromCategory(category, 10, it)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -86,17 +73,11 @@ class MediaClient @Inject constructor(
|
|||
* @return
|
||||
*/
|
||||
fun getMediaListForUser(userName: String): Single<List<Media>> {
|
||||
return responseToMediaList(
|
||||
mediaInterface.getMediaListForUser(
|
||||
userName,
|
||||
10,
|
||||
continuationStore["user_$userName"] ?: Collections.emptyMap()
|
||||
),
|
||||
"user_$userName"
|
||||
)
|
||||
return continuationRequest("user_", userName) {
|
||||
mediaInterface.getMediaListForUser(userName, 10, it)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method takes a keyword as input and returns a list of Media objects filtered using image generator query
|
||||
* It uses the generator query API to get the images searched using a query, 10 at a time.
|
||||
|
|
@ -107,7 +88,7 @@ class MediaClient @Inject constructor(
|
|||
* @return
|
||||
*/
|
||||
fun getMediaListFromSearch(keyword: String?, limit: Int, offset: Int) =
|
||||
responseToMediaList(mediaInterface.getMediaListFromSearch(keyword, limit, offset))
|
||||
responseMapper(mediaInterface.getMediaListFromSearch(keyword, limit, offset))
|
||||
|
||||
/**
|
||||
* @return list of images for a particular depict entity
|
||||
|
|
@ -117,7 +98,7 @@ class MediaClient @Inject constructor(
|
|||
srlimit: Int,
|
||||
sroffset: Int
|
||||
): Single<List<Media>> {
|
||||
return responseToMediaList(
|
||||
return responseMapper(
|
||||
mediaInterface.fetchImagesForDepictedItem(
|
||||
"haswbstatement:" + BuildConfig.DEPICTS_PROPERTY + "=" + query,
|
||||
srlimit.toString(),
|
||||
|
|
@ -126,23 +107,6 @@ class MediaClient @Inject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
private fun responseToMediaList(
|
||||
response: Single<MwQueryResponse>,
|
||||
key: String? = null
|
||||
): Single<List<Media>> {
|
||||
return response.map {
|
||||
if (key != null) {
|
||||
continuationExists[key] =
|
||||
it.continuation()?.let { continuation ->
|
||||
continuationStore[key] = continuation
|
||||
true
|
||||
} ?: false
|
||||
}
|
||||
it.query()?.pages() ?: emptyList()
|
||||
}.flatMap(::mediaFromPageAndEntity)
|
||||
|
||||
}
|
||||
|
||||
private fun mediaFromPageAndEntity(pages: List<MwQueryPage>): Single<List<Media>> {
|
||||
return if (pages.isEmpty())
|
||||
Single.just(emptyList())
|
||||
|
|
@ -165,7 +129,7 @@ class MediaClient @Inject constructor(
|
|||
* @return
|
||||
*/
|
||||
fun getMedia(titles: String?): Single<Media> {
|
||||
return responseToMediaList(mediaInterface.getMedia(titles))
|
||||
return responseMapper(mediaInterface.getMedia(titles))
|
||||
.map { it.first() }
|
||||
}
|
||||
|
||||
|
|
@ -176,7 +140,7 @@ class MediaClient @Inject constructor(
|
|||
*/
|
||||
fun getPictureOfTheDay(): Single<Media> {
|
||||
val date = CommonsDateUtil.getIso8601DateFormatShort().format(Date())
|
||||
return responseToMediaList(mediaInterface.getMediaWithGenerator("Template:Potd/$date")).map { it.first() }
|
||||
return responseMapper(mediaInterface.getMediaWithGenerator("Template:Potd/$date")).map { it.first() }
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -193,24 +157,22 @@ class MediaClient @Inject constructor(
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if media for user has reached the end of the list.
|
||||
* @param userName
|
||||
* @return
|
||||
*/
|
||||
fun doesMediaListForUserHaveMorePages(userName: String): Boolean {
|
||||
return hasMorePagesFor("user_$userName")
|
||||
}
|
||||
|
||||
private fun hasMorePagesFor(key: String) = continuationExists[key] ?: true
|
||||
|
||||
fun doesPageContainMedia(title: String?): Single<Boolean> {
|
||||
return pageMediaInterface.getMediaList(title)
|
||||
.map { it.items.isNotEmpty() }
|
||||
}
|
||||
|
||||
fun resetCategoryContinuation(category: String) {
|
||||
continuationExists.remove("$CATEGORY_CONTINUATION_PREFIX$category")
|
||||
continuationStore.remove("$CATEGORY_CONTINUATION_PREFIX$category")
|
||||
resetContinuation(CATEGORY_CONTINUATION_PREFIX, category)
|
||||
}
|
||||
|
||||
override fun responseMapper(
|
||||
networkResult: Single<MwQueryResponse>,
|
||||
key: String?
|
||||
): Single<List<Media>> {
|
||||
return networkResult.map {
|
||||
handleContinuationResponse(it.continuation(), key)
|
||||
it.query()?.pages() ?: emptyList()
|
||||
}.flatMap(::mediaFromPageAndEntity)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ import android.view.MenuInflater;
|
|||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Toast;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentStatePagerAdapter;
|
||||
|
|
@ -26,7 +25,6 @@ import fr.free.nrw.commons.R;
|
|||
import fr.free.nrw.commons.bookmarks.Bookmark;
|
||||
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesContentProvider;
|
||||
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesDao;
|
||||
import fr.free.nrw.commons.category.CategoryImagesCallback;
|
||||
import fr.free.nrw.commons.contributions.Contribution;
|
||||
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
|
||||
import fr.free.nrw.commons.utils.DownloadUtils;
|
||||
|
|
@ -269,8 +267,6 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple
|
|||
Timber.d("Returning as activity is destroyed!");
|
||||
return;
|
||||
}
|
||||
if (i+1 >= adapter.getCount() && getContext() instanceof CategoryImagesCallback)
|
||||
((CategoryImagesCallback) getContext()).requestMoreImages();
|
||||
|
||||
getActivity().invalidateOptionsMenu();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,44 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:focusableInTouchMode="true"
|
||||
android:id="@+id/image_search_results_display"
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="@dimen/tiny_gap"
|
||||
>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/imagesNotFound"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:layout_centerInParent="true"
|
||||
android:visibility="gone" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/bottomProgressBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:paddingTop="@dimen/tiny_padding"
|
||||
android:paddingBottom="@dimen/tiny_padding"
|
||||
android:visibility="gone"
|
||||
/>
|
||||
<ProgressBar
|
||||
android:id="@+id/imageSearchInProgress"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
/>
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/imagesListBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scrollbars="vertical"
|
||||
android:layout_above="@+id/bottomProgressBar"
|
||||
android:scrollbarSize="@dimen/standard_gap"
|
||||
android:fadingEdge="none" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
|
@ -3,19 +3,19 @@ package fr.free.nrw.commons.explore.categroies
|
|||
import com.nhaarman.mockitokotlin2.mock
|
||||
import com.nhaarman.mockitokotlin2.whenever
|
||||
import fr.free.nrw.commons.category.CategoryClient
|
||||
import fr.free.nrw.commons.explore.categories.search.PageableCategoriesDataSource
|
||||
import fr.free.nrw.commons.explore.categories.search.PageableSearchCategoriesDataSource
|
||||
import io.reactivex.Single
|
||||
import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.hamcrest.Matchers
|
||||
import org.junit.Test
|
||||
|
||||
class PageableCategoriesDataSourceTest {
|
||||
class PageableSearchCategoriesDataSourceTest {
|
||||
@Test
|
||||
fun `loadFunction loads categories`() {
|
||||
val categoryClient: CategoryClient = mock()
|
||||
whenever(categoryClient.searchCategories("test", 0, 1))
|
||||
.thenReturn(Single.just(emptyList()))
|
||||
val pageableCategoriesDataSource = PageableCategoriesDataSource(mock(), categoryClient)
|
||||
val pageableCategoriesDataSource = PageableSearchCategoriesDataSource(mock(), categoryClient)
|
||||
pageableCategoriesDataSource.onQueryUpdated("test")
|
||||
assertThat(pageableCategoriesDataSource.loadFunction(0, 1), Matchers.`is`(emptyList()))
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue