mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 20:33:53 +01:00
Added bookmark Wikidata items option (#4515)
* classes * Almost done * All done but build fail * All done but build fail * Modifications * Modifications * Fixed * string resource * minor change * Maintained code conventions * Moving * Exception handled * id name changed * Test fail fixed * Bookmark is available from other activities * Test fail fixed * Documentation error fixed * Test added * Revert Project_Default.xml * Minor Change * Revert changes
This commit is contained in:
parent
3c29f45f15
commit
38ed364423
28 changed files with 1222 additions and 4 deletions
|
|
@ -258,6 +258,7 @@ android {
|
|||
buildConfigField "String", "RECENT_SEARCH_AUTHORITY", "\"fr.free.nrw.commons.explore.recentsearches.contentprovider\""
|
||||
buildConfigField "String", "BOOKMARK_AUTHORITY", "\"fr.free.nrw.commons.bookmarks.contentprovider\""
|
||||
buildConfigField "String", "BOOKMARK_LOCATIONS_AUTHORITY", "\"fr.free.nrw.commons.bookmarks.locations.contentprovider\""
|
||||
buildConfigField "String", "BOOKMARK_ITEMS_AUTHORITY", "\"fr.free.nrw.commons.bookmarks.items.contentprovider\""
|
||||
buildConfigField "String", "COMMIT_SHA", "\"" + getBuildVersion().toString() + "\""
|
||||
buildConfigField "String", "TEST_USERNAME", "\"" + System.getenv("test_user_name") + "\""
|
||||
buildConfigField "String", "TEST_PASSWORD", "\"" + System.getenv("test_user_password") + "\""
|
||||
|
|
@ -292,6 +293,7 @@ android {
|
|||
buildConfigField "String", "RECENT_SEARCH_AUTHORITY", "\"fr.free.nrw.commons.beta.explore.recentsearches.contentprovider\""
|
||||
buildConfigField "String", "BOOKMARK_AUTHORITY", "\"fr.free.nrw.commons.beta.bookmarks.contentprovider\""
|
||||
buildConfigField "String", "BOOKMARK_LOCATIONS_AUTHORITY", "\"fr.free.nrw.commons.beta.bookmarks.locations.contentprovider\""
|
||||
buildConfigField "String", "BOOKMARK_ITEMS_AUTHORITY", "\"fr.free.nrw.commons.beta.bookmarks.items.contentprovider\""
|
||||
buildConfigField "String", "COMMIT_SHA", "\"" + getBuildVersion().toString() + "\""
|
||||
buildConfigField "String", "TEST_USERNAME", "\"" + System.getenv("test_user_name") + "\""
|
||||
buildConfigField "String", "TEST_PASSWORD", "\"" + System.getenv("test_user_password") + "\""
|
||||
|
|
|
|||
|
|
@ -208,7 +208,14 @@
|
|||
android:label="@string/provider_bookmarks_location"
|
||||
android:syncable="false" />
|
||||
|
||||
<receiver android:name=".widget.PicOfDayAppWidget">
|
||||
<provider
|
||||
android:name=".bookmarks.items.BookmarkItemsContentProvider"
|
||||
android:authorities="${applicationId}.bookmarks.items.contentprovider"
|
||||
android:exported="false"
|
||||
android:label="@string/provider_bookmarks_location"
|
||||
android:syncable="false" />
|
||||
|
||||
<receiver android:name=".widget.PicOfDayAppWidget">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||
</intent-filter>
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import com.mapbox.mapboxsdk.Mapbox;
|
|||
import com.squareup.leakcanary.LeakCanary;
|
||||
import com.squareup.leakcanary.RefWatcher;
|
||||
import fr.free.nrw.commons.auth.SessionManager;
|
||||
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsDao.Table;
|
||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao;
|
||||
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesDao;
|
||||
import fr.free.nrw.commons.category.CategoryDao;
|
||||
|
|
@ -349,6 +350,7 @@ public class CommonsApplication extends MultiDexApplication {
|
|||
}
|
||||
BookmarkPicturesDao.Table.onDelete(db);
|
||||
BookmarkLocationsDao.Table.onDelete(db);
|
||||
Table.onDelete(db);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import butterknife.BindView;
|
|||
import butterknife.ButterKnife;
|
||||
import fr.free.nrw.commons.Media;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsFragment;
|
||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsFragment;
|
||||
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesFragment;
|
||||
import fr.free.nrw.commons.category.CategoryImagesCallback;
|
||||
|
|
@ -48,10 +49,14 @@ public class BookmarkListRootFragment extends CommonsDaggerSupportFragment imple
|
|||
public BookmarkListRootFragment(Bundle bundle, BookmarksPagerAdapter bookmarksPagerAdapter) {
|
||||
String title = bundle.getString("categoryName");
|
||||
int order = bundle.getInt("order");
|
||||
final int orderItem = bundle.getInt("orderItem");
|
||||
if (order == 0) {
|
||||
listFragment = new BookmarkPicturesFragment();
|
||||
} else {
|
||||
listFragment = new BookmarkLocationsFragment();
|
||||
if(orderItem == 2) {
|
||||
listFragment = new BookmarkItemsFragment();
|
||||
}
|
||||
}
|
||||
Bundle featuredArguments = new Bundle();
|
||||
featuredArguments.putString("categoryName", title);
|
||||
|
|
|
|||
|
|
@ -44,6 +44,11 @@ public class BookmarksPagerAdapter extends FragmentPagerAdapter {
|
|||
pages.add(new BookmarkPages(
|
||||
new BookmarkListRootFragment(locationBundle, this),
|
||||
context.getString(R.string.title_page_bookmarks_locations)));
|
||||
|
||||
locationBundle.putInt("orderItem", 2);
|
||||
pages.add(new BookmarkPages(
|
||||
new BookmarkListRootFragment(locationBundle, this),
|
||||
context.getString(R.string.title_page_bookmarks_items)));
|
||||
}
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
package fr.free.nrw.commons.bookmarks.items
|
||||
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.facebook.drawee.view.SimpleDraweeView
|
||||
import fr.free.nrw.commons.R
|
||||
import fr.free.nrw.commons.explore.depictions.WikidataItemDetailsActivity
|
||||
import fr.free.nrw.commons.upload.structure.depictions.DepictedItem
|
||||
|
||||
/**
|
||||
* Helps to inflate Wikidata Items into Items tab
|
||||
*/
|
||||
class BookmarkItemsAdapter (val list: List<DepictedItem>, val context: Context) :
|
||||
RecyclerView.Adapter<BookmarkItemsAdapter.BookmarkItemViewHolder>() {
|
||||
|
||||
class BookmarkItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||
|
||||
var depictsLabel: TextView = itemView.findViewById(R.id.depicts_label)
|
||||
var description: TextView = itemView.findViewById(R.id.description)
|
||||
var depictsImage: SimpleDraweeView = itemView.findViewById(R.id.depicts_image)
|
||||
var layout : ConstraintLayout = itemView.findViewById(R.id.layout_item)
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BookmarkItemViewHolder {
|
||||
val v: View = LayoutInflater.from(context)
|
||||
.inflate(R.layout.item_depictions, parent, false)
|
||||
return BookmarkItemViewHolder(v)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: BookmarkItemViewHolder, position: Int) {
|
||||
|
||||
val depictedItem = list[position]
|
||||
holder.depictsLabel.text = depictedItem.name
|
||||
holder.description.text = depictedItem.description
|
||||
|
||||
if (depictedItem.imageUrl?.isNotBlank() == true) {
|
||||
holder.depictsImage.setImageURI(depictedItem.imageUrl)
|
||||
} else {
|
||||
holder.depictsImage.setActualImageResource(R.drawable.ic_wikidata_logo_24dp)
|
||||
}
|
||||
holder.layout.setOnClickListener {
|
||||
WikidataItemDetailsActivity.startYourself(context, depictedItem)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return list.size
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
package fr.free.nrw.commons.bookmarks.items;
|
||||
|
||||
import static fr.free.nrw.commons.bookmarks.items.BookmarkItemsDao.Table.COLUMN_ID;
|
||||
import static fr.free.nrw.commons.bookmarks.items.BookmarkItemsDao.Table.TABLE_NAME;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteQueryBuilder;
|
||||
import android.net.Uri;
|
||||
import android.text.TextUtils;
|
||||
import androidx.annotation.NonNull;
|
||||
import fr.free.nrw.commons.BuildConfig;
|
||||
import fr.free.nrw.commons.data.DBOpenHelper;
|
||||
import fr.free.nrw.commons.di.CommonsDaggerContentProvider;
|
||||
import javax.inject.Inject;
|
||||
import timber.log.Timber;
|
||||
|
||||
/**
|
||||
* Handles private storage for bookmarked items
|
||||
*/
|
||||
public class BookmarkItemsContentProvider extends CommonsDaggerContentProvider {
|
||||
|
||||
private static final String BASE_PATH = "bookmarksItems";
|
||||
public static final Uri BASE_URI =
|
||||
Uri.parse("content://" + BuildConfig.BOOKMARK_ITEMS_AUTHORITY + "/" + BASE_PATH);
|
||||
|
||||
|
||||
/**
|
||||
* Append bookmark items ID to the base uri
|
||||
*/
|
||||
public static Uri uriForName(final String id) {
|
||||
return Uri.parse(BASE_URI + "/" + id);
|
||||
}
|
||||
|
||||
@Inject
|
||||
DBOpenHelper dbOpenHelper;
|
||||
|
||||
@Override
|
||||
public String getType(@NonNull final Uri uri) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries the SQLite database for the bookmark items
|
||||
* @param uri : contains the uri for bookmark items
|
||||
* @param projection : contains the all fields of the table
|
||||
* @param selection : handles Where
|
||||
* @param selectionArgs : the condition of Where clause
|
||||
* @param sortOrder : ascending or descending
|
||||
*/
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@Override
|
||||
public Cursor query(@NonNull final Uri uri, final String[] projection, final String selection,
|
||||
final String[] selectionArgs, final String sortOrder) {
|
||||
final SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
|
||||
queryBuilder.setTables(TABLE_NAME);
|
||||
final SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
|
||||
final Cursor cursor = queryBuilder.query(db, projection, selection,
|
||||
selectionArgs, null, null, sortOrder);
|
||||
cursor.setNotificationUri(getContext().getContentResolver(), uri);
|
||||
return cursor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the update query of local SQLite Database
|
||||
* @param uri : contains the uri for bookmark items
|
||||
* @param contentValues : new values to be entered to db
|
||||
* @param selection : handles Where
|
||||
* @param selectionArgs : the condition of Where clause
|
||||
*/
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@Override
|
||||
public int update(@NonNull final Uri uri, final ContentValues contentValues,
|
||||
final String selection, final String[] selectionArgs) {
|
||||
final SQLiteDatabase sqlDB = dbOpenHelper.getWritableDatabase();
|
||||
final int rowsUpdated;
|
||||
if (TextUtils.isEmpty(selection)) {
|
||||
final int id = Integer.parseInt(uri.getLastPathSegment());
|
||||
rowsUpdated = sqlDB.update(TABLE_NAME,
|
||||
contentValues,
|
||||
COLUMN_ID + " = ?",
|
||||
new String[]{String.valueOf(id)});
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"Parameter `selection` should be empty when updating an ID");
|
||||
}
|
||||
|
||||
getContext().getContentResolver().notifyChange(uri, null);
|
||||
return rowsUpdated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the insertion of new bookmark items record to local SQLite Database
|
||||
* @param uri
|
||||
* @param contentValues
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@Override
|
||||
public Uri insert(@NonNull final Uri uri, final ContentValues contentValues) {
|
||||
final SQLiteDatabase sqlDB = dbOpenHelper.getWritableDatabase();
|
||||
final long id = sqlDB.insert(TABLE_NAME, null, contentValues);
|
||||
getContext().getContentResolver().notifyChange(uri, null);
|
||||
return Uri.parse(BASE_URI + "/" + id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the deletion of new bookmark items record to local SQLite Database
|
||||
* @param uri
|
||||
* @param s
|
||||
* @param strings
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@Override
|
||||
public int delete(@NonNull final Uri uri, final String s, final String[] strings) {
|
||||
final int rows;
|
||||
final SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
|
||||
Timber.d("Deleting bookmark name %s", uri.getLastPathSegment());
|
||||
rows = db.delete(
|
||||
TABLE_NAME,
|
||||
"item_id = ?",
|
||||
new String[]{uri.getLastPathSegment()}
|
||||
);
|
||||
getContext().getContentResolver().notifyChange(uri, null);
|
||||
return rows;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package fr.free.nrw.commons.bookmarks.items;
|
||||
|
||||
import fr.free.nrw.commons.upload.structure.depictions.DepictedItem;
|
||||
import java.util.List;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
/**
|
||||
* Handles loading bookmarked items from Database
|
||||
*/
|
||||
@Singleton
|
||||
public class BookmarkItemsController {
|
||||
|
||||
@Inject
|
||||
BookmarkItemsDao bookmarkItemsDao;
|
||||
|
||||
@Inject
|
||||
public BookmarkItemsController() {}
|
||||
|
||||
/**
|
||||
* Load from DB the bookmarked items
|
||||
* @return a list of DepictedItem objects.
|
||||
*/
|
||||
public List<DepictedItem> loadFavoritesItems() {
|
||||
return bookmarkItemsDao.getAllBookmarksItems();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,282 @@
|
|||
package fr.free.nrw.commons.bookmarks.items;
|
||||
|
||||
import android.content.ContentProviderClient;
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.os.RemoteException;
|
||||
import fr.free.nrw.commons.upload.structure.depictions.DepictedItem;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Provider;
|
||||
import javax.inject.Singleton;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
* Handles database operations for bookmarked items
|
||||
*/
|
||||
@Singleton
|
||||
public class BookmarkItemsDao {
|
||||
|
||||
private final Provider<ContentProviderClient> clientProvider;
|
||||
|
||||
@Inject
|
||||
public BookmarkItemsDao(
|
||||
@Named("bookmarksItem") final Provider<ContentProviderClient> clientProvider) {
|
||||
this.clientProvider = clientProvider;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find all persisted items bookmarks on database
|
||||
* @return list of bookmarks
|
||||
*/
|
||||
public List<DepictedItem> getAllBookmarksItems() {
|
||||
final List<DepictedItem> items = new ArrayList<>();
|
||||
final ContentProviderClient db = clientProvider.get();
|
||||
try (final Cursor cursor = db.query(
|
||||
BookmarkItemsContentProvider.BASE_URI,
|
||||
Table.ALL_FIELDS,
|
||||
null,
|
||||
new String[]{},
|
||||
null)) {
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
items.add(fromCursor(cursor));
|
||||
}
|
||||
} catch (final RemoteException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
db.release();
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Look for a bookmark in database and in order to insert or delete it
|
||||
* @param depictedItem : Bookmark object
|
||||
* @return boolean : is bookmark now favorite ?
|
||||
*/
|
||||
public boolean updateBookmarkItem(final DepictedItem depictedItem) {
|
||||
final boolean bookmarkExists = findBookmarkItem(depictedItem.getId());
|
||||
if (bookmarkExists) {
|
||||
deleteBookmarkItem(depictedItem);
|
||||
} else {
|
||||
addBookmarkItem(depictedItem);
|
||||
}
|
||||
return !bookmarkExists;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a Bookmark to database
|
||||
* @param depictedItem : Bookmark to add
|
||||
*/
|
||||
private void addBookmarkItem(final DepictedItem depictedItem) {
|
||||
final ContentProviderClient db = clientProvider.get();
|
||||
try {
|
||||
db.insert(BookmarkItemsContentProvider.BASE_URI, toContentValues(depictedItem));
|
||||
} catch (final RemoteException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
db.release();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a bookmark from database
|
||||
* @param depictedItem : Bookmark to delete
|
||||
*/
|
||||
private void deleteBookmarkItem(final DepictedItem depictedItem) {
|
||||
final ContentProviderClient db = clientProvider.get();
|
||||
try {
|
||||
db.delete(BookmarkItemsContentProvider.uriForName(depictedItem.getId()), null, null);
|
||||
} catch (final RemoteException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
db.release();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a bookmark from database based on its name
|
||||
* @param depictedItemID : Bookmark to find
|
||||
* @return boolean : is bookmark in database ?
|
||||
*/
|
||||
public boolean findBookmarkItem(final String depictedItemID) {
|
||||
if (depictedItemID == null) { //Avoiding NPE's
|
||||
return false;
|
||||
}
|
||||
final ContentProviderClient db = clientProvider.get();
|
||||
try (final Cursor cursor = db.query(
|
||||
BookmarkItemsContentProvider.BASE_URI,
|
||||
Table.ALL_FIELDS,
|
||||
Table.COLUMN_ID + "=?",
|
||||
new String[]{depictedItemID},
|
||||
null
|
||||
)) {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
return true;
|
||||
}
|
||||
} catch (final RemoteException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
db.release();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recives real data from cursor
|
||||
* @param cursor : Object for storing database data
|
||||
* @return DepictedItem
|
||||
*/
|
||||
DepictedItem fromCursor(final Cursor cursor) {
|
||||
final String fileName = cursor.getString(cursor.getColumnIndex(Table.COLUMN_NAME));
|
||||
final String description
|
||||
= cursor.getString(cursor.getColumnIndex(Table.COLUMN_DESCRIPTION));
|
||||
final String imageUrl = cursor.getString(cursor.getColumnIndex(Table.COLUMN_IMAGE));
|
||||
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 boolean isSelected
|
||||
= Boolean.parseBoolean(cursor.getString(cursor
|
||||
.getColumnIndex(Table.COLUMN_IS_SELECTED)));
|
||||
final String id = cursor.getString(cursor.getColumnIndex(Table.COLUMN_ID));
|
||||
|
||||
return new DepictedItem(
|
||||
fileName,
|
||||
description,
|
||||
imageUrl,
|
||||
instanceList,
|
||||
categoryList,
|
||||
isSelected,
|
||||
id
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts string to List
|
||||
* @param listString comma separated single string from of list items
|
||||
* @return List of string
|
||||
*/
|
||||
private List<String> StringToArray(final String listString) {
|
||||
final String[] elements = listString.split(",");
|
||||
return Arrays.asList(elements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts string to List
|
||||
* @param list list of items
|
||||
* @return string comma separated single string of items
|
||||
*/
|
||||
private String ArrayToString(final List<String> list) {
|
||||
if (list != null) {
|
||||
return StringUtils.join(list, ',');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes data from DepictedItem and create a content value object
|
||||
* @param depictedItem depicted item
|
||||
* @return ContentValues
|
||||
*/
|
||||
private ContentValues toContentValues(final DepictedItem depictedItem) {
|
||||
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_IS_SELECTED, depictedItem.isSelected());
|
||||
cv.put(Table.COLUMN_ID, depictedItem.getId());
|
||||
return cv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Table of bookmarksItems data
|
||||
*/
|
||||
public static final class Table {
|
||||
public static final String TABLE_NAME = "bookmarksItems";
|
||||
public static final String COLUMN_NAME = "item_name";
|
||||
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_IS_SELECTED = "item_is_selected";
|
||||
public static final String COLUMN_ID = "item_id";
|
||||
|
||||
public static final String[] ALL_FIELDS = {
|
||||
COLUMN_NAME,
|
||||
COLUMN_DESCRIPTION,
|
||||
COLUMN_IMAGE,
|
||||
COLUMN_INSTANCE_LIST,
|
||||
COLUMN_CATEGORIES_LIST,
|
||||
COLUMN_IS_SELECTED,
|
||||
COLUMN_ID
|
||||
};
|
||||
|
||||
static final String DROP_TABLE_STATEMENT = "DROP TABLE IF EXISTS " + TABLE_NAME;
|
||||
static final String CREATE_TABLE_STATEMENT = "CREATE TABLE " + TABLE_NAME + " ("
|
||||
+ COLUMN_NAME + " STRING,"
|
||||
+ COLUMN_DESCRIPTION + " STRING,"
|
||||
+ COLUMN_IMAGE + " STRING,"
|
||||
+ COLUMN_INSTANCE_LIST + " STRING,"
|
||||
+ COLUMN_CATEGORIES_LIST + " STRING,"
|
||||
+ COLUMN_IS_SELECTED + " STRING,"
|
||||
+ COLUMN_ID + " STRING PRIMARY KEY"
|
||||
+ ");";
|
||||
|
||||
/**
|
||||
* Creates table
|
||||
* @param db SQLiteDatabase
|
||||
*/
|
||||
public static void onCreate(final SQLiteDatabase db) {
|
||||
db.execSQL(CREATE_TABLE_STATEMENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes database
|
||||
* @param db SQLiteDatabase
|
||||
*/
|
||||
public static void onDelete(final SQLiteDatabase db) {
|
||||
db.execSQL(DROP_TABLE_STATEMENT);
|
||||
onCreate(db);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates database
|
||||
* @param db SQLiteDatabase
|
||||
* @param from starting
|
||||
* @param to end
|
||||
*/
|
||||
public static void onUpdate(final SQLiteDatabase db, int from, final int to) {
|
||||
if (from == to) {
|
||||
return;
|
||||
}
|
||||
if (from < 7) {
|
||||
from++;
|
||||
onUpdate(db, from, to);
|
||||
return;
|
||||
}
|
||||
|
||||
if (from == 7) {
|
||||
onCreate(db);
|
||||
from++;
|
||||
onUpdate(db, from, to);
|
||||
return;
|
||||
}
|
||||
|
||||
if (from == 8) {
|
||||
from++;
|
||||
onUpdate(db, from, to);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
package fr.free.nrw.commons.bookmarks.items;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import dagger.android.support.DaggerFragment;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.upload.structure.depictions.DepictedItem;
|
||||
import java.util.List;
|
||||
import javax.inject.Inject;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Tab fragment to show list of bookmarked Wikidata Items
|
||||
*/
|
||||
public class BookmarkItemsFragment extends DaggerFragment {
|
||||
|
||||
@BindView(R.id.status_message)
|
||||
TextView statusTextView;
|
||||
|
||||
@BindView(R.id.loading_images_progress_bar)
|
||||
ProgressBar progressBar;
|
||||
|
||||
@BindView(R.id.list_view)
|
||||
RecyclerView recyclerView;
|
||||
|
||||
@BindView(R.id.parent_layout)
|
||||
RelativeLayout parentLayout;
|
||||
|
||||
@Inject
|
||||
BookmarkItemsController controller;
|
||||
|
||||
public static BookmarkItemsFragment newInstance() {
|
||||
return new BookmarkItemsFragment();
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(
|
||||
@NonNull final LayoutInflater inflater,
|
||||
final ViewGroup container,
|
||||
final Bundle savedInstanceState
|
||||
) {
|
||||
final View v = inflater.inflate(R.layout.fragment_bookmarks_items, container, false);
|
||||
ButterKnife.bind(this, v);
|
||||
return v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(final @NotNull View view, @Nullable final Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
initList(requireContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
initList(requireContext());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get list of DepictedItem and sets to the adapter
|
||||
* @param context context
|
||||
*/
|
||||
private void initList(final Context context) {
|
||||
final List<DepictedItem> depictItems = controller.loadFavoritesItems();
|
||||
final BookmarkItemsAdapter adapter = new BookmarkItemsAdapter(depictItems, context);
|
||||
recyclerView.setAdapter(adapter);
|
||||
progressBar.setVisibility(View.GONE);
|
||||
if (depictItems.isEmpty()) {
|
||||
statusTextView.setText(R.string.bookmark_empty);
|
||||
statusTextView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
statusTextView.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,8 @@ import android.database.sqlite.SQLiteDatabase;
|
|||
import android.database.sqlite.SQLiteException;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
|
||||
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsDao;
|
||||
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsDao.Table;
|
||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao;
|
||||
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesDao;
|
||||
import fr.free.nrw.commons.category.CategoryDao;
|
||||
|
|
@ -30,6 +32,7 @@ public class DBOpenHelper extends SQLiteOpenHelper {
|
|||
CategoryDao.Table.onCreate(sqLiteDatabase);
|
||||
BookmarkPicturesDao.Table.onCreate(sqLiteDatabase);
|
||||
BookmarkLocationsDao.Table.onCreate(sqLiteDatabase);
|
||||
BookmarkItemsDao.Table.onCreate(sqLiteDatabase);
|
||||
RecentSearchesDao.Table.onCreate(sqLiteDatabase);
|
||||
}
|
||||
|
||||
|
|
@ -38,6 +41,7 @@ public class DBOpenHelper extends SQLiteOpenHelper {
|
|||
CategoryDao.Table.onUpdate(sqLiteDatabase, from, to);
|
||||
BookmarkPicturesDao.Table.onUpdate(sqLiteDatabase, from, to);
|
||||
BookmarkLocationsDao.Table.onUpdate(sqLiteDatabase, from, to);
|
||||
BookmarkItemsDao.Table.onUpdate(sqLiteDatabase, from, to);
|
||||
RecentSearchesDao.Table.onUpdate(sqLiteDatabase, from, to);
|
||||
deleteTable(sqLiteDatabase,CONTRIBUTIONS_TABLE);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
package fr.free.nrw.commons.di
|
||||
|
||||
import android.app.Activity
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsFragment
|
||||
|
||||
@Module
|
||||
class BookmarkItemsFragmentModule {
|
||||
@Provides
|
||||
fun BookmarkItemsFragment.providesActivity(): Activity = activity!!
|
||||
}
|
||||
|
|
@ -163,6 +163,12 @@ public class CommonsApplicationModule {
|
|||
return context.getContentResolver().acquireContentProviderClient(BuildConfig.BOOKMARK_LOCATIONS_AUTHORITY);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Named("bookmarksItem")
|
||||
public ContentProviderClient provideBookmarkItemContentProviderClient(Context context) {
|
||||
return context.getContentResolver().acquireContentProviderClient(BuildConfig.BOOKMARK_ITEMS_AUTHORITY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a Json store instance(JsonKvStore) which keeps
|
||||
* the provided Gson in it's instance
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package fr.free.nrw.commons.di;
|
|||
|
||||
import dagger.Module;
|
||||
import dagger.android.ContributesAndroidInjector;
|
||||
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsContentProvider;
|
||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsContentProvider;
|
||||
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesContentProvider;
|
||||
import fr.free.nrw.commons.category.CategoryContentProvider;
|
||||
|
|
@ -27,4 +28,7 @@ public abstract class ContentProviderBuilderModule {
|
|||
|
||||
@ContributesAndroidInjector
|
||||
abstract BookmarkLocationsContentProvider bindBookmarkLocationContentProvider();
|
||||
|
||||
@ContributesAndroidInjector
|
||||
abstract BookmarkItemsContentProvider bindBookmarkItemContentProvider();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import dagger.Module;
|
|||
import dagger.android.ContributesAndroidInjector;
|
||||
import fr.free.nrw.commons.bookmarks.BookmarkFragment;
|
||||
import fr.free.nrw.commons.bookmarks.BookmarkListRootFragment;
|
||||
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsFragment;
|
||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsFragment;
|
||||
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesFragment;
|
||||
import fr.free.nrw.commons.contributions.ContributionsFragment;
|
||||
|
|
@ -90,6 +91,9 @@ public abstract class FragmentBuilderModule {
|
|||
@ContributesAndroidInjector(modules = BookmarkLocationsFragmentModule.class)
|
||||
abstract BookmarkLocationsFragment bindBookmarkLocationListFragment();
|
||||
|
||||
@ContributesAndroidInjector(modules = BookmarkItemsFragmentModule.class)
|
||||
abstract BookmarkItemsFragment bindBookmarkItemListFragment();
|
||||
|
||||
@ContributesAndroidInjector
|
||||
abstract ReviewImageFragment bindReviewOutOfContextFragment();
|
||||
|
||||
|
|
|
|||
|
|
@ -15,20 +15,28 @@ import androidx.fragment.app.FragmentManager;
|
|||
import androidx.viewpager.widget.ViewPager;
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
import fr.free.nrw.commons.Media;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.Utils;
|
||||
import fr.free.nrw.commons.ViewPagerAdapter;
|
||||
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsDao;
|
||||
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;
|
||||
import fr.free.nrw.commons.media.MediaDetailPagerFragment;
|
||||
import fr.free.nrw.commons.theme.BaseActivity;
|
||||
import fr.free.nrw.commons.upload.structure.depictions.DepictModel;
|
||||
import fr.free.nrw.commons.upload.structure.depictions.DepictedItem;
|
||||
import fr.free.nrw.commons.wikidata.WikidataConstants;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* Activity to show depiction media, parent classes and child classes of depicted items in Explore
|
||||
|
|
@ -38,10 +46,16 @@ public class WikidataItemDetailsActivity extends BaseActivity implements MediaDe
|
|||
private FragmentManager supportFragmentManager;
|
||||
private DepictedImagesFragment depictionImagesListFragment;
|
||||
private MediaDetailPagerFragment mediaDetailPagerFragment;
|
||||
|
||||
/**
|
||||
* Name of the depicted item
|
||||
* Ex: Rabbit
|
||||
*/
|
||||
|
||||
@Inject BookmarkItemsDao bookmarkItemsDao;
|
||||
private CompositeDisposable compositeDisposable;
|
||||
@Inject
|
||||
DepictModel depictModel;
|
||||
private String wikidataItemName;
|
||||
@BindView(R.id.mediaContainer)
|
||||
FrameLayout mediaContainer;
|
||||
|
|
@ -53,17 +67,23 @@ public class WikidataItemDetailsActivity extends BaseActivity implements MediaDe
|
|||
Toolbar toolbar;
|
||||
|
||||
ViewPagerAdapter viewPagerAdapter;
|
||||
private DepictedItem wikidataItem;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_wikidata_item_details);
|
||||
ButterKnife.bind(this);
|
||||
compositeDisposable = new CompositeDisposable();
|
||||
supportFragmentManager = getSupportFragmentManager();
|
||||
viewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager());
|
||||
viewPager.setAdapter(viewPagerAdapter);
|
||||
viewPager.setOffscreenPageLimit(2);
|
||||
tabLayout.setupWithViewPager(viewPager);
|
||||
|
||||
final DepictedItem depictedItem = getIntent().getParcelableExtra(
|
||||
WikidataConstants.BOOKMARKS_ITEMS);
|
||||
wikidataItem = depictedItem;
|
||||
setSupportActionBar(toolbar);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
setTabs();
|
||||
|
|
@ -214,6 +234,7 @@ public class WikidataItemDetailsActivity extends BaseActivity implements MediaDe
|
|||
Intent intent = new Intent(context, WikidataItemDetailsActivity.class);
|
||||
intent.putExtra("wikidataItemName", depictedItem.getName());
|
||||
intent.putExtra("entityId", depictedItem.getId());
|
||||
intent.putExtra(WikidataConstants.BOOKMARKS_ITEMS, depictedItem);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
|
||||
|
|
@ -224,6 +245,9 @@ public class WikidataItemDetailsActivity extends BaseActivity implements MediaDe
|
|||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
MenuInflater menuInflater=getMenuInflater();
|
||||
menuInflater.inflate(R.menu.menu_wikidata_item,menu);
|
||||
|
||||
updateBookmarkState(menu.findItem(R.id.menu_bookmark_current_item));
|
||||
|
||||
return super.onCreateOptionsMenu(menu);
|
||||
}
|
||||
|
||||
|
|
@ -233,12 +257,47 @@ public class WikidataItemDetailsActivity extends BaseActivity implements MediaDe
|
|||
*/
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
|
||||
switch (item.getItemId()){
|
||||
case R.id.browser_actions_menu_items:
|
||||
String entityId=getIntent().getStringExtra("entityId");
|
||||
Uri uri = Uri.parse("https://www.wikidata.org/wiki/" + entityId);
|
||||
Utils.handleWebUrl(this, uri);
|
||||
return true;
|
||||
case R.id.menu_bookmark_current_item:
|
||||
|
||||
if(getIntent().getStringExtra("fragment") != null) {
|
||||
compositeDisposable.add(depictModel.getDepictions(
|
||||
getIntent().getStringExtra("entityId")
|
||||
).subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(depictedItems -> {
|
||||
final boolean bookmarkExists = bookmarkItemsDao.updateBookmarkItem(
|
||||
depictedItems.get(0));
|
||||
final Snackbar snackbar
|
||||
= bookmarkExists ? Snackbar.make(findViewById(R.id.toolbar_layout),
|
||||
R.string.add_bookmark, Snackbar.LENGTH_LONG)
|
||||
: Snackbar.make(findViewById(R.id.toolbar_layout),
|
||||
R.string.remove_bookmark,
|
||||
Snackbar.LENGTH_LONG);
|
||||
|
||||
snackbar.show();
|
||||
updateBookmarkState(item);
|
||||
}));
|
||||
|
||||
} else {
|
||||
final boolean bookmarkExists
|
||||
= bookmarkItemsDao.updateBookmarkItem(wikidataItem);
|
||||
final Snackbar snackbar
|
||||
= bookmarkExists ? Snackbar.make(findViewById(R.id.toolbar_layout),
|
||||
R.string.add_bookmark, Snackbar.LENGTH_LONG)
|
||||
: Snackbar.make(findViewById(R.id.toolbar_layout), R.string.remove_bookmark,
|
||||
Snackbar.LENGTH_LONG);
|
||||
|
||||
snackbar.show();
|
||||
updateBookmarkState(item);
|
||||
}
|
||||
return true;
|
||||
case android.R.id.home:
|
||||
onBackPressed();
|
||||
return true;
|
||||
|
|
@ -246,4 +305,18 @@ public class WikidataItemDetailsActivity extends BaseActivity implements MediaDe
|
|||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateBookmarkState(final MenuItem item) {
|
||||
final boolean isBookmarked;
|
||||
if(getIntent().getStringExtra("fragment") != null) {
|
||||
isBookmarked
|
||||
= bookmarkItemsDao.findBookmarkItem(getIntent().getStringExtra("entityId"));
|
||||
} else {
|
||||
isBookmarked = bookmarkItemsDao.findBookmarkItem(wikidataItem.getId());
|
||||
}
|
||||
final int icon
|
||||
= isBookmarked ? R.drawable.menu_ic_round_star_filled_24px
|
||||
: R.drawable.menu_ic_round_star_border_24px;
|
||||
item.setIcon(icon);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1272,6 +1272,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment implements
|
|||
Intent intent = new Intent(getContext(), WikidataItemDetailsActivity.class);
|
||||
intent.putExtra("wikidataItemName", depictionName);
|
||||
intent.putExtra("entityId", entityId);
|
||||
intent.putExtra("fragment", "MediaDetailFragment");
|
||||
getContext().startActivity(intent);
|
||||
});
|
||||
return item;
|
||||
|
|
|
|||
|
|
@ -51,6 +51,18 @@ class DepictModel @Inject constructor(private val depictsClient: DepictsClient)
|
|||
else Single.just(emptyList())
|
||||
}
|
||||
|
||||
fun getDepictions(ids: String): Single<List<DepictedItem>> =
|
||||
if (ids.isNotEmpty())
|
||||
depictsClient.getEntities(ids)
|
||||
.map{
|
||||
it.entities()
|
||||
.values
|
||||
.mapIndexed { _, entity -> DepictedItem(entity)}
|
||||
}
|
||||
.onErrorResumeWithEmptyList()
|
||||
else Single.just(emptyList())
|
||||
|
||||
|
||||
private fun networkItems(query: String): Flowable<List<DepictedItem>> {
|
||||
return depictsClient.searchForDepictions(query, SEARCH_DEPICTS_LIMIT, 0)
|
||||
.onErrorResumeWithEmptyList()
|
||||
|
|
|
|||
|
|
@ -2,4 +2,5 @@ package fr.free.nrw.commons.wikidata;
|
|||
|
||||
public class WikidataConstants {
|
||||
public static final String PLACE_OBJECT = "place";
|
||||
public static final String BOOKMARKS_ITEMS = "bookmarks.items";
|
||||
}
|
||||
|
|
|
|||
33
app/src/main/res/layout/fragment_bookmarks_items.xml
Normal file
33
app/src/main/res/layout/fragment_bookmarks_items.xml
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/parent_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".bookmarks.items.BookmarkItemsFragment">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/status_message"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_gravity="center"
|
||||
android:text="@string/waiting_first_sync"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/loading_images_progress_bar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:visibility="gone" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/list_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
/>
|
||||
|
||||
</RelativeLayout>
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/layout_item"
|
||||
android:padding="@dimen/tiny_gap">
|
||||
|
||||
<TextView
|
||||
|
|
|
|||
|
|
@ -1,6 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:id="@+id/menu_bookmark_current_item"
|
||||
android:icon="@drawable/menu_ic_round_star_border_24px"
|
||||
android:title="@string/menu_bookmark"
|
||||
app:showAsAction="always" />
|
||||
|
||||
<item
|
||||
android:id="@+id/browser_actions_menu_items"
|
||||
android:title="@string/menu_view_item_page" />
|
||||
</menu>
|
||||
|
|
@ -652,6 +652,7 @@ 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="title_page_bookmarks_items">Items</string>
|
||||
<string name="custom_selector_title">Custom Selector</string>
|
||||
<string name="custom_selector_empty_text">No Images</string>
|
||||
<string name="done">Done</string>
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ class BookmarksPagerAdapterTests {
|
|||
|
||||
@Test
|
||||
fun testGetCount() {
|
||||
Assert.assertEquals(bookmarksPagerAdapter.count, 2)
|
||||
Assert.assertEquals(bookmarksPagerAdapter.count, 3)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
package fr.free.nrw.commons.bookmarks.items
|
||||
|
||||
import com.nhaarman.mockitokotlin2.whenever
|
||||
import fr.free.nrw.commons.upload.structure.depictions.DepictedItem
|
||||
import org.junit.Assert
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.mockito.InjectMocks
|
||||
import org.mockito.Mock
|
||||
import org.mockito.MockitoAnnotations
|
||||
import java.util.ArrayList
|
||||
|
||||
class BookmarkItemsControllerTest {
|
||||
@Mock
|
||||
var bookmarkDao: BookmarkItemsDao? = null
|
||||
@InjectMocks
|
||||
lateinit var bookmarkItemsController: BookmarkItemsController
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
whenever(bookmarkDao!!.allBookmarksItems)
|
||||
.thenReturn(mockBookmarkList)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get mock bookmark list
|
||||
* @return list of DepictedItem
|
||||
*/
|
||||
private val mockBookmarkList: List<DepictedItem>
|
||||
get() {
|
||||
val list = ArrayList<DepictedItem>()
|
||||
list.add(
|
||||
DepictedItem(
|
||||
"name", "description", "image url", listOf("instance"),
|
||||
listOf("categories"), true, "id")
|
||||
)
|
||||
return list
|
||||
}
|
||||
|
||||
/**
|
||||
* Test case where all bookmark items are fetched and media is found against it
|
||||
*/
|
||||
@Test
|
||||
fun loadBookmarkedItems() {
|
||||
val bookmarkedItems =
|
||||
bookmarkItemsController.loadFavoritesItems()
|
||||
Assert.assertEquals(1, bookmarkedItems.size.toLong())
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,270 @@
|
|||
package fr.free.nrw.commons.bookmarks.items
|
||||
|
||||
import android.content.ContentProviderClient
|
||||
import android.content.ContentValues
|
||||
import android.database.Cursor
|
||||
import android.database.MatrixCursor
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import android.net.Uri
|
||||
import android.os.RemoteException
|
||||
import com.nhaarman.mockitokotlin2.*
|
||||
import fr.free.nrw.commons.TestCommonsApplication
|
||||
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsDao.Table.*
|
||||
import fr.free.nrw.commons.upload.structure.depictions.DepictedItem
|
||||
import org.junit.Assert
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(sdk = [21], application = TestCommonsApplication::class)
|
||||
class BookmarkItemsDaoTest {
|
||||
private val columns = arrayOf(
|
||||
COLUMN_NAME,
|
||||
COLUMN_DESCRIPTION,
|
||||
COLUMN_IMAGE,
|
||||
COLUMN_INSTANCE_LIST,
|
||||
COLUMN_CATEGORIES_LIST,
|
||||
COLUMN_IS_SELECTED,
|
||||
COLUMN_ID,
|
||||
)
|
||||
private val client: ContentProviderClient = mock()
|
||||
private val database: SQLiteDatabase = mock()
|
||||
private val captor = argumentCaptor<ContentValues>()
|
||||
|
||||
private lateinit var testObject: BookmarkItemsDao
|
||||
private lateinit var exampleItemBookmark: DepictedItem
|
||||
|
||||
/**
|
||||
* Set up Test DepictedItem and BookmarkItemsDao
|
||||
*/
|
||||
@Before
|
||||
fun setUp() {
|
||||
exampleItemBookmark = DepictedItem("itemName", "itemDescription",
|
||||
"itemImageUrl", listOf("instance"), listOf("categories"), false,
|
||||
"itemID")
|
||||
testObject = BookmarkItemsDao { client }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun createTable() {
|
||||
onCreate(database)
|
||||
verify(database).execSQL(CREATE_TABLE_STATEMENT)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun deleteTable() {
|
||||
onDelete(database)
|
||||
inOrder(database) {
|
||||
verify(database).execSQL(DROP_TABLE_STATEMENT)
|
||||
verify(database).execSQL(CREATE_TABLE_STATEMENT)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun createFromCursor() {
|
||||
createCursor(1).let { cursor ->
|
||||
cursor.moveToFirst()
|
||||
testObject.fromCursor(cursor).let {
|
||||
Assert.assertEquals("itemName", it.name)
|
||||
Assert.assertEquals("itemDescription", it.description)
|
||||
Assert.assertEquals("itemImageUrl", it.imageUrl)
|
||||
Assert.assertEquals(listOf("instance"), it.instanceOfs)
|
||||
Assert.assertEquals(listOf("categories"), it.commonsCategories)
|
||||
Assert.assertEquals(false, it.isSelected)
|
||||
Assert.assertEquals("itemID", it.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getAllItemsBookmarks() {
|
||||
whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull()))
|
||||
.thenReturn(createCursor(14))
|
||||
|
||||
val result = testObject.allBookmarksItems
|
||||
|
||||
Assert.assertEquals(14, (result.size))
|
||||
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException::class)
|
||||
fun getAllItemsBookmarksTranslatesExceptions() {
|
||||
whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull())).thenThrow(
|
||||
RemoteException("")
|
||||
)
|
||||
testObject.allBookmarksItems
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getAllItemsBookmarksReturnsEmptyList_emptyCursor() {
|
||||
whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull()))
|
||||
.thenReturn(createCursor(0))
|
||||
Assert.assertTrue(testObject.allBookmarksItems.isEmpty())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getAllItemsBookmarksReturnsEmptyList_nullCursor() {
|
||||
whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull())).thenReturn(null)
|
||||
Assert.assertTrue(testObject.allBookmarksItems.isEmpty())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun cursorsAreClosedAfterGetAllItemsBookmarksQuery() {
|
||||
val mockCursor: Cursor = mock()
|
||||
whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull())).thenReturn(mockCursor)
|
||||
whenever(mockCursor.moveToFirst()).thenReturn(false)
|
||||
|
||||
testObject.allBookmarksItems
|
||||
|
||||
verify(mockCursor).close()
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun updateNewItemBookmark() {
|
||||
whenever(client.insert(any(), any())).thenReturn(Uri.EMPTY)
|
||||
whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(null)
|
||||
|
||||
Assert.assertTrue(testObject.updateBookmarkItem(exampleItemBookmark))
|
||||
verify(client).insert(eq(BookmarkItemsContentProvider.BASE_URI), captor.capture())
|
||||
captor.firstValue.let { cv ->
|
||||
Assert.assertEquals(7, cv.size())
|
||||
Assert.assertEquals(
|
||||
exampleItemBookmark.name,
|
||||
cv.getAsString(COLUMN_NAME)
|
||||
)
|
||||
Assert.assertEquals(
|
||||
exampleItemBookmark.description,
|
||||
cv.getAsString(COLUMN_DESCRIPTION)
|
||||
)
|
||||
Assert.assertEquals(
|
||||
exampleItemBookmark.imageUrl,
|
||||
cv.getAsString(COLUMN_IMAGE)
|
||||
)
|
||||
Assert.assertEquals(
|
||||
exampleItemBookmark.instanceOfs[0],
|
||||
cv.getAsString(COLUMN_INSTANCE_LIST)
|
||||
)
|
||||
Assert.assertEquals(
|
||||
exampleItemBookmark.commonsCategories[0],
|
||||
cv.getAsString(COLUMN_CATEGORIES_LIST)
|
||||
)
|
||||
Assert.assertEquals(
|
||||
exampleItemBookmark.isSelected,
|
||||
cv.getAsBoolean(COLUMN_IS_SELECTED)
|
||||
)
|
||||
Assert.assertEquals(
|
||||
exampleItemBookmark.id,
|
||||
cv.getAsString(COLUMN_ID)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun updateExistingItemBookmark() {
|
||||
whenever(client.delete(isA(), isNull(), isNull())).thenReturn(1)
|
||||
whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(createCursor(1))
|
||||
|
||||
Assert.assertFalse(testObject.updateBookmarkItem(exampleItemBookmark))
|
||||
verify(client).delete(eq(BookmarkItemsContentProvider.uriForName(exampleItemBookmark.id)),
|
||||
isNull(), isNull())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun findExistingItemBookmark() {
|
||||
whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(createCursor(1))
|
||||
Assert.assertTrue(testObject.findBookmarkItem(exampleItemBookmark.id))
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException::class)
|
||||
fun findItemBookmarkTranslatesExceptions() {
|
||||
whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull())).thenThrow(
|
||||
RemoteException("")
|
||||
)
|
||||
testObject.findBookmarkItem(exampleItemBookmark.id)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun findNotExistingItemBookmarkReturnsNull_emptyCursor() {
|
||||
whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(createCursor(0))
|
||||
Assert.assertFalse(testObject.findBookmarkItem(exampleItemBookmark.id))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun findNotExistingItemBookmarkReturnsNull_nullCursor() {
|
||||
whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(null)
|
||||
Assert.assertFalse(testObject.findBookmarkItem(exampleItemBookmark.id))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun cursorsAreClosedAfterFindItemBookmarkQuery() {
|
||||
val mockCursor: Cursor = mock()
|
||||
whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(mockCursor)
|
||||
whenever(mockCursor.moveToFirst()).thenReturn(false)
|
||||
|
||||
testObject.findBookmarkItem(exampleItemBookmark.id)
|
||||
|
||||
verify(mockCursor).close()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrateTableVersionFrom_v1_to_v2() {
|
||||
onUpdate(database, 1, 2)
|
||||
// Table didn't exist before v5
|
||||
verifyZeroInteractions(database)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrateTableVersionFrom_v2_to_v3() {
|
||||
onUpdate(database, 2, 3)
|
||||
// Table didn't exist before v5
|
||||
verifyZeroInteractions(database)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrateTableVersionFrom_v3_to_v4() {
|
||||
onUpdate(database, 3, 4)
|
||||
// Table didn't exist before v5
|
||||
verifyZeroInteractions(database)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrateTableVersionFrom_v4_to_v5() {
|
||||
onUpdate(database, 4, 5)
|
||||
// Table didn't change in version 5
|
||||
verifyZeroInteractions(database)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrateTableVersionFrom_v5_to_v6() {
|
||||
onUpdate(database, 5, 6)
|
||||
// Table didn't change in version 6
|
||||
verifyZeroInteractions(database)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrateTableVersionFrom_v6_to_v7() {
|
||||
onUpdate(database, 6, 7)
|
||||
// Table didn't change in version 7
|
||||
verifyZeroInteractions(database)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrateTableVersionFrom_v7_to_v8() {
|
||||
onUpdate(database, 7, 8)
|
||||
verify(database).execSQL(CREATE_TABLE_STATEMENT)
|
||||
}
|
||||
|
||||
|
||||
private fun createCursor(rowCount: Int) = MatrixCursor(columns, rowCount).apply {
|
||||
|
||||
for (i in 0 until rowCount) {
|
||||
addRow(listOf("itemName", "itemDescription",
|
||||
"itemImageUrl", "instance", "categories", false,
|
||||
"itemID"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
package fr.free.nrw.commons.bookmarks.items
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.ProgressBar
|
||||
import android.widget.RelativeLayout
|
||||
import android.widget.TextView
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.fragment.app.FragmentTransaction
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.nhaarman.mockitokotlin2.whenever
|
||||
import fr.free.nrw.commons.R
|
||||
import fr.free.nrw.commons.TestAppAdapter
|
||||
import fr.free.nrw.commons.TestCommonsApplication
|
||||
import fr.free.nrw.commons.profile.ProfileActivity
|
||||
import fr.free.nrw.commons.upload.structure.depictions.DepictedItem
|
||||
import org.junit.Assert
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mock
|
||||
import org.mockito.MockitoAnnotations
|
||||
import org.robolectric.Robolectric
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.RuntimeEnvironment
|
||||
import org.robolectric.annotation.Config
|
||||
import org.robolectric.annotation.LooperMode
|
||||
import org.wikipedia.AppAdapter
|
||||
import java.lang.reflect.Method
|
||||
import java.util.*
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(sdk = [21], application = TestCommonsApplication::class)
|
||||
@LooperMode(LooperMode.Mode.PAUSED)
|
||||
class BookmarkItemsFragmentUnitTest {
|
||||
|
||||
private lateinit var fragment: BookmarkItemsFragment
|
||||
private lateinit var context: Context
|
||||
private lateinit var view: View
|
||||
private lateinit var statusTextView: TextView
|
||||
private lateinit var progressBar: ProgressBar
|
||||
private lateinit var recyclerView: RecyclerView
|
||||
private lateinit var layoutInflater: LayoutInflater
|
||||
|
||||
@Mock
|
||||
private lateinit var parentLayout: RelativeLayout
|
||||
|
||||
@Mock
|
||||
private lateinit var savedInstanceState: Bundle
|
||||
|
||||
@Mock
|
||||
private lateinit var controller: BookmarkItemsController
|
||||
|
||||
/**
|
||||
* Get Mock bookmark list.
|
||||
*/
|
||||
private val mockBookmarkList: List<DepictedItem>
|
||||
get() {
|
||||
val list = ArrayList<DepictedItem>()
|
||||
list.add(
|
||||
DepictedItem(
|
||||
"name", "description", "image url", listOf("instance"),
|
||||
listOf("categories"), true, "id")
|
||||
)
|
||||
return list
|
||||
}
|
||||
|
||||
/**
|
||||
* fragment Setup
|
||||
*/
|
||||
@Before
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
context = RuntimeEnvironment.application.applicationContext
|
||||
AppAdapter.set(TestAppAdapter())
|
||||
val activity = Robolectric.buildActivity(ProfileActivity::class.java).create().get()
|
||||
fragment = BookmarkItemsFragment.newInstance()
|
||||
val fragmentManager: FragmentManager = activity.supportFragmentManager
|
||||
val fragmentTransaction: FragmentTransaction = fragmentManager.beginTransaction()
|
||||
fragmentTransaction.add(fragment, null)
|
||||
fragmentTransaction.commit()
|
||||
|
||||
layoutInflater = LayoutInflater.from(activity)
|
||||
view = layoutInflater
|
||||
.inflate(R.layout.fragment_bookmarks_items, null) as View
|
||||
|
||||
statusTextView = view.findViewById(R.id.status_message)
|
||||
progressBar = view.findViewById(R.id.loading_images_progress_bar)
|
||||
recyclerView = view.findViewById(R.id.list_view)
|
||||
|
||||
fragment.statusTextView = statusTextView
|
||||
fragment.progressBar = progressBar
|
||||
fragment.recyclerView = recyclerView
|
||||
fragment.parentLayout = parentLayout
|
||||
fragment.controller = controller
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* test init items when non empty
|
||||
*/
|
||||
@Test
|
||||
fun testInitNonEmpty(){
|
||||
whenever(controller.loadFavoritesItems()).thenReturn(mockBookmarkList)
|
||||
val method: Method =
|
||||
BookmarkItemsFragment::class.java.getDeclaredMethod("initList", Context::class.java)
|
||||
method.isAccessible = true
|
||||
method.invoke(fragment, context)
|
||||
}
|
||||
|
||||
/**
|
||||
* test onCreateView
|
||||
*/
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun testOnCreateView() {
|
||||
|
||||
fragment.onCreateView(layoutInflater,null,savedInstanceState)
|
||||
}
|
||||
|
||||
/**
|
||||
* check fragment notnull
|
||||
*/
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun checkFragmentNotNull() {
|
||||
Assert.assertNotNull(fragment)
|
||||
}
|
||||
}
|
||||
|
|
@ -50,6 +50,9 @@ class WikidataItemDetailsActivityUnitTests {
|
|||
@Mock
|
||||
private lateinit var depictedItem: DepictedItem
|
||||
|
||||
@Mock
|
||||
private lateinit var wikidataItem: DepictedItem
|
||||
|
||||
@Mock
|
||||
private lateinit var mediaContainer: FrameLayout
|
||||
|
||||
|
|
@ -92,6 +95,9 @@ class WikidataItemDetailsActivityUnitTests {
|
|||
viewPager = parent.findViewById(R.id.viewPager)
|
||||
Whitebox.setInternalState(activity, "viewPager", viewPager)
|
||||
|
||||
Whitebox.setInternalState(activity, "wikidataItem", wikidataItem)
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue