Displaying Category image and Description (#4531)

* API call done

* API call

* Image implementation done

* Gradle

* Java docs and code convention

* Description added

* Refactoring Category

* Refactoring Category

* Refactoring Category

* Description and thumbnail issue fixed

* Description and thumbnail issue fixed

* Minor issue fixed

* Minor issue fixed

* Server changed

* Logo changed

* Change in structure

* Fixed failed tests

* Fixed Test failed

* Optimized imports

* Dialog can't be dismissed

* Dialog can't be dismissed

* Resolved Conflicts

* UI fixed

* Added description and thumbnail in local DB

* Added description and thumbnail in local DB

* Test fixed

* Added

* Updated with latest master

* Test Updated with latest master

* Issue fixed

* Revert gradle changes

* Revert gradle changes

* Update gradle-wrapper.properties

* Require Api removed
This commit is contained in:
Ayan Sarkar 2022-01-20 11:49:57 +05:30 committed by GitHub
parent 0914eeea53
commit 92957f4204
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
31 changed files with 373 additions and 151 deletions

View file

@ -5,6 +5,7 @@ import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.RemoteException;
import fr.free.nrw.commons.category.CategoryItem;
import fr.free.nrw.commons.upload.structure.depictions.DepictedItem;
import java.util.ArrayList;
import java.util.Arrays;
@ -141,9 +142,17 @@ public class BookmarkItemsDao {
final String instanceListString
= cursor.getString(cursor.getColumnIndex(Table.COLUMN_INSTANCE_LIST));
final List<String> instanceList = StringToArray(instanceListString);
final String categoryListString = cursor.getString(cursor
.getColumnIndex(Table.COLUMN_CATEGORIES_LIST));
final List<String> categoryList = StringToArray(categoryListString);
final String categoryNameListString = cursor.getString(cursor
.getColumnIndex(Table.COLUMN_CATEGORIES_NAME_LIST));
final List<String> categoryNameList = StringToArray(categoryNameListString);
final String categoryDescriptionListString = cursor.getString(cursor
.getColumnIndex(Table.COLUMN_CATEGORIES_DESCRIPTION_LIST));
final List<String> categoryDescriptionList = StringToArray(categoryDescriptionListString);
final String categoryThumbnailListString = cursor.getString(cursor
.getColumnIndex(Table.COLUMN_CATEGORIES_THUMBNAIL_LIST));
final List<String> categoryThumbnailList = StringToArray(categoryThumbnailListString);
final List<CategoryItem> categoryList = convertToCategoryItems(categoryNameList,
categoryDescriptionList, categoryThumbnailList);
final boolean isSelected
= Boolean.parseBoolean(cursor.getString(cursor
.getColumnIndex(Table.COLUMN_IS_SELECTED)));
@ -160,6 +169,17 @@ public class BookmarkItemsDao {
);
}
private List<CategoryItem> convertToCategoryItems(List<String> categoryNameList,
List<String> categoryDescriptionList, List<String> categoryThumbnailList) {
List<CategoryItem> categoryItems = new ArrayList<>();
for(int i=0; i<categoryNameList.size(); i++){
categoryItems.add(new CategoryItem(categoryNameList.get(i),
categoryDescriptionList.get(i),
categoryThumbnailList.get(i), false));
}
return categoryItems;
}
/**
* Converts string to List
* @param listString comma separated single string from of list items
@ -188,12 +208,35 @@ public class BookmarkItemsDao {
* @return ContentValues
*/
private ContentValues toContentValues(final DepictedItem depictedItem) {
final List<String> namesOfCommonsCategories = new ArrayList<>();
for (final CategoryItem category :
depictedItem.getCommonsCategories()) {
namesOfCommonsCategories.add(category.getName());
}
final List<String> descriptionsOfCommonsCategories = new ArrayList<>();
for (final CategoryItem category :
depictedItem.getCommonsCategories()) {
descriptionsOfCommonsCategories.add(category.getDescription());
}
final List<String> thumbnailsOfCommonsCategories = new ArrayList<>();
for (final CategoryItem category :
depictedItem.getCommonsCategories()) {
thumbnailsOfCommonsCategories.add(category.getThumbnail());
}
final ContentValues cv = new ContentValues();
cv.put(Table.COLUMN_NAME, depictedItem.getName());
cv.put(Table.COLUMN_DESCRIPTION, depictedItem.getDescription());
cv.put(Table.COLUMN_IMAGE, depictedItem.getImageUrl());
cv.put(Table.COLUMN_INSTANCE_LIST, ArrayToString(depictedItem.getInstanceOfs()));
cv.put(Table.COLUMN_CATEGORIES_LIST, ArrayToString(depictedItem.getCommonsCategories()));
cv.put(Table.COLUMN_CATEGORIES_NAME_LIST, ArrayToString(namesOfCommonsCategories));
cv.put(Table.COLUMN_CATEGORIES_DESCRIPTION_LIST,
ArrayToString(descriptionsOfCommonsCategories));
cv.put(Table.COLUMN_CATEGORIES_THUMBNAIL_LIST,
ArrayToString(thumbnailsOfCommonsCategories));
cv.put(Table.COLUMN_IS_SELECTED, depictedItem.isSelected());
cv.put(Table.COLUMN_ID, depictedItem.getId());
return cv;
@ -208,7 +251,9 @@ public class BookmarkItemsDao {
public static final String COLUMN_DESCRIPTION = "item_description";
public static final String COLUMN_IMAGE = "item_image_url";
public static final String COLUMN_INSTANCE_LIST = "item_instance_of";
public static final String COLUMN_CATEGORIES_LIST = "item_categories";
public static final String COLUMN_CATEGORIES_NAME_LIST = "item_name_categories";
public static final String COLUMN_CATEGORIES_DESCRIPTION_LIST = "item_description_categories";
public static final String COLUMN_CATEGORIES_THUMBNAIL_LIST = "item_thumbnail_categories";
public static final String COLUMN_IS_SELECTED = "item_is_selected";
public static final String COLUMN_ID = "item_id";
@ -217,7 +262,9 @@ public class BookmarkItemsDao {
COLUMN_DESCRIPTION,
COLUMN_IMAGE,
COLUMN_INSTANCE_LIST,
COLUMN_CATEGORIES_LIST,
COLUMN_CATEGORIES_NAME_LIST,
COLUMN_CATEGORIES_DESCRIPTION_LIST,
COLUMN_CATEGORIES_THUMBNAIL_LIST,
COLUMN_IS_SELECTED,
COLUMN_ID
};
@ -228,7 +275,9 @@ public class BookmarkItemsDao {
+ COLUMN_DESCRIPTION + " STRING,"
+ COLUMN_IMAGE + " STRING,"
+ COLUMN_INSTANCE_LIST + " STRING,"
+ COLUMN_CATEGORIES_LIST + " STRING,"
+ COLUMN_CATEGORIES_NAME_LIST + " STRING,"
+ COLUMN_CATEGORIES_DESCRIPTION_LIST + " STRING,"
+ COLUMN_CATEGORIES_THUMBNAIL_LIST + " STRING,"
+ COLUMN_IS_SELECTED + " STRING,"
+ COLUMN_ID + " STRING PRIMARY KEY"
+ ");";

View file

@ -56,7 +56,7 @@ class CategoriesModel @Inject constructor(
// Newly used category...
if (category == null) {
category = Category(null, item.name, Date(), 0)
category = Category(null, item.name, item.description, item.thumbnail, Date(), 0)
}
category.incTimesUsed()
categoryDao.save(category)
@ -74,14 +74,14 @@ class CategoriesModel @Inject constructor(
selectedDepictions: List<DepictedItem>
): Observable<List<CategoryItem>> {
return suggestionsOrSearch(term, imageTitleList, selectedDepictions)
.map { it.map { CategoryItem(it, false) } }
.map { it.map { CategoryItem(it.name, it.description, it.thumbnail, false) } }
}
private fun suggestionsOrSearch(
term: String,
imageTitleList: List<String>,
selectedDepictions: List<DepictedItem>
): Observable<List<String>> {
): Observable<List<CategoryItem>> {
return if (TextUtils.isEmpty(term))
Observable.combineLatest(
categoriesFromDepiction(selectedDepictions),
@ -100,10 +100,10 @@ class CategoriesModel @Inject constructor(
Observable.just(selectedDepictions.map { it.commonsCategories }.flatten())
private fun combine(
depictionCategories: List<String>,
locationCategories: List<String>,
titles: List<String>,
recents: List<String>
depictionCategories: List<CategoryItem>,
locationCategories: List<CategoryItem>,
titles: List<CategoryItem>,
recents: List<CategoryItem>
) = depictionCategories + locationCategories + titles + recents
@ -115,7 +115,7 @@ class CategoriesModel @Inject constructor(
private fun titleCategories(titleList: List<String>) =
if (titleList.isNotEmpty())
Observable.combineLatest(titleList.map { getTitleCategories(it) }) { searchResults ->
searchResults.map { it as List<String> }.flatten()
searchResults.map { it as List<CategoryItem> }.flatten()
}
else
Observable.just(emptyList())
@ -125,7 +125,7 @@ class CategoriesModel @Inject constructor(
* @param title
* @return
*/
private fun getTitleCategories(title: String): Observable<List<String>> {
private fun getTitleCategories(title: String): Observable<List<CategoryItem>> {
return categoryClient.searchCategories(title, SEARCH_CATS_LIMIT).toObservable()
}

View file

@ -10,15 +10,19 @@ import java.util.Date;
public class Category {
private Uri contentUri;
private String name;
private String description;
private String thumbnail;
private Date lastUsed;
private int timesUsed;
public Category() {
}
public Category(Uri contentUri, String name, Date lastUsed, int timesUsed) {
public Category(Uri contentUri, String name, String description, String thumbnail, Date lastUsed, int timesUsed) {
this.contentUri = contentUri;
this.name = name;
this.description = description;
this.thumbnail = thumbnail;
this.lastUsed = lastUsed;
this.timesUsed = timesUsed;
}
@ -93,4 +97,19 @@ public class Category {
this.contentUri = contentUri;
}
public String getDescription() {
return description;
}
public String getThumbnail() {
return thumbnail;
}
public void setDescription(final String description) {
this.description = description;
}
public void setThumbnail(final String thumbnail) {
this.thumbnail = thumbnail;
}
}

View file

@ -16,7 +16,7 @@ const val CATEGORY_NEEDING_CATEGORIES = "needing categories"
*/
@Singleton
class CategoryClient @Inject constructor(private val categoryInterface: CategoryInterface) :
ContinuationClient<MwQueryResponse, String>() {
ContinuationClient<MwQueryResponse, CategoryItem>() {
/**
* Searches for categories containing the specified string.
@ -28,7 +28,7 @@ class CategoryClient @Inject constructor(private val categoryInterface: Category
*/
@JvmOverloads
fun searchCategories(filter: String?, itemLimit: Int, offset: Int = 0):
Single<List<String>> {
Single<List<CategoryItem>> {
return responseMapper(categoryInterface.searchCategories(filter, itemLimit, offset))
}
@ -42,7 +42,7 @@ class CategoryClient @Inject constructor(private val categoryInterface: Category
*/
@JvmOverloads
fun searchCategoriesForPrefix(prefix: String?, itemLimit: Int, offset: Int = 0):
Single<List<String>> {
Single<List<CategoryItem>> {
return responseMapper(
categoryInterface.searchCategoriesForPrefix(prefix, itemLimit, offset)
)
@ -55,7 +55,7 @@ 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>> {
fun getSubCategoryList(categoryName: String): Single<List<CategoryItem>> {
return continuationRequest(SUB_CATEGORY_CONTINUATION_PREFIX, categoryName) {
categoryInterface.getSubCategoryList(
categoryName, it
@ -70,7 +70,7 @@ class CategoryClient @Inject constructor(private val categoryInterface: Category
* @param categoryName Category name as defined on commons
* @return
*/
fun getParentCategoryList(categoryName: String): Single<List<String>> {
fun getParentCategoryList(categoryName: String): Single<List<CategoryItem>> {
return continuationRequest(PARENT_CATEGORY_CONTINUATION_PREFIX, categoryName) {
categoryInterface.getParentCategoryList(categoryName, it)
}
@ -87,7 +87,7 @@ class CategoryClient @Inject constructor(private val categoryInterface: Category
override fun responseMapper(
networkResult: Single<MwQueryResponse>,
key: String?
): Single<List<String>> {
): Single<List<CategoryItem>> {
return networkResult
.map {
handleContinuationResponse(it.continuation(), key)
@ -96,7 +96,10 @@ class CategoryClient @Inject constructor(private val categoryInterface: Category
.map {
it.filter {
page -> page.categoryInfo() == null || !page.categoryInfo().isHidden
}.map { page -> page.title().replace(CATEGORY_PREFIX, "") }
}.map {
CategoryItem(it.title().replace(CATEGORY_PREFIX, ""),
it.description().toString(), it.thumbUrl().toString(), false)
}
}
}
}

View file

@ -79,8 +79,8 @@ public class CategoryDao {
* @return a list containing recent categories
*/
@NonNull
List<String> recentCategories(int limit) {
List<String> items = new ArrayList<>();
List<CategoryItem> recentCategories(int limit) {
List<CategoryItem> items = new ArrayList<>();
Cursor cursor = null;
ContentProviderClient db = clientProvider.get();
try {
@ -93,7 +93,9 @@ public class CategoryDao {
// fixme add a limit on the original query instead of falling out of the loop?
while (cursor != null && cursor.moveToNext()
&& cursor.getPosition() < limit) {
items.add(fromCursor(cursor).getName());
items.add(new CategoryItem(fromCursor(cursor).getName(),
fromCursor(cursor).getDescription(), fromCursor(cursor).getThumbnail(),
false));
}
} catch (RemoteException e) {
throw new RuntimeException(e);
@ -112,6 +114,8 @@ public class CategoryDao {
return new Category(
CategoryContentProvider.uriForId(cursor.getInt(cursor.getColumnIndex(Table.COLUMN_ID))),
cursor.getString(cursor.getColumnIndex(Table.COLUMN_NAME)),
cursor.getString(cursor.getColumnIndex(Table.COLUMN_DESCRIPTION)),
cursor.getString(cursor.getColumnIndex(Table.COLUMN_THUMBNAIL)),
new Date(cursor.getLong(cursor.getColumnIndex(Table.COLUMN_LAST_USED))),
cursor.getInt(cursor.getColumnIndex(Table.COLUMN_TIMES_USED))
);
@ -120,6 +124,8 @@ public class CategoryDao {
private ContentValues toContentValues(Category category) {
ContentValues cv = new ContentValues();
cv.put(CategoryDao.Table.COLUMN_NAME, category.getName());
cv.put(Table.COLUMN_DESCRIPTION, category.getDescription());
cv.put(Table.COLUMN_THUMBNAIL, category.getThumbnail());
cv.put(CategoryDao.Table.COLUMN_LAST_USED, category.getLastUsed().getTime());
cv.put(CategoryDao.Table.COLUMN_TIMES_USED, category.getTimesUsed());
return cv;
@ -130,6 +136,8 @@ public class CategoryDao {
public static final String COLUMN_ID = "_id";
static final String COLUMN_NAME = "name";
static final String COLUMN_DESCRIPTION = "description";
static final String COLUMN_THUMBNAIL = "thumbnail";
static final String COLUMN_LAST_USED = "last_used";
static final String COLUMN_TIMES_USED = "times_used";
@ -137,6 +145,8 @@ public class CategoryDao {
public static final String[] ALL_FIELDS = {
COLUMN_ID,
COLUMN_NAME,
COLUMN_DESCRIPTION,
COLUMN_THUMBNAIL,
COLUMN_LAST_USED,
COLUMN_TIMES_USED
};
@ -146,6 +156,8 @@ public class CategoryDao {
static final String CREATE_TABLE_STATEMENT = "CREATE TABLE " + TABLE_NAME + " ("
+ COLUMN_ID + " INTEGER PRIMARY KEY,"
+ COLUMN_NAME + " STRING,"
+ COLUMN_DESCRIPTION + " STRING,"
+ COLUMN_THUMBNAIL + " STRING,"
+ COLUMN_LAST_USED + " INTEGER,"
+ COLUMN_TIMES_USED + " INTEGER"
+ ");";

View file

@ -94,8 +94,14 @@ public class CategoryEditSearchRecyclerViewAdapter
@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
List<String> resultCategories = categoryClient.searchCategories(constraint.toString(), 10).blockingGet();
results.values = resultCategories;
List<CategoryItem> resultCategories = categoryClient
.searchCategories(constraint.toString(), 10).blockingGet();
final List<String> namesOfCommonsCategories = new ArrayList<>();
for (final CategoryItem category :
resultCategories) {
namesOfCommonsCategories.add(category.getName());
}
results.values = namesOfCommonsCategories;
results.count = resultCategories.size();
return results;
}

View file

@ -20,9 +20,11 @@ public interface CategoryInterface {
* @return
*/
@GET("w/api.php?action=query&format=json&formatversion=2"
+ "&generator=search&gsrnamespace=14")
+ "&generator=search&prop=description|pageimages&piprop=thumbnail&pithumbsize=70"
+ "&gsrnamespace=14")
Single<MwQueryResponse> searchCategories(@Query("gsrsearch") String filter,
@Query("gsrlimit") int itemLimit, @Query("gsroffset") int offset);
@Query("gsrlimit") int itemLimit,
@Query("gsroffset") int offset);
/**
* Searches for categories starting with the specified prefix.
@ -32,9 +34,11 @@ public interface CategoryInterface {
* @return
*/
@GET("w/api.php?action=query&format=json&formatversion=2"
+ "&generator=allcategories&prop=categoryinfo")
+ "&generator=allcategories&prop=categoryinfo|description|pageimages&piprop=thumbnail"
+ "&pithumbsize=70")
Single<MwQueryResponse> searchCategoriesForPrefix(@Query("gacprefix") String prefix,
@Query("gaclimit") int itemLimit, @Query("gacoffset") int offset);
@Query("gaclimit") int itemLimit,
@Query("gacoffset") int offset);
@GET("w/api.php?action=query&format=json&formatversion=2"
+ "&generator=categorymembers&gcmtype=subcat"

View file

@ -4,7 +4,8 @@ import android.os.Parcelable
import kotlinx.android.parcel.Parcelize
@Parcelize
data class CategoryItem(val name: String, var isSelected: Boolean) : Parcelable {
data class CategoryItem(val name: String, val description: String,
val thumbnail: String, var isSelected: Boolean) : Parcelable {
override fun toString(): String {
return "CategoryItem: '$name'"

View file

@ -250,8 +250,10 @@ public class NetworkingModule {
@Provides
@Singleton
public CategoryInterface provideCategoryInterface(@Named(NAMED_COMMONS_WIKI_SITE) WikiSite commonsWikiSite) {
return ServiceFactory.get(commonsWikiSite, BuildConfig.COMMONS_URL, CategoryInterface.class);
public CategoryInterface provideCategoryInterface(
@Named(NAMED_COMMONS_WIKI_SITE) WikiSite commonsWikiSite) {
return ServiceFactory
.get(commonsWikiSite, BuildConfig.COMMONS_URL, CategoryInterface.class);
}
@Provides

View file

@ -14,6 +14,6 @@ class PageableParentCategoriesDataSource @Inject constructor(
if (startPosition == 0) {
categoryClient.resetParentCategoryContinuation(query)
}
categoryClient.getParentCategoryList(query).blockingGet()
categoryClient.getParentCategoryList(query).blockingGet().map { it.name }
}
}

View file

@ -12,5 +12,6 @@ class PageableSearchCategoriesDataSource @Inject constructor(
override val loadFunction = { loadSize: Int, startPosition: Int ->
categoryClient.searchCategories(query, loadSize, startPosition).blockingGet()
.map { it.name }
}
}

View file

@ -14,6 +14,6 @@ class PageableSubCategoriesDataSource @Inject constructor(
if (startPosition == 0) {
categoryClient.resetSubCategoryContinuation(query)
}
categoryClient.getSubCategoryList(query).blockingGet()
categoryClient.getSubCategoryList(query).blockingGet().map { it.name }
}
}

View file

@ -3,6 +3,7 @@ package fr.free.nrw.commons.mwapi;
import static fr.free.nrw.commons.category.CategoryClientKt.CATEGORY_PREFIX;
import com.google.gson.Gson;
import fr.free.nrw.commons.category.CategoryItem;
import io.reactivex.Single;
import java.util.ArrayList;
import java.util.Collections;
@ -40,7 +41,7 @@ public class CategoryApi {
this.gson = gson;
}
public Single<List<String>> request(String coords) {
public Single<List<CategoryItem>> request(String coords) {
return Single.fromCallable(() -> {
HttpUrl apiUrl = buildUrl(coords);
Timber.d("URL: %s", apiUrl.toString());
@ -53,12 +54,12 @@ public class CategoryApi {
}
MwQueryResponse apiResponse = gson.fromJson(body.charStream(), MwQueryResponse.class);
Set<String> categories = new LinkedHashSet<>();
Set<CategoryItem> categories = new LinkedHashSet<>();
if (apiResponse != null && apiResponse.query() != null && apiResponse.query().pages() != null) {
for (MwQueryPage page : apiResponse.query().pages()) {
if (page.categories() != null) {
for (MwQueryPage.Category category : page.categories()) {
categories.add(category.title().replace(CATEGORY_PREFIX, ""));
categories.add(new CategoryItem(category.title().replace(CATEGORY_PREFIX, ""), "", "", false));
}
}
}

View file

@ -1,18 +1,19 @@
package fr.free.nrw.commons.upload
import fr.free.nrw.commons.category.CategoryItem
import io.reactivex.subjects.BehaviorSubject
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class GpsCategoryModel @Inject constructor() {
val categoriesFromLocation = BehaviorSubject.createDefault(emptyList<String>())
val categoriesFromLocation = BehaviorSubject.createDefault(emptyList<CategoryItem>())
fun clear() {
categoriesFromLocation.onNext(emptyList())
}
fun setCategoriesFromLocation(categoryList: List<String>) {
fun setCategoriesFromLocation(categoryList: List<CategoryItem>) {
categoriesFromLocation.onNext(categoryList)
}
}

View file

@ -1,8 +1,10 @@
package fr.free.nrw.commons.upload.categories
import fr.free.nrw.commons.category.CategoryItem
import org.jetbrains.annotations.NotNull
class UploadCategoryAdapter(onCategoryClicked: (CategoryItem) -> Unit) :
class UploadCategoryAdapter(
onCategoryClicked: @NotNull() (CategoryItem) -> Unit) :
BaseDelegateAdapter<CategoryItem>(
uploadCategoryDelegate(onCategoryClicked),
areItemsTheSame = { oldItem, newItem -> oldItem.name == newItem.name },

View file

@ -1,20 +1,38 @@
package fr.free.nrw.commons.upload.categories
import android.view.View
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
import fr.free.nrw.commons.R
import fr.free.nrw.commons.category.CategoryItem
import fr.free.nrw.commons.databinding.LayoutUploadCategoriesItemBinding
fun uploadCategoryDelegate(onCategoryClicked: (CategoryItem) -> Unit) =
adapterDelegateViewBinding<CategoryItem, CategoryItem, LayoutUploadCategoriesItemBinding>({ layoutInflater, root ->
adapterDelegateViewBinding<CategoryItem, CategoryItem,
LayoutUploadCategoriesItemBinding>({ layoutInflater, root ->
LayoutUploadCategoriesItemBinding.inflate(layoutInflater, root, false)
}) {
binding.root.setOnClickListener {
val onClickListener = { _: View? ->
item.isSelected = !item.isSelected
binding.uploadCategoryCheckbox.isChecked = item.isSelected
onCategoryClicked(item)
}
binding.root.setOnClickListener(onClickListener)
binding.uploadCategoryCheckbox.setOnClickListener(onClickListener)
bind {
binding.uploadCategoryCheckbox.isChecked = item.isSelected
binding.uploadCategoryCheckbox.text = item.name
binding.categoryLabel.text = item.name
if(item.thumbnail != "null") {
binding.categoryImage.setImageURI(item.thumbnail)
} else {
binding.categoryImage.setActualImageResource(R.drawable.commons)
}
if(item.description != "null") {
binding.categoryDescription.text = item.description
} else {
binding.categoryDescription.text = ""
}
}
}

View file

@ -3,6 +3,7 @@ package fr.free.nrw.commons.upload.structure.depictions
import android.os.Parcelable
import androidx.room.Entity
import androidx.room.PrimaryKey
import fr.free.nrw.commons.category.CategoryItem
import fr.free.nrw.commons.nearby.Place
import fr.free.nrw.commons.upload.WikidataItem
import fr.free.nrw.commons.wikidata.WikidataProperties
@ -28,7 +29,7 @@ data class DepictedItem constructor(
val description: String?,
val imageUrl: String?,
val instanceOfs: List<String>,
val commonsCategories: List<String>,
val commonsCategories: List<CategoryItem>,
var isSelected: Boolean,
@PrimaryKey override val id: String
) : WikidataItem, Parcelable {
@ -52,7 +53,8 @@ data class DepictedItem constructor(
getImageUrl(it.value, THUMB_IMAGE_SIZE)
},
entity[INSTANCE_OF].toIds(),
entity[COMMONS_CATEGORY]?.map { (it.mainSnak.dataValue as DataValue.ValueString).value }
entity[COMMONS_CATEGORY]?.map { CategoryItem((it.mainSnak.dataValue as DataValue.ValueString).value,
"", "", false) }
?: emptyList(),
false,
entity.id()

View file

@ -1,5 +1,6 @@
package fr.free.nrw.commons.utils;
import fr.free.nrw.commons.category.CategoryItem;
import java.util.Comparator;
public class StringSortingUtils {
@ -16,10 +17,10 @@ public class StringSortingUtils {
* @param filter String to compare similarity with
* @return Comparator with string similarity
*/
public static Comparator<String> sortBySimilarity(final String filter) {
public static Comparator<CategoryItem> sortBySimilarity(final String filter) {
return (firstItem, secondItem) -> {
double firstItemSimilarity = calculateSimilarity(firstItem, filter);
double secondItemSimilarity = calculateSimilarity(secondItem, filter);
double firstItemSimilarity = calculateSimilarity(firstItem.getName(), filter);
double secondItemSimilarity = calculateSimilarity(secondItem.getName(), filter);
return (int) Math.signum(secondItemSimilarity - firstItemSimilarity);
};
}

View file

@ -1,9 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<CheckBox xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/uploadCategoryCheckbox"
android:layout_width="match_parent"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/category_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<CheckBox
android:id="@+id/upload_category_checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checkMark="?android:attr/textCheckMark"
android:checked="false"
android:gravity="center_vertical"
android:padding="@dimen/tiny_gap"/>
android:padding="@dimen/tiny_gap"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/category_image"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/category_image"
android:layout_width="50dp"
android:layout_height="50dp"
android:paddingEnd="@dimen/tiny_gap"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="@+id/upload_category_checkbox"
app:layout_constraintTop_toTopOf="parent"
app:placeholderImage="@drawable/commons" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/category_image"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/category_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:text="@string/label"
android:textStyle="bold" />
<TextView
android:id="@+id/category_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:text="@string/description" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -652,6 +652,8 @@ Upload your first media by tapping on the add button.</string>
The shadow of the image view of the location picker</string>
<string name="image_location">Image Location</string>
<string name="check_whether_location_is_correct">Check whether location is correct</string>
<string name="label">Label</string>
<string name="description">Description</string>
<string name="title_page_bookmarks_items">Items</string>
<string name="custom_selector_title">Custom Selector</string>
<string name="custom_selector_empty_text">No Images</string>