Fix category search bug (#3080)

* Closes #3027
* Concat category search with search with image title list and default categories

* Fixed unit test CategoriesPresenterTest.searchForCategoriesTest

* bug fix [search for categories even when the edit text is empty (perform title based search)]

* Category items should show the selected item on top
This commit is contained in:
Ashish Kumar 2019-07-21 19:20:35 +05:30 committed by Josephine Lim
parent 32715d9cce
commit 8cd9bd5524
6 changed files with 89 additions and 10 deletions

View file

@ -48,9 +48,22 @@ public class CategoriesModel{
*/
public Comparator<CategoryItem> sortBySimilarity(final String filter) {
Comparator<String> stringSimilarityComparator = StringSortingUtils.sortBySimilarity(filter);
return (firstItem, secondItem) -> stringSimilarityComparator
return (firstItem, secondItem) -> {
//if the category is selected, it should get precedence
if (null != firstItem && firstItem.isSelected()) {
if (null != secondItem && secondItem.isSelected()) {
return stringSimilarityComparator
.compare(firstItem.getName(), secondItem.getName());
}
return -1;
}
if (null != secondItem && secondItem.isSelected()) {
return 1;
}
return stringSimilarityComparator
.compare(firstItem.getName(), secondItem.getName());
};
}
/**
* Returns if the item contains an year
@ -255,4 +268,38 @@ public class CategoriesModel{
this.categoriesCache.clear();
this.selectedCategories.clear();
}
/**
* Search for categories
*/
public Observable<CategoryItem> searchCategories(String query, List<String> imageTitleList) {
if (TextUtils.isEmpty(query)) {
return gpsCategories()
.concatWith(titleCategories(imageTitleList))
.concatWith(recentCategories());
}
return mwApi
.searchCategories(query, SEARCH_CATS_LIMIT)
.map(s -> new CategoryItem(s, false));
}
/**
* Returns default categories
*/
public Observable<CategoryItem> getDefaultCategories(List<String> titleList) {
Observable<CategoryItem> directCategories = directCategories();
if (hasDirectCategories()) {
Timber.d("Image has direct Categories");
return directCategories
.concatWith(gpsCategories())
.concatWith(titleCategories(titleList))
.concatWith(recentCategories());
} else {
Timber.d("Image has no direct Categories");
return gpsCategories()
.concatWith(titleCategories(titleList))
.concatWith(recentCategories());
}
}
}

View file

@ -11,10 +11,8 @@ import fr.free.nrw.commons.upload.UploadModel;
import fr.free.nrw.commons.upload.UploadModel.UploadItem;
import io.reactivex.Observable;
import io.reactivex.Single;
import java.util.Comparator;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Singleton;
@ -167,7 +165,7 @@ public class UploadRemoteDataSource {
}
/**
* ask the UplaodModel for the image quality of the UploadItem
* ask the UploadModel for the image quality of the UploadItem
*
* @param uploadItem
* @param shouldValidateTitle
@ -176,4 +174,21 @@ public class UploadRemoteDataSource {
public Single<Integer> getImageQuality(UploadItem uploadItem, boolean shouldValidateTitle) {
return uploadModel.getImageQuality(uploadItem, shouldValidateTitle);
}
/**
* Ask the CategoriesModel to search categories
* @param query
* @param imageTitleList
* @return
*/
public Observable<CategoryItem> searchCategories(String query, List<String> imageTitleList) {
return categoriesModel.searchCategories(query, imageTitleList);
}
/**
* Ask the CategoriesModel for default categories
*/
public Observable<CategoryItem> getDefaultCategories(List<String> imageTitleList) {
return categoriesModel.getDefaultCategories(imageTitleList);
}
}

View file

@ -8,10 +8,8 @@ import fr.free.nrw.commons.upload.SimilarImageInterface;
import fr.free.nrw.commons.upload.UploadModel.UploadItem;
import io.reactivex.Observable;
import io.reactivex.Single;
import java.util.Comparator;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Singleton;
@ -262,4 +260,18 @@ public class UploadRepository {
public void setSelectedLicense(String licenseName) {
localDataSource.setSelectedLicense(licenseName);
}
/**
* Ask the RemoteDataSource to search for categories
*/
public Observable<CategoryItem> searchCategories(String query, List<String> imageTitleList) {
return remoteDataSource.searchCategories(query, imageTitleList);
}
/**
* Ask the RemoteDataSource to get default categories
*/
public Observable<CategoryItem> getDefaultCategories(List<String> imageTitleList) {
return remoteDataSource.getDefaultCategories(imageTitleList);
}
}

View file

@ -80,6 +80,9 @@ public class CategoriesPresenter implements CategoriesContract.UserActionListene
.observeOn(ioScheduler)
.concatWith(
repository.searchAll(query, imageTitleList)
.mergeWith(repository.searchCategories(query, imageTitleList))
.concatWith(TextUtils.isEmpty(query) ? repository
.getDefaultCategories(imageTitleList) : Observable.empty())
)
.filter(categoryItem -> !repository.containsYear(categoryItem.getName()))
.distinct();

View file

@ -89,7 +89,7 @@ public class UploadCategoriesFragment extends UploadBaseFragment implements Cate
@Override
public void onResume() {
super.onResume();
if (presenter != null && isVisible && (categories == null || categories.isEmpty())) {
if (presenter != null && isVisible) {
presenter.searchForCategories(null);
}
}
@ -193,7 +193,7 @@ public class UploadCategoriesFragment extends UploadBaseFragment implements Cate
super.setUserVisibleHint(isVisibleToUser);
isVisible = isVisibleToUser;
if (presenter != null && isResumed() && (categories == null || categories.isEmpty())) {
if (presenter != null && isResumed()) {
presenter.searchForCategories(null);
}
}

View file

@ -57,7 +57,9 @@ class CategoriesPresenterTest {
fun searchForCategoriesTest() {
Mockito.`when`(repository?.sortBySimilarity(ArgumentMatchers.anyString())).thenReturn(Comparator<CategoryItem> { _, _ -> 1 })
Mockito.`when`(repository?.selectedCategories).thenReturn(categoryItems)
Mockito.`when`(repository?.searchAll(ArgumentMatchers.anyString(), ArgumentMatchers.anyList())).thenReturn(Observable.empty())
Mockito.`when`(repository?.searchAll(ArgumentMatchers.anyString(), ArgumentMatchers.anyList())).thenReturn(testObservable)
Mockito.`when`(repository?.searchCategories(ArgumentMatchers.anyString(), ArgumentMatchers.anyList())).thenReturn(testObservable)
Mockito.`when`(repository?.getDefaultCategories(ArgumentMatchers.anyList())).thenReturn(testObservable)
categoriesPresenter?.searchForCategories("test")
verify(view)?.showProgress(true)
verify(view)?.showError(null)