mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 12:23:58 +01:00
parent
7817518462
commit
9d59915459
41 changed files with 444 additions and 477 deletions
|
|
@ -141,5 +141,7 @@ public class BookmarksActivity extends NavigationBaseActivity
|
|||
}
|
||||
|
||||
@Override
|
||||
public void requestMoreImages() { }
|
||||
public void onMediaClicked(int position) {
|
||||
//TODO use with pagination
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@ class CategoriesModel @Inject constructor(
|
|||
else
|
||||
categoryClient.searchCategoriesForPrefix(term.toLowerCase(), SEARCH_CATS_LIMIT)
|
||||
.map { it.sortedWith(StringSortingUtils.sortBySimilarity(term)) }
|
||||
.toObservable()
|
||||
}
|
||||
|
||||
private fun categoriesFromDepiction(selectedDepictions: List<DepictedItem>) =
|
||||
|
|
@ -126,7 +127,7 @@ class CategoriesModel @Inject constructor(
|
|||
* @return
|
||||
*/
|
||||
private fun getTitleCategories(title: String): Observable<List<String>> {
|
||||
return categoryClient.searchCategories(title.toLowerCase(), SEARCH_CATS_LIMIT)
|
||||
return categoryClient.searchCategories(title.toLowerCase(), SEARCH_CATS_LIMIT).toObservable()
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +1,21 @@
|
|||
package fr.free.nrw.commons.category
|
||||
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.Single
|
||||
import org.wikipedia.dataclient.mwapi.MwQueryResponse
|
||||
import javax.inject.Inject
|
||||
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) {
|
||||
class CategoryClient @Inject constructor(private val categoryInterface: CategoryInterface) :
|
||||
ContinuationClient<MwQueryResponse, String>() {
|
||||
|
||||
/**
|
||||
* Searches for categories containing the specified string.
|
||||
*
|
||||
|
|
@ -21,8 +26,8 @@ class CategoryClient @Inject constructor(private val categoryInterface: Category
|
|||
*/
|
||||
@JvmOverloads
|
||||
fun searchCategories(filter: String?, itemLimit: Int, offset: Int = 0):
|
||||
Observable<List<String>> {
|
||||
return responseToCategoryName(categoryInterface.searchCategories(filter, itemLimit, offset))
|
||||
Single<List<String>> {
|
||||
return responseMapper(categoryInterface.searchCategories(filter, itemLimit, offset))
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -35,8 +40,8 @@ class CategoryClient @Inject constructor(private val categoryInterface: Category
|
|||
*/
|
||||
@JvmOverloads
|
||||
fun searchCategoriesForPrefix(prefix: String?, itemLimit: Int, offset: Int = 0):
|
||||
Observable<List<String>> {
|
||||
return responseToCategoryName(
|
||||
Single<List<String>> {
|
||||
return responseMapper(
|
||||
categoryInterface.searchCategoriesForPrefix(prefix, itemLimit, offset)
|
||||
)
|
||||
}
|
||||
|
|
@ -48,8 +53,12 @@ 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?): Observable<List<String>> {
|
||||
return responseToCategoryName(categoryInterface.getSubCategoryList(categoryName))
|
||||
fun getSubCategoryList(categoryName: String): Single<List<String>> {
|
||||
return continuationRequest(SUB_CATEGORY_CONTINUATION_PREFIX, categoryName) {
|
||||
categoryInterface.getSubCategoryList(
|
||||
categoryName, it
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -59,19 +68,29 @@ class CategoryClient @Inject constructor(private val categoryInterface: Category
|
|||
* @param categoryName Category name as defined on commons
|
||||
* @return
|
||||
*/
|
||||
fun getParentCategoryList(categoryName: String?): Observable<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: Observable<MwQueryResponse>): Observable<List<String>> {
|
||||
return responseObservable
|
||||
.map { it.query()?.pages() ?: emptyList() }
|
||||
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 networkResult
|
||||
.map {
|
||||
handleContinuationResponse(it.continuation(), key)
|
||||
it.query()?.pages() ?: emptyList()
|
||||
}
|
||||
.map {
|
||||
it.map { page -> page.title().replace(CATEGORY_PREFIX, "") }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ 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;
|
||||
import java.util.ArrayList;
|
||||
|
|
@ -69,25 +71,21 @@ public class CategoryDetailsActivity extends NavigationBaseActivity
|
|||
List<Fragment> fragmentList = new ArrayList<>();
|
||||
List<String> titleList = new ArrayList<>();
|
||||
categoriesMediaFragment = new CategoriesMediaFragment();
|
||||
SubCategoryListFragment subCategoryListFragment = new SubCategoryListFragment();
|
||||
SubCategoryListFragment parentCategoryListFragment = new SubCategoryListFragment();
|
||||
SubCategoriesFragment subCategoryListFragment = new SubCategoriesFragment();
|
||||
ParentCategoriesFragment parentCategoriesFragment = new ParentCategoriesFragment();
|
||||
categoryName = getIntent().getStringExtra("categoryName");
|
||||
if (getIntent() != null && categoryName != null) {
|
||||
Bundle arguments = new Bundle();
|
||||
arguments.putString("categoryName", categoryName);
|
||||
arguments.putBoolean("isParentCategory", false);
|
||||
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,12 +187,8 @@ 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
|
||||
public void onMediaClicked(int position) {
|
||||
// this class is unused and will be deleted
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ package fr.free.nrw.commons.category;
|
|||
|
||||
public interface CategoryImagesCallback {
|
||||
void viewPagerNotifyDataSetChanged();
|
||||
void requestMoreImages();
|
||||
void onMediaClicked(int position);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
package fr.free.nrw.commons.category;
|
||||
|
||||
import io.reactivex.Single;
|
||||
import java.util.Map;
|
||||
import org.wikipedia.dataclient.mwapi.MwQueryResponse;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
import retrofit2.http.GET;
|
||||
import retrofit2.http.Query;
|
||||
import retrofit2.http.QueryMap;
|
||||
|
||||
/**
|
||||
* Interface for interacting with Commons category related APIs
|
||||
|
|
@ -20,7 +21,7 @@ public interface CategoryInterface {
|
|||
*/
|
||||
@GET("w/api.php?action=query&format=json&formatversion=2"
|
||||
+ "&generator=search&gsrnamespace=14")
|
||||
Observable<MwQueryResponse> searchCategories(@Query("gsrsearch") String filter,
|
||||
Single<MwQueryResponse> searchCategories(@Query("gsrsearch") String filter,
|
||||
@Query("gsrlimit") int itemLimit, @Query("gsroffset") int offset);
|
||||
|
||||
/**
|
||||
|
|
@ -32,16 +33,18 @@ public interface CategoryInterface {
|
|||
*/
|
||||
@GET("w/api.php?action=query&format=json&formatversion=2"
|
||||
+ "&generator=allcategories")
|
||||
Observable<MwQueryResponse> searchCategoriesForPrefix(@Query("gacprefix") String prefix,
|
||||
Single<MwQueryResponse> searchCategoriesForPrefix(@Query("gacprefix") String prefix,
|
||||
@Query("gaclimit") int itemLimit, @Query("gacoffset") int offset);
|
||||
|
||||
@GET("w/api.php?action=query&format=json&formatversion=2"
|
||||
+ "&generator=categorymembers&gcmtype=subcat"
|
||||
+ "&prop=info&gcmlimit=500")
|
||||
Observable<MwQueryResponse> getSubCategoryList(@Query("gcmtitle") String categoryName);
|
||||
+ "&prop=info&gcmlimit=50")
|
||||
Single<MwQueryResponse> getSubCategoryList(@Query("gcmtitle") String categoryName,
|
||||
@QueryMap(encoded = true) Map<String, String> continuation);
|
||||
|
||||
@GET("w/api.php?action=query&format=json&formatversion=2"
|
||||
+ "&generator=categories&prop=info&gcllimit=500")
|
||||
Observable<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,14 +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;
|
||||
|
|
@ -28,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"})
|
||||
|
|
@ -49,9 +50,6 @@ public abstract class FragmentBuilderModule {
|
|||
@ContributesAndroidInjector
|
||||
abstract DepictedImagesFragment bindDepictedImagesFragment();
|
||||
|
||||
@ContributesAndroidInjector
|
||||
abstract SubCategoryListFragment bindSubCategoryListFragment();
|
||||
|
||||
@ContributesAndroidInjector
|
||||
abstract SearchMediaFragment bindBrowseImagesListFragment();
|
||||
|
||||
|
|
@ -99,4 +97,10 @@ public abstract class FragmentBuilderModule {
|
|||
|
||||
@ContributesAndroidInjector
|
||||
abstract CategoriesMediaFragment bindCategoriesMediaFragment();
|
||||
|
||||
@ContributesAndroidInjector
|
||||
abstract SubCategoriesFragment bindSubCategoriesFragment();
|
||||
|
||||
@ContributesAndroidInjector
|
||||
abstract ParentCategoriesFragment bindParentCategoriesFragment();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import android.view.Menu;
|
|||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.FrameLayout;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
|
@ -31,8 +30,7 @@ import java.util.List;
|
|||
|
||||
public class ExploreActivity
|
||||
extends NavigationBaseActivity
|
||||
implements MediaDetailPagerFragment.MediaDetailProvider,
|
||||
AdapterView.OnItemClickListener, CategoryImagesCallback {
|
||||
implements MediaDetailPagerFragment.MediaDetailProvider, CategoryImagesCallback {
|
||||
|
||||
private static final String FEATURED_IMAGES_CATEGORY = "Featured_pictures_on_Wikimedia_Commons";
|
||||
private static final String MOBILE_UPLOADS_CATEGORY = "Uploaded_with_Mobile/Android";
|
||||
|
|
@ -163,21 +161,11 @@ 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.
|
||||
*/
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
|
||||
public void onMediaClicked( int position) {
|
||||
tabLayout.setVisibility(View.GONE);
|
||||
viewPager.setVisibility(View.GONE);
|
||||
mediaContainer.setVisibility(View.VISIBLE);
|
||||
|
|
@ -195,7 +183,7 @@ public class ExploreActivity
|
|||
// coming back to the explore activity. See https://github.com/commons-app/apps-android-commons/issues/1631
|
||||
// https://stackoverflow.com/questions/11353075/how-can-i-maintain-fragment-state-when-added-to-the-back-stack/19022550#19022550 supportFragmentManager.executePendingTransactions();
|
||||
}
|
||||
mediaDetails.showImage(i);
|
||||
mediaDetails.showImage(position);
|
||||
forceInitBackButton();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -191,7 +191,8 @@ public class SearchActivity extends NavigationBaseActivity
|
|||
* Open media detail pager fragment on click of image in search results
|
||||
* @param index item index that should be opened
|
||||
*/
|
||||
public void onSearchImageClicked(int index) {
|
||||
@Override
|
||||
public void onMediaClicked(int index) {
|
||||
ViewUtil.hideKeyboard(this.findViewById(R.id.searchBox));
|
||||
toolbar.setVisibility(View.GONE);
|
||||
tabLayout.setVisibility(View.GONE);
|
||||
|
|
@ -263,15 +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();
|
||||
//Dispose the disposables when the activity is destroyed
|
||||
|
|
|
|||
|
|
@ -4,12 +4,24 @@ 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
|
||||
|
||||
|
||||
@Module
|
||||
abstract class CategoriesModule {
|
||||
|
||||
@Binds
|
||||
abstract fun CategoryMediaPresenterImpl.bindsParentDepictionPresenter()
|
||||
abstract fun CategoryMediaPresenterImpl.bindsCategoryMediaPresenter()
|
||||
: CategoryMediaPresenter
|
||||
|
||||
@Binds
|
||||
abstract fun SubCategoriesPresenterImpl.bindsSubCategoriesPresenter()
|
||||
: SubCategoriesPresenter
|
||||
|
||||
@Binds
|
||||
abstract fun ParentCategoriesPresenterImpl.bindsParentCategoriesPresenter()
|
||||
: ParentCategoriesPresenter
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
package fr.free.nrw.commons.explore.categories
|
||||
|
||||
import fr.free.nrw.commons.R
|
||||
import fr.free.nrw.commons.category.CategoryDetailsActivity
|
||||
import fr.free.nrw.commons.explore.paging.BasePagingFragment
|
||||
|
||||
|
||||
abstract class PageableCategoryFragment : BasePagingFragment<String>() {
|
||||
override val errorTextId: Int = R.string.error_loading_categories
|
||||
override val pagedListAdapter by lazy {
|
||||
PagedSearchCategoriesAdapter {
|
||||
CategoryDetailsActivity.startYourself(context, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -41,5 +41,3 @@ class CategoryItemViewHolder(containerView: View, val onCategoryClicked: (String
|
|||
textView1.text = item.substringAfter(CATEGORY_PREFIX)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -3,8 +3,6 @@ package fr.free.nrw.commons.explore.categories.media
|
|||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import fr.free.nrw.commons.category.CATEGORY_PREFIX
|
||||
import fr.free.nrw.commons.category.CategoryDetailsActivity
|
||||
import fr.free.nrw.commons.category.CategoryImagesCallback
|
||||
import fr.free.nrw.commons.explore.media.PageableMediaFragment
|
||||
import javax.inject.Inject
|
||||
|
||||
|
|
@ -20,12 +18,4 @@ class CategoriesMediaFragment : PageableMediaFragment() {
|
|||
super.onViewCreated(view, savedInstanceState)
|
||||
onQueryUpdated("$CATEGORY_PREFIX${arguments!!.getString("categoryName")!!}")
|
||||
}
|
||||
|
||||
override fun onItemClicked(position: Int) {
|
||||
(activity as CategoryDetailsActivity).onMediaClicked(position)
|
||||
}
|
||||
|
||||
override fun notifyViewPager() {
|
||||
(activity as CategoryImagesCallback).viewPagerNotifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,12 +5,12 @@ 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) {
|
||||
|
||||
override val loadFunction = { loadSize: Int, startPosition: Int ->
|
||||
categoryClient.searchCategories(query, loadSize, startPosition).blockingFirst()
|
||||
categoryClient.searchCategories(query, loadSize, startPosition).blockingGet()
|
||||
}
|
||||
}
|
||||
|
|
@ -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,27 +1,18 @@
|
|||
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
|
||||
|
||||
/**
|
||||
* Displays the category search screen.
|
||||
*/
|
||||
class SearchCategoryFragment : BasePagingFragment<String>() {
|
||||
class SearchCategoryFragment : PageableCategoryFragment() {
|
||||
@Inject
|
||||
lateinit var presenter: SearchCategoriesFragmentPresenter
|
||||
|
||||
override val errorTextId: Int = R.string.error_loading_categories
|
||||
|
||||
override val injectedPresenter
|
||||
get() = presenter
|
||||
|
||||
override val pagedListAdapter by lazy {
|
||||
PagedSearchCategoriesAdapter {
|
||||
CategoryDetailsActivity.startYourself(context, it)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getEmptyText(query: String) = getString(R.string.categories_not_found, query)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
package fr.free.nrw.commons.explore.categories.sub
|
||||
|
||||
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 PageableSubCategoriesDataSource @Inject constructor(
|
||||
liveDataConverter: LiveDataConverter,
|
||||
val categoryClient: CategoryClient
|
||||
) : PageableBaseDataSource<String>(liveDataConverter) {
|
||||
|
||||
override val loadFunction = { loadSize: Int, startPosition: Int ->
|
||||
if (startPosition == 0) {
|
||||
categoryClient.resetSubCategoryContinuation(query)
|
||||
}
|
||||
categoryClient.getSubCategoryList(query).blockingGet()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package fr.free.nrw.commons.explore.categories.sub
|
||||
|
||||
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 SubCategoriesFragment : PageableCategoryFragment() {
|
||||
|
||||
@Inject lateinit var presenter: SubCategoriesPresenter
|
||||
|
||||
override val injectedPresenter
|
||||
get() = presenter
|
||||
|
||||
override fun getEmptyText(query: String) = getString(R.string.no_subcategory_found)
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
onQueryUpdated("$CATEGORY_PREFIX${arguments!!.getString("categoryName")!!}")
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package fr.free.nrw.commons.explore.categories.sub
|
||||
|
||||
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 SubCategoriesPresenter : PagingContract.Presenter<String>
|
||||
|
||||
class SubCategoriesPresenterImpl @Inject constructor(
|
||||
@Named(CommonsApplicationModule.MAIN_THREAD) mainThreadScheduler: Scheduler,
|
||||
dataSourceFactory: PageableSubCategoriesDataSource
|
||||
) : BasePagingPresenter<String>(mainThreadScheduler, dataSourceFactory),
|
||||
SubCategoriesPresenter
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -17,12 +17,4 @@ class DepictedImagesFragment : PageableMediaFragment() {
|
|||
super.onViewCreated(view, savedInstanceState)
|
||||
onQueryUpdated(arguments!!.getString("entityId")!!)
|
||||
}
|
||||
|
||||
override fun onItemClicked(position: Int) {
|
||||
(activity as WikidataItemDetailsActivity).onMediaClicked(position)
|
||||
}
|
||||
|
||||
override fun notifyViewPager() {
|
||||
(activity as WikidataItemDetailsActivity).viewPagerNotifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,25 +1,35 @@
|
|||
package fr.free.nrw.commons.explore.media
|
||||
|
||||
import android.content.Context
|
||||
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.category.CategoryImagesCallback
|
||||
import fr.free.nrw.commons.explore.paging.BasePagingFragment
|
||||
import fr.free.nrw.commons.media.MediaDetailPagerFragment.MediaDetailProvider
|
||||
import kotlinx.android.synthetic.main.fragment_search_paginated.*
|
||||
|
||||
|
||||
abstract class PageableMediaFragment : BasePagingFragment<Media>() {
|
||||
override val pagedListAdapter by lazy { PagedMediaAdapter(::onItemClicked) }
|
||||
abstract class PageableMediaFragment : BasePagingFragment<Media>(), MediaDetailProvider {
|
||||
|
||||
override val pagedListAdapter by lazy {
|
||||
PagedMediaAdapter(categoryImagesCallback::onMediaClicked)
|
||||
}
|
||||
|
||||
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)
|
||||
lateinit var categoryImagesCallback: CategoryImagesCallback
|
||||
|
||||
protected abstract fun notifyViewPager()
|
||||
override fun onAttach(context: Context) {
|
||||
super.onAttach(context)
|
||||
categoryImagesCallback = (context as CategoryImagesCallback)
|
||||
}
|
||||
|
||||
private val simpleDataObserver = SimpleDataObserver { notifyViewPager() }
|
||||
private val simpleDataObserver =
|
||||
SimpleDataObserver { categoryImagesCallback.viewPagerNotifyDataSetChanged() }
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
|
@ -31,12 +41,12 @@ abstract class PageableMediaFragment : BasePagingFragment<Media>() {
|
|||
pagedListAdapter.unregisterAdapterDataObserver(simpleDataObserver)
|
||||
}
|
||||
|
||||
fun getMediaAtPosition(position: Int): Media? =
|
||||
override fun getMediaAtPosition(position: Int): Media? =
|
||||
pagedListAdapter.currentList?.get(position)?.takeIf { it.filename != null }
|
||||
.also {
|
||||
pagedListAdapter.currentList?.loadAround(position)
|
||||
paginatedSearchResultsList.scrollToPosition(position)
|
||||
}
|
||||
|
||||
fun getTotalMediaCount(): Int = pagedListAdapter.itemCount
|
||||
override fun getTotalMediaCount(): Int = pagedListAdapter.itemCount
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,26 +1,15 @@
|
|||
package fr.free.nrw.commons.explore.media
|
||||
|
||||
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 : PageableMediaFragment(){
|
||||
class SearchMediaFragment : PageableMediaFragment() {
|
||||
@Inject
|
||||
lateinit var presenter: SearchMediaFragmentPresenter
|
||||
|
||||
override val injectedPresenter
|
||||
get() = presenter
|
||||
|
||||
override fun onItemClicked(position: Int) {
|
||||
(context as SearchActivity).onSearchImageClicked(position)
|
||||
}
|
||||
|
||||
override fun notifyViewPager() {
|
||||
(activity as CategoryImagesCallback).viewPagerNotifyDataSetChanged()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,23 +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")
|
||||
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>
|
||||
|
|
@ -4,9 +4,8 @@ import categoryItem
|
|||
import com.nhaarman.mockitokotlin2.mock
|
||||
import com.nhaarman.mockitokotlin2.whenever
|
||||
import depictedItem
|
||||
import fr.free.nrw.commons.explore.depictions.DepictsClient
|
||||
import fr.free.nrw.commons.upload.GpsCategoryModel
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.Single
|
||||
import io.reactivex.subjects.BehaviorSubject
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
|
@ -35,7 +34,7 @@ class CategoriesModelTest {
|
|||
|
||||
val expectedList = listOf("Test")
|
||||
whenever(categoryClient.searchCategoriesForPrefix("tes", 25))
|
||||
.thenReturn(Observable.just(expectedList))
|
||||
.thenReturn(Single.just(expectedList))
|
||||
|
||||
// Checking if both return "Test"
|
||||
val expectedItems = expectedList.map { CategoryItem(it, false) }
|
||||
|
|
@ -56,7 +55,7 @@ class CategoriesModelTest {
|
|||
whenever(gpsCategoryModel.categoriesFromLocation)
|
||||
.thenReturn(BehaviorSubject.createDefault(listOf("gpsCategory")))
|
||||
whenever(categoryClient.searchCategories("tes", 25))
|
||||
.thenReturn(Observable.just(listOf("titleSearch")))
|
||||
.thenReturn(Single.just(listOf("titleSearch")))
|
||||
whenever(categoryDao.recentCategories(25)).thenReturn(listOf("recentCategories"))
|
||||
CategoriesModel(categoryClient, categoryDao, gpsCategoryModel)
|
||||
.searchAll("", listOf("tes"), listOf(depictedItem))
|
||||
|
|
|
|||
|
|
@ -2,11 +2,10 @@ package fr.free.nrw.commons.category
|
|||
|
||||
import com.nhaarman.mockitokotlin2.mock
|
||||
import com.nhaarman.mockitokotlin2.whenever
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.Single
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.mockito.ArgumentMatchers.anyInt
|
||||
import org.mockito.ArgumentMatchers.anyString
|
||||
import org.mockito.ArgumentMatchers.*
|
||||
import org.mockito.InjectMocks
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.mock
|
||||
|
|
@ -32,7 +31,7 @@ class CategoryClientTest {
|
|||
fun searchCategoriesFound() {
|
||||
val mockResponse = withMockResponse("Category:Test")
|
||||
whenever(categoryInterface.searchCategories(anyString(), anyInt(), anyInt()))
|
||||
.thenReturn(Observable.just(mockResponse))
|
||||
.thenReturn(Single.just(mockResponse))
|
||||
categoryClient.searchCategories("tes", 10)
|
||||
.test()
|
||||
.assertValues(listOf("Test"))
|
||||
|
|
@ -45,7 +44,7 @@ class CategoryClientTest {
|
|||
fun searchCategoriesNull() {
|
||||
val mockResponse = withNullPages()
|
||||
whenever(categoryInterface.searchCategories(anyString(), anyInt(), anyInt()))
|
||||
.thenReturn(Observable.just(mockResponse))
|
||||
.thenReturn(Single.just(mockResponse))
|
||||
categoryClient.searchCategories("tes", 10)
|
||||
.test()
|
||||
.assertValues(emptyList())
|
||||
|
|
@ -58,7 +57,7 @@ class CategoryClientTest {
|
|||
fun searchCategoriesForPrefixFound() {
|
||||
val mockResponse = withMockResponse("Category:Test")
|
||||
whenever(categoryInterface.searchCategoriesForPrefix(anyString(), anyInt(), anyInt()))
|
||||
.thenReturn(Observable.just(mockResponse))
|
||||
.thenReturn(Single.just(mockResponse))
|
||||
categoryClient.searchCategoriesForPrefix("tes", 10)
|
||||
.test()
|
||||
.assertValues(listOf("Test"))
|
||||
|
|
@ -71,7 +70,7 @@ class CategoryClientTest {
|
|||
fun searchCategoriesForPrefixNull() {
|
||||
val mockResponse = withNullPages()
|
||||
whenever(categoryInterface.searchCategoriesForPrefix(anyString(), anyInt(), anyInt()))
|
||||
.thenReturn(Observable.just(mockResponse))
|
||||
.thenReturn(Single.just(mockResponse))
|
||||
categoryClient.searchCategoriesForPrefix("tes", 10)
|
||||
.test()
|
||||
.assertValues(emptyList())
|
||||
|
|
@ -83,8 +82,8 @@ class CategoryClientTest {
|
|||
@Test
|
||||
fun getParentCategoryListFound() {
|
||||
val mockResponse = withMockResponse("Category:Test")
|
||||
whenever(categoryInterface.getParentCategoryList(anyString()))
|
||||
.thenReturn(Observable.just(mockResponse))
|
||||
whenever(categoryInterface.getParentCategoryList(anyString(), anyMap()))
|
||||
.thenReturn(Single.just(mockResponse))
|
||||
categoryClient.getParentCategoryList("tes")
|
||||
.test()
|
||||
.assertValues(listOf("Test"))
|
||||
|
|
@ -93,8 +92,8 @@ class CategoryClientTest {
|
|||
@Test
|
||||
fun getParentCategoryListNull() {
|
||||
val mockResponse = withNullPages()
|
||||
whenever(categoryInterface.getParentCategoryList(anyString()))
|
||||
.thenReturn(Observable.just(mockResponse))
|
||||
whenever(categoryInterface.getParentCategoryList(anyString(), anyMap()))
|
||||
.thenReturn(Single.just(mockResponse))
|
||||
categoryClient.getParentCategoryList("tes")
|
||||
.test()
|
||||
.assertValues(emptyList())
|
||||
|
|
@ -103,8 +102,8 @@ class CategoryClientTest {
|
|||
@Test
|
||||
fun getSubCategoryListFound() {
|
||||
val mockResponse = withMockResponse("Category:Test")
|
||||
whenever(categoryInterface.getSubCategoryList("tes"))
|
||||
.thenReturn(Observable.just(mockResponse))
|
||||
whenever(categoryInterface.getSubCategoryList("tes", emptyMap()))
|
||||
.thenReturn(Single.just(mockResponse))
|
||||
categoryClient.getSubCategoryList("tes")
|
||||
.test()
|
||||
.assertValues(listOf("Test"))
|
||||
|
|
@ -113,8 +112,11 @@ class CategoryClientTest {
|
|||
@Test
|
||||
fun getSubCategoryListNull() {
|
||||
val mockResponse = withNullPages()
|
||||
whenever(categoryInterface.getSubCategoryList(anyString()))
|
||||
.thenReturn(Observable.just(mockResponse))
|
||||
whenever(categoryInterface.getSubCategoryList(
|
||||
anyString(),
|
||||
anyMap()
|
||||
))
|
||||
.thenReturn(Single.just(mockResponse))
|
||||
categoryClient.getSubCategoryList("tes")
|
||||
.test()
|
||||
.assertValues(emptyList())
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
package fr.free.nrw.commons.contributions
|
||||
|
||||
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
|
||||
import com.nhaarman.mockitokotlin2.*
|
||||
import com.nhaarman.mockitokotlin2.verify
|
||||
import com.nhaarman.mockitokotlin2.verifyZeroInteractions
|
||||
import com.nhaarman.mockitokotlin2.whenever
|
||||
import fr.free.nrw.commons.Media
|
||||
import fr.free.nrw.commons.auth.SessionManager
|
||||
import fr.free.nrw.commons.media.MediaClient
|
||||
|
|
@ -58,8 +60,6 @@ class ContributionBoundaryCallbackTest {
|
|||
whenever(mediaClient.getMediaListForUser(anyString())).thenReturn(
|
||||
Single.just(listOf(mock(Media::class.java)))
|
||||
)
|
||||
whenever(mediaClient.doesMediaListForUserHaveMorePages(anyString()))
|
||||
.thenReturn(true)
|
||||
contributionBoundaryCallback.onZeroItemsLoaded()
|
||||
verify(repository).save(anyList<Contribution>());
|
||||
verify(mediaClient).getMediaListForUser(anyString());
|
||||
|
|
@ -73,8 +73,6 @@ class ContributionBoundaryCallbackTest {
|
|||
whenever(mediaClient.getMediaListForUser(anyString())).thenReturn(
|
||||
Single.just(listOf(mock(Media::class.java)))
|
||||
)
|
||||
whenever(mediaClient.doesMediaListForUserHaveMorePages(anyString()))
|
||||
.thenReturn(true)
|
||||
contributionBoundaryCallback.onItemAtEndLoaded(mock(Contribution::class.java))
|
||||
verify(repository).save(anyList());
|
||||
verify(mediaClient).getMediaListForUser(anyString());
|
||||
|
|
@ -88,8 +86,6 @@ class ContributionBoundaryCallbackTest {
|
|||
whenever(mediaClient.getMediaListForUser(anyString())).thenReturn(
|
||||
Single.just(listOf(mock(Media::class.java)))
|
||||
)
|
||||
whenever(mediaClient.doesMediaListForUserHaveMorePages(anyString()))
|
||||
.thenReturn(true)
|
||||
contributionBoundaryCallback.onItemAtFrontLoaded(mock(Contribution::class.java))
|
||||
verify(repository).save(anyList());
|
||||
verify(mediaClient).getMediaListForUser(anyString());
|
||||
|
|
@ -103,28 +99,14 @@ class ContributionBoundaryCallbackTest {
|
|||
whenever(mediaClient.getMediaListForUser(anyString())).thenReturn(
|
||||
Single.just(listOf(mock(Media::class.java)))
|
||||
)
|
||||
whenever(mediaClient.doesMediaListForUserHaveMorePages(anyString()))
|
||||
.thenReturn(true)
|
||||
contributionBoundaryCallback.fetchContributions()
|
||||
verify(repository).save(anyList());
|
||||
verify(mediaClient).getMediaListForUser(anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testFetchContributionsForEndOfList() {
|
||||
whenever(sessionManager.userName).thenReturn("Test")
|
||||
whenever(mediaClient.doesMediaListForUserHaveMorePages(anyString()))
|
||||
.thenReturn(false)
|
||||
contributionBoundaryCallback.fetchContributions()
|
||||
verify(mediaClient, times(0)).getMediaListForUser(anyString())
|
||||
verifyNoMoreInteractions(repository)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testFetchContributionsFailed() {
|
||||
whenever(sessionManager.userName).thenReturn("Test")
|
||||
whenever(mediaClient.doesMediaListForUserHaveMorePages(anyString()))
|
||||
.thenReturn(true)
|
||||
whenever(mediaClient.getMediaListForUser(anyString())).thenReturn(Single.error(Exception("Error")))
|
||||
contributionBoundaryCallback.fetchContributions()
|
||||
verifyZeroInteractions(repository);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
package fr.free.nrw.commons.explore.categories.parent
|
||||
|
||||
import com.nhaarman.mockitokotlin2.never
|
||||
import com.nhaarman.mockitokotlin2.verify
|
||||
import com.nhaarman.mockitokotlin2.whenever
|
||||
import fr.free.nrw.commons.category.CategoryClient
|
||||
import fr.free.nrw.commons.explore.paging.LiveDataConverter
|
||||
import io.reactivex.Single
|
||||
import org.hamcrest.CoreMatchers.`is`
|
||||
import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.mockito.Mock
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
class PageableParentCategoriesDataSourceTest{
|
||||
@Mock
|
||||
lateinit var categoryClient: CategoryClient
|
||||
@Mock
|
||||
lateinit var liveDataConverter: LiveDataConverter
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `loadFunction calls reset at position 0`() {
|
||||
val dataSource =
|
||||
PageableParentCategoriesDataSource(liveDataConverter, categoryClient)
|
||||
dataSource.onQueryUpdated("test")
|
||||
whenever(categoryClient.getParentCategoryList("test"))
|
||||
.thenReturn(Single.just(emptyList()))
|
||||
assertThat(dataSource.loadFunction(-1, 0), `is`(emptyList()))
|
||||
verify(categoryClient).resetParentCategoryContinuation("test")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `loadFunction does not call reset at any other position`() {
|
||||
val dataSource =
|
||||
PageableParentCategoriesDataSource(liveDataConverter, categoryClient)
|
||||
dataSource.onQueryUpdated("test")
|
||||
whenever(categoryClient.getParentCategoryList("test"))
|
||||
.thenReturn(Single.just(emptyList()))
|
||||
assertThat(dataSource.loadFunction(-1, 1), `is`(emptyList()))
|
||||
verify(categoryClient, never()).resetParentCategoryContinuation("test")
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
package fr.free.nrw.commons.explore.categories.sub
|
||||
|
||||
import com.nhaarman.mockitokotlin2.never
|
||||
import com.nhaarman.mockitokotlin2.verify
|
||||
import com.nhaarman.mockitokotlin2.whenever
|
||||
import fr.free.nrw.commons.category.CategoryClient
|
||||
import fr.free.nrw.commons.explore.paging.LiveDataConverter
|
||||
import io.reactivex.Single
|
||||
import org.hamcrest.CoreMatchers.`is`
|
||||
import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.mockito.Mock
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
class PageableSubCategoriesDataSourceTest{
|
||||
@Mock
|
||||
lateinit var categoryClient: CategoryClient
|
||||
@Mock
|
||||
lateinit var liveDataConverter: LiveDataConverter
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `loadFunction calls reset at position 0`() {
|
||||
val dataSource =
|
||||
PageableSubCategoriesDataSource(liveDataConverter, categoryClient)
|
||||
dataSource.onQueryUpdated("test")
|
||||
whenever(categoryClient.getSubCategoryList("test"))
|
||||
.thenReturn(Single.just(emptyList()))
|
||||
assertThat(dataSource.loadFunction(-1, 0), `is`(emptyList()))
|
||||
verify(categoryClient).resetSubCategoryContinuation("test")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `loadFunction does not call reset at any other position`() {
|
||||
val dataSource =
|
||||
PageableSubCategoriesDataSource(liveDataConverter, categoryClient)
|
||||
dataSource.onQueryUpdated("test")
|
||||
whenever(categoryClient.getSubCategoryList("test"))
|
||||
.thenReturn(Single.just(emptyList()))
|
||||
assertThat(dataSource.loadFunction(-1, 1), `is`(emptyList()))
|
||||
verify(categoryClient, never()).resetSubCategoryContinuation("test")
|
||||
}
|
||||
}
|
||||
|
|
@ -3,19 +3,20 @@ 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 io.reactivex.Observable
|
||||
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(Observable.just(emptyList()))
|
||||
val pageableCategoriesDataSource = PageableCategoriesDataSource(mock(), categoryClient)
|
||||
.thenReturn(Single.just(emptyList()))
|
||||
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