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:
Ayan Sarkar 2021-12-28 16:45:09 +05:30 committed by GitHub
parent 3c29f45f15
commit 38ed364423
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 1222 additions and 4 deletions

View file

@ -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") + "\""

View file

@ -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>

View file

@ -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);
}

View file

@ -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);

View file

@ -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();
}

View file

@ -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
}
}

View file

@ -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;
}
}

View file

@ -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();
}
}

View file

@ -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);
}
}
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}

View file

@ -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!!
}

View file

@ -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

View file

@ -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();
}

View file

@ -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();

View file

@ -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);
}
}

View file

@ -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;

View file

@ -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()

View file

@ -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";
}

View 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>

View file

@ -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

View file

@ -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>

View file

@ -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>

View file

@ -37,7 +37,7 @@ class BookmarksPagerAdapterTests {
@Test
fun testGetCount() {
Assert.assertEquals(bookmarksPagerAdapter.count, 2)
Assert.assertEquals(bookmarksPagerAdapter.count, 3)
}
@Test

View file

@ -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())
}
}

View file

@ -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"))
}
}
}

View file

@ -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)
}
}

View file

@ -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