mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 20:33:53 +01:00
Merge branch 'main' into fix-empty-username
This commit is contained in:
commit
b2407e7c4b
29 changed files with 708 additions and 950 deletions
|
|
@ -232,12 +232,6 @@
|
|||
android:exported="false"
|
||||
android:label="@string/provider_bookmarks"
|
||||
android:syncable="false" />
|
||||
<provider
|
||||
android:name=".bookmarks.locations.BookmarkLocationsContentProvider"
|
||||
android:authorities="${applicationId}.bookmarks.locations.contentprovider"
|
||||
android:exported="false"
|
||||
android:label="@string/provider_bookmarks_location"
|
||||
android:syncable="false" />
|
||||
<provider
|
||||
android:name=".bookmarks.items.BookmarkItemsContentProvider"
|
||||
android:authorities="${applicationId}.bookmarks.items.contentprovider"
|
||||
|
|
|
|||
|
|
@ -247,13 +247,17 @@ class CommonsApplication : MultiDexApplication() {
|
|||
DBOpenHelper.CONTRIBUTIONS_TABLE
|
||||
) //Delete the contributions table in the existing db on older versions
|
||||
|
||||
dbOpenHelper.deleteTable(
|
||||
db,
|
||||
DBOpenHelper.BOOKMARKS_LOCATIONS
|
||||
)
|
||||
|
||||
try {
|
||||
contributionDao.deleteAll()
|
||||
} catch (e: SQLiteException) {
|
||||
Timber.e(e)
|
||||
}
|
||||
BookmarkPicturesDao.Table.onDelete(db)
|
||||
BookmarkLocationsDao.Table.onDelete(db)
|
||||
BookmarkItemsDao.Table.onDelete(db)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,119 +0,0 @@
|
|||
package fr.free.nrw.commons.bookmarks.locations;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteQueryBuilder;
|
||||
// We can get uri using java.Net.Uri, but andoid implimentation is faster (but it's forgiving with handling exceptions though)
|
||||
import android.net.Uri;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import fr.free.nrw.commons.BuildConfig;
|
||||
import fr.free.nrw.commons.data.DBOpenHelper;
|
||||
import fr.free.nrw.commons.di.CommonsDaggerContentProvider;
|
||||
import timber.log.Timber;
|
||||
|
||||
import static fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_NAME;
|
||||
import static fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.TABLE_NAME;
|
||||
|
||||
/**
|
||||
* Handles private storage for Bookmark locations
|
||||
*/
|
||||
public class BookmarkLocationsContentProvider extends CommonsDaggerContentProvider {
|
||||
|
||||
private static final String BASE_PATH = "bookmarksLocations";
|
||||
public static final Uri BASE_URI = Uri.parse("content://" + BuildConfig.BOOKMARK_LOCATIONS_AUTHORITY + "/" + BASE_PATH);
|
||||
|
||||
/**
|
||||
* Append bookmark locations name to the base uri
|
||||
*/
|
||||
public static Uri uriForName(String name) {
|
||||
return Uri.parse(BASE_URI.toString() + "/" + name);
|
||||
}
|
||||
|
||||
@Inject DBOpenHelper dbOpenHelper;
|
||||
|
||||
@Override
|
||||
public String getType(@NonNull Uri uri) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries the SQLite database for the bookmark locations
|
||||
* @param uri : contains the uri for bookmark locations
|
||||
* @param projection
|
||||
* @param selection : handles Where
|
||||
* @param selectionArgs : the condition of Where clause
|
||||
* @param sortOrder : ascending or descending
|
||||
*/
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@Override
|
||||
public Cursor query(@NonNull Uri uri, String[] projection, String selection,
|
||||
String[] selectionArgs, String sortOrder) {
|
||||
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
|
||||
queryBuilder.setTables(TABLE_NAME);
|
||||
|
||||
SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
|
||||
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 locations
|
||||
* @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 Uri uri, ContentValues contentValues, String selection,
|
||||
String[] selectionArgs) {
|
||||
SQLiteDatabase sqlDB = dbOpenHelper.getWritableDatabase();
|
||||
int rowsUpdated;
|
||||
if (TextUtils.isEmpty(selection)) {
|
||||
int id = Integer.valueOf(uri.getLastPathSegment());
|
||||
rowsUpdated = sqlDB.update(TABLE_NAME,
|
||||
contentValues,
|
||||
COLUMN_NAME + " = ?",
|
||||
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 locations record to local SQLite Database
|
||||
*/
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@Override
|
||||
public Uri insert(@NonNull Uri uri, ContentValues contentValues) {
|
||||
SQLiteDatabase sqlDB = dbOpenHelper.getWritableDatabase();
|
||||
long id = sqlDB.insert(BookmarkLocationsDao.Table.TABLE_NAME, null, contentValues);
|
||||
getContext().getContentResolver().notifyChange(uri, null);
|
||||
return Uri.parse(BASE_URI + "/" + id);
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@Override
|
||||
public int delete(@NonNull Uri uri, String s, String[] strings) {
|
||||
int rows;
|
||||
SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
|
||||
Timber.d("Deleting bookmark name %s", uri.getLastPathSegment());
|
||||
rows = db.delete(TABLE_NAME,
|
||||
"location_name = ?",
|
||||
new String[]{uri.getLastPathSegment()}
|
||||
);
|
||||
getContext().getContentResolver().notifyChange(uri, null);
|
||||
return rows;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
package fr.free.nrw.commons.bookmarks.locations;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import fr.free.nrw.commons.nearby.Place;
|
||||
|
||||
@Singleton
|
||||
public class BookmarkLocationsController {
|
||||
|
||||
@Inject
|
||||
BookmarkLocationsDao bookmarkLocationDao;
|
||||
|
||||
@Inject
|
||||
public BookmarkLocationsController() {}
|
||||
|
||||
/**
|
||||
* Load from DB the bookmarked locations
|
||||
* @return a list of Place objects.
|
||||
*/
|
||||
public List<Place> loadFavoritesLocations() {
|
||||
return bookmarkLocationDao.getAllBookmarksLocations();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package fr.free.nrw.commons.bookmarks.locations
|
||||
|
||||
import fr.free.nrw.commons.nearby.Place
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class BookmarkLocationsController @Inject constructor(
|
||||
private val bookmarkLocationDao: BookmarkLocationsDao
|
||||
) {
|
||||
|
||||
/**
|
||||
* Load bookmarked locations from the database.
|
||||
* @return a list of Place objects.
|
||||
*/
|
||||
suspend fun loadFavoritesLocations(): List<Place> =
|
||||
bookmarkLocationDao.getAllBookmarksLocationsPlace()
|
||||
}
|
||||
|
|
@ -1,313 +0,0 @@
|
|||
package fr.free.nrw.commons.bookmarks.locations;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.ContentProviderClient;
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteException;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import fr.free.nrw.commons.nearby.NearbyController;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Provider;
|
||||
|
||||
import fr.free.nrw.commons.location.LatLng;
|
||||
import fr.free.nrw.commons.nearby.Label;
|
||||
import fr.free.nrw.commons.nearby.Place;
|
||||
import fr.free.nrw.commons.nearby.Sitelinks;
|
||||
import timber.log.Timber;
|
||||
|
||||
import static fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsContentProvider.BASE_URI;
|
||||
|
||||
public class BookmarkLocationsDao {
|
||||
|
||||
private final Provider<ContentProviderClient> clientProvider;
|
||||
|
||||
@Inject
|
||||
public BookmarkLocationsDao(@Named("bookmarksLocation") Provider<ContentProviderClient> clientProvider) {
|
||||
this.clientProvider = clientProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all persisted locations bookmarks on database
|
||||
*
|
||||
* @return list of Place
|
||||
*/
|
||||
@NonNull
|
||||
public List<Place> getAllBookmarksLocations() {
|
||||
List<Place> items = new ArrayList<>();
|
||||
Cursor cursor = null;
|
||||
ContentProviderClient db = clientProvider.get();
|
||||
try {
|
||||
cursor = db.query(
|
||||
BookmarkLocationsContentProvider.BASE_URI,
|
||||
Table.ALL_FIELDS,
|
||||
null,
|
||||
new String[]{},
|
||||
null);
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
items.add(fromCursor(cursor));
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
db.release();
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for a place in bookmarks table in order to insert or delete it
|
||||
*
|
||||
* @param bookmarkLocation : Place object
|
||||
* @return is Place now fav ?
|
||||
*/
|
||||
public boolean updateBookmarkLocation(Place bookmarkLocation) {
|
||||
boolean bookmarkExists = findBookmarkLocation(bookmarkLocation);
|
||||
if (bookmarkExists) {
|
||||
deleteBookmarkLocation(bookmarkLocation);
|
||||
NearbyController.updateMarkerLabelListBookmark(bookmarkLocation, false);
|
||||
} else {
|
||||
addBookmarkLocation(bookmarkLocation);
|
||||
NearbyController.updateMarkerLabelListBookmark(bookmarkLocation, true);
|
||||
}
|
||||
return !bookmarkExists;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a Place to bookmarks table
|
||||
*
|
||||
* @param bookmarkLocation : Place to add
|
||||
*/
|
||||
private void addBookmarkLocation(Place bookmarkLocation) {
|
||||
ContentProviderClient db = clientProvider.get();
|
||||
try {
|
||||
db.insert(BASE_URI, toContentValues(bookmarkLocation));
|
||||
} catch (RemoteException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
db.release();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a Place from bookmarks table
|
||||
*
|
||||
* @param bookmarkLocation : Place to delete
|
||||
*/
|
||||
private void deleteBookmarkLocation(Place bookmarkLocation) {
|
||||
ContentProviderClient db = clientProvider.get();
|
||||
try {
|
||||
db.delete(BookmarkLocationsContentProvider.uriForName(bookmarkLocation.name), null, null);
|
||||
} catch (RemoteException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
db.release();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a Place from database based on its name
|
||||
*
|
||||
* @param bookmarkLocation : Place to find
|
||||
* @return boolean : is Place in database ?
|
||||
*/
|
||||
public boolean findBookmarkLocation(Place bookmarkLocation) {
|
||||
Cursor cursor = null;
|
||||
ContentProviderClient db = clientProvider.get();
|
||||
try {
|
||||
cursor = db.query(
|
||||
BookmarkLocationsContentProvider.BASE_URI,
|
||||
Table.ALL_FIELDS,
|
||||
Table.COLUMN_NAME + "=?",
|
||||
new String[]{bookmarkLocation.name},
|
||||
null);
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
return true;
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
// This feels lazy, but to hell with checked exceptions. :)
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
db.release();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressLint("Range")
|
||||
@NonNull
|
||||
Place fromCursor(final Cursor cursor) {
|
||||
final LatLng location = new LatLng(cursor.getDouble(cursor.getColumnIndex(Table.COLUMN_LAT)),
|
||||
cursor.getDouble(cursor.getColumnIndex(Table.COLUMN_LONG)), 1F);
|
||||
|
||||
final Sitelinks.Builder builder = new Sitelinks.Builder();
|
||||
builder.setWikipediaLink(cursor.getString(cursor.getColumnIndex(Table.COLUMN_WIKIPEDIA_LINK)));
|
||||
builder.setWikidataLink(cursor.getString(cursor.getColumnIndex(Table.COLUMN_WIKIDATA_LINK)));
|
||||
builder.setCommonsLink(cursor.getString(cursor.getColumnIndex(Table.COLUMN_COMMONS_LINK)));
|
||||
|
||||
return new Place(
|
||||
cursor.getString(cursor.getColumnIndex(Table.COLUMN_LANGUAGE)),
|
||||
cursor.getString(cursor.getColumnIndex(Table.COLUMN_NAME)),
|
||||
Label.fromText((cursor.getString(cursor.getColumnIndex(Table.COLUMN_LABEL_TEXT)))),
|
||||
cursor.getString(cursor.getColumnIndex(Table.COLUMN_DESCRIPTION)),
|
||||
location,
|
||||
cursor.getString(cursor.getColumnIndex(Table.COLUMN_CATEGORY)),
|
||||
builder.build(),
|
||||
cursor.getString(cursor.getColumnIndex(Table.COLUMN_PIC)),
|
||||
Boolean.parseBoolean(cursor.getString(cursor.getColumnIndex(Table.COLUMN_EXISTS)))
|
||||
);
|
||||
}
|
||||
|
||||
private ContentValues toContentValues(Place bookmarkLocation) {
|
||||
ContentValues cv = new ContentValues();
|
||||
cv.put(BookmarkLocationsDao.Table.COLUMN_NAME, bookmarkLocation.getName());
|
||||
cv.put(BookmarkLocationsDao.Table.COLUMN_LANGUAGE, bookmarkLocation.getLanguage());
|
||||
cv.put(BookmarkLocationsDao.Table.COLUMN_DESCRIPTION, bookmarkLocation.getLongDescription());
|
||||
cv.put(BookmarkLocationsDao.Table.COLUMN_CATEGORY, bookmarkLocation.getCategory());
|
||||
cv.put(BookmarkLocationsDao.Table.COLUMN_LABEL_TEXT, bookmarkLocation.getLabel()!=null ? bookmarkLocation.getLabel().getText() : "");
|
||||
cv.put(BookmarkLocationsDao.Table.COLUMN_LABEL_ICON, bookmarkLocation.getLabel()!=null ? bookmarkLocation.getLabel().getIcon() : null);
|
||||
cv.put(BookmarkLocationsDao.Table.COLUMN_WIKIPEDIA_LINK, bookmarkLocation.siteLinks.getWikipediaLink().toString());
|
||||
cv.put(BookmarkLocationsDao.Table.COLUMN_WIKIDATA_LINK, bookmarkLocation.siteLinks.getWikidataLink().toString());
|
||||
cv.put(BookmarkLocationsDao.Table.COLUMN_COMMONS_LINK, bookmarkLocation.siteLinks.getCommonsLink().toString());
|
||||
cv.put(BookmarkLocationsDao.Table.COLUMN_LAT, bookmarkLocation.location.getLatitude());
|
||||
cv.put(BookmarkLocationsDao.Table.COLUMN_LONG, bookmarkLocation.location.getLongitude());
|
||||
cv.put(BookmarkLocationsDao.Table.COLUMN_PIC, bookmarkLocation.pic);
|
||||
cv.put(BookmarkLocationsDao.Table.COLUMN_EXISTS, bookmarkLocation.exists.toString());
|
||||
return cv;
|
||||
}
|
||||
|
||||
public static class Table {
|
||||
public static final String TABLE_NAME = "bookmarksLocations";
|
||||
|
||||
static final String COLUMN_NAME = "location_name";
|
||||
static final String COLUMN_LANGUAGE = "location_language";
|
||||
static final String COLUMN_DESCRIPTION = "location_description";
|
||||
static final String COLUMN_LAT = "location_lat";
|
||||
static final String COLUMN_LONG = "location_long";
|
||||
static final String COLUMN_CATEGORY = "location_category";
|
||||
static final String COLUMN_LABEL_TEXT = "location_label_text";
|
||||
static final String COLUMN_LABEL_ICON = "location_label_icon";
|
||||
static final String COLUMN_IMAGE_URL = "location_image_url";
|
||||
static final String COLUMN_WIKIPEDIA_LINK = "location_wikipedia_link";
|
||||
static final String COLUMN_WIKIDATA_LINK = "location_wikidata_link";
|
||||
static final String COLUMN_COMMONS_LINK = "location_commons_link";
|
||||
static final String COLUMN_PIC = "location_pic";
|
||||
static final String COLUMN_EXISTS = "location_exists";
|
||||
|
||||
// NOTE! KEEP IN SAME ORDER AS THEY ARE DEFINED UP THERE. HELPS HARD CODE COLUMN INDICES.
|
||||
public static final String[] ALL_FIELDS = {
|
||||
COLUMN_NAME,
|
||||
COLUMN_LANGUAGE,
|
||||
COLUMN_DESCRIPTION,
|
||||
COLUMN_CATEGORY,
|
||||
COLUMN_LABEL_TEXT,
|
||||
COLUMN_LABEL_ICON,
|
||||
COLUMN_LAT,
|
||||
COLUMN_LONG,
|
||||
COLUMN_IMAGE_URL,
|
||||
COLUMN_WIKIPEDIA_LINK,
|
||||
COLUMN_WIKIDATA_LINK,
|
||||
COLUMN_COMMONS_LINK,
|
||||
COLUMN_PIC,
|
||||
COLUMN_EXISTS,
|
||||
};
|
||||
|
||||
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 PRIMARY KEY,"
|
||||
+ COLUMN_LANGUAGE + " STRING,"
|
||||
+ COLUMN_DESCRIPTION + " STRING,"
|
||||
+ COLUMN_CATEGORY + " STRING,"
|
||||
+ COLUMN_LABEL_TEXT + " STRING,"
|
||||
+ COLUMN_LABEL_ICON + " INTEGER,"
|
||||
+ COLUMN_LAT + " DOUBLE,"
|
||||
+ COLUMN_LONG + " DOUBLE,"
|
||||
+ COLUMN_IMAGE_URL + " STRING,"
|
||||
+ COLUMN_WIKIPEDIA_LINK + " STRING,"
|
||||
+ COLUMN_WIKIDATA_LINK + " STRING,"
|
||||
+ COLUMN_COMMONS_LINK + " STRING,"
|
||||
+ COLUMN_PIC + " STRING,"
|
||||
+ COLUMN_EXISTS + " STRING"
|
||||
+ ");";
|
||||
|
||||
public static void onCreate(SQLiteDatabase db) {
|
||||
db.execSQL(CREATE_TABLE_STATEMENT);
|
||||
}
|
||||
|
||||
public static void onDelete(SQLiteDatabase db) {
|
||||
db.execSQL(DROP_TABLE_STATEMENT);
|
||||
onCreate(db);
|
||||
}
|
||||
|
||||
public static void onUpdate(final SQLiteDatabase db, int from, final int to) {
|
||||
Timber.d("bookmarksLocations db is updated from:"+from+", to:"+to);
|
||||
if (from == to) {
|
||||
return;
|
||||
}
|
||||
if (from < 7) {
|
||||
// doesn't exist yet
|
||||
from++;
|
||||
onUpdate(db, from, to);
|
||||
return;
|
||||
}
|
||||
if (from == 7) {
|
||||
// table added in version 8
|
||||
onCreate(db);
|
||||
from++;
|
||||
onUpdate(db, from, to);
|
||||
return;
|
||||
}
|
||||
if (from < 10) {
|
||||
from++;
|
||||
onUpdate(db, from, to);
|
||||
return;
|
||||
}
|
||||
if (from == 10) {
|
||||
//This is safe, and can be called clean, as we/I do not remember the appropriate version for this
|
||||
//We are anyways switching to room, these things won't be necessary then
|
||||
try {
|
||||
db.execSQL("ALTER TABLE bookmarksLocations ADD COLUMN location_pic STRING;");
|
||||
}catch (SQLiteException exception){
|
||||
Timber.e(exception);//
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (from >= 12) {
|
||||
try {
|
||||
db.execSQL(
|
||||
"ALTER TABLE bookmarksLocations ADD COLUMN location_destroyed STRING;");
|
||||
} catch (SQLiteException exception) {
|
||||
Timber.e(exception);
|
||||
}
|
||||
}
|
||||
if (from >= 13){
|
||||
try {
|
||||
db.execSQL("ALTER TABLE bookmarksLocations ADD COLUMN location_language STRING;");
|
||||
} catch (SQLiteException exception){
|
||||
Timber.e(exception);
|
||||
}
|
||||
}
|
||||
if (from >= 14){
|
||||
try {
|
||||
db.execSQL("ALTER TABLE bookmarksLocations ADD COLUMN location_exists STRING;");
|
||||
} catch (SQLiteException exception){
|
||||
Timber.e(exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
package fr.free.nrw.commons.bookmarks.locations
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import fr.free.nrw.commons.nearby.NearbyController
|
||||
import fr.free.nrw.commons.nearby.Place
|
||||
|
||||
/**
|
||||
* DAO for managing bookmark locations in the database.
|
||||
*/
|
||||
@Dao
|
||||
abstract class BookmarkLocationsDao {
|
||||
|
||||
/**
|
||||
* Adds or updates a bookmark location in the database.
|
||||
*/
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
abstract suspend fun addBookmarkLocation(bookmarkLocation: BookmarksLocations)
|
||||
|
||||
/**
|
||||
* Fetches all bookmark locations from the database.
|
||||
*/
|
||||
@Query("SELECT * FROM bookmarks_locations")
|
||||
abstract suspend fun getAllBookmarksLocations(): List<BookmarksLocations>
|
||||
|
||||
/**
|
||||
* Checks if a bookmark location exists by name.
|
||||
*/
|
||||
@Query("SELECT EXISTS (SELECT 1 FROM bookmarks_locations WHERE location_name = :name)")
|
||||
abstract suspend fun findBookmarkLocation(name: String): Boolean
|
||||
|
||||
/**
|
||||
* Deletes a bookmark location from the database.
|
||||
*/
|
||||
@Delete
|
||||
abstract suspend fun deleteBookmarkLocation(bookmarkLocation: BookmarksLocations)
|
||||
|
||||
/**
|
||||
* Adds or removes a bookmark location and updates markers.
|
||||
* @return `true` if added, `false` if removed.
|
||||
*/
|
||||
suspend fun updateBookmarkLocation(bookmarkLocation: Place): Boolean {
|
||||
val exists = findBookmarkLocation(bookmarkLocation.name)
|
||||
|
||||
if (exists) {
|
||||
deleteBookmarkLocation(bookmarkLocation.toBookmarksLocations())
|
||||
NearbyController.updateMarkerLabelListBookmark(bookmarkLocation, false)
|
||||
} else {
|
||||
addBookmarkLocation(bookmarkLocation.toBookmarksLocations())
|
||||
NearbyController.updateMarkerLabelListBookmark(bookmarkLocation, true)
|
||||
}
|
||||
|
||||
return !exists
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches all bookmark locations as `Place` objects.
|
||||
*/
|
||||
suspend fun getAllBookmarksLocationsPlace(): List<Place> {
|
||||
return getAllBookmarksLocations().map { it.toPlace() }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,137 +0,0 @@
|
|||
package fr.free.nrw.commons.bookmarks.locations;
|
||||
|
||||
import android.Manifest.permission;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import androidx.activity.result.ActivityResultCallback;
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import dagger.android.support.DaggerFragment;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.contributions.ContributionController;
|
||||
import fr.free.nrw.commons.databinding.FragmentBookmarksLocationsBinding;
|
||||
import fr.free.nrw.commons.nearby.Place;
|
||||
import fr.free.nrw.commons.nearby.fragments.CommonPlaceClickActions;
|
||||
import fr.free.nrw.commons.nearby.fragments.PlaceAdapter;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.inject.Inject;
|
||||
import kotlin.Unit;
|
||||
|
||||
public class BookmarkLocationsFragment extends DaggerFragment {
|
||||
|
||||
public FragmentBookmarksLocationsBinding binding;
|
||||
|
||||
@Inject BookmarkLocationsController controller;
|
||||
@Inject ContributionController contributionController;
|
||||
@Inject BookmarkLocationsDao bookmarkLocationDao;
|
||||
@Inject CommonPlaceClickActions commonPlaceClickActions;
|
||||
private PlaceAdapter adapter;
|
||||
|
||||
private final ActivityResultLauncher<Intent> cameraPickLauncherForResult =
|
||||
registerForActivityResult(new StartActivityForResult(),
|
||||
result -> {
|
||||
contributionController.handleActivityResultWithCallback(requireActivity(), callbacks -> {
|
||||
contributionController.onPictureReturnedFromCamera(result, requireActivity(), callbacks);
|
||||
});
|
||||
});
|
||||
|
||||
private final ActivityResultLauncher<Intent> galleryPickLauncherForResult =
|
||||
registerForActivityResult(new StartActivityForResult(),
|
||||
result -> {
|
||||
contributionController.handleActivityResultWithCallback(requireActivity(), callbacks -> {
|
||||
contributionController.onPictureReturnedFromGallery(result, requireActivity(), callbacks);
|
||||
});
|
||||
});
|
||||
|
||||
private ActivityResultLauncher<String[]> inAppCameraLocationPermissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback<Map<String, Boolean>>() {
|
||||
@Override
|
||||
public void onActivityResult(Map<String, Boolean> result) {
|
||||
boolean areAllGranted = true;
|
||||
for(final boolean b : result.values()) {
|
||||
areAllGranted = areAllGranted && b;
|
||||
}
|
||||
|
||||
if (areAllGranted) {
|
||||
contributionController.locationPermissionCallback.onLocationPermissionGranted();
|
||||
} else {
|
||||
if (shouldShowRequestPermissionRationale(permission.ACCESS_FINE_LOCATION)) {
|
||||
contributionController.handleShowRationaleFlowCameraLocation(getActivity(), inAppCameraLocationPermissionLauncher, cameraPickLauncherForResult);
|
||||
} else {
|
||||
contributionController.locationPermissionCallback.onLocationPermissionDenied(getActivity().getString(R.string.in_app_camera_location_permission_denied));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Create an instance of the fragment with the right bundle parameters
|
||||
* @return an instance of the fragment
|
||||
*/
|
||||
public static BookmarkLocationsFragment newInstance() {
|
||||
return new BookmarkLocationsFragment();
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(
|
||||
@NonNull LayoutInflater inflater,
|
||||
ViewGroup container,
|
||||
Bundle savedInstanceState
|
||||
) {
|
||||
binding = FragmentBookmarksLocationsBinding.inflate(inflater, container, false);
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
binding.loadingImagesProgressBar.setVisibility(View.VISIBLE);
|
||||
binding.listView.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
adapter = new PlaceAdapter(bookmarkLocationDao,
|
||||
place -> Unit.INSTANCE,
|
||||
(place, isBookmarked) -> {
|
||||
adapter.remove(place);
|
||||
return Unit.INSTANCE;
|
||||
},
|
||||
commonPlaceClickActions,
|
||||
inAppCameraLocationPermissionLauncher,
|
||||
galleryPickLauncherForResult,
|
||||
cameraPickLauncherForResult
|
||||
);
|
||||
binding.listView.setAdapter(adapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
initList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the recycler view with bookmarked locations
|
||||
*/
|
||||
private void initList() {
|
||||
List<Place> places = controller.loadFavoritesLocations();
|
||||
adapter.setItems(places);
|
||||
binding.loadingImagesProgressBar.setVisibility(View.GONE);
|
||||
if (places.size() <= 0) {
|
||||
binding.statusMessage.setText(R.string.bookmark_empty);
|
||||
binding.statusMessage.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
binding.statusMessage.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
binding = null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,161 @@
|
|||
package fr.free.nrw.commons.bookmarks.locations
|
||||
|
||||
import android.Manifest.permission
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.contract.ActivityResultContracts.RequestMultiplePermissions
|
||||
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import dagger.android.support.DaggerFragment
|
||||
import fr.free.nrw.commons.R
|
||||
import fr.free.nrw.commons.contributions.ContributionController
|
||||
import fr.free.nrw.commons.databinding.FragmentBookmarksLocationsBinding
|
||||
import fr.free.nrw.commons.filepicker.FilePicker
|
||||
import fr.free.nrw.commons.nearby.Place
|
||||
import fr.free.nrw.commons.nearby.fragments.CommonPlaceClickActions
|
||||
import fr.free.nrw.commons.nearby.fragments.PlaceAdapter
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
class BookmarkLocationsFragment : DaggerFragment() {
|
||||
|
||||
private var binding: FragmentBookmarksLocationsBinding? = null
|
||||
|
||||
@Inject lateinit var controller: BookmarkLocationsController
|
||||
@Inject lateinit var contributionController: ContributionController
|
||||
@Inject lateinit var bookmarkLocationDao: BookmarkLocationsDao
|
||||
@Inject lateinit var commonPlaceClickActions: CommonPlaceClickActions
|
||||
|
||||
private lateinit var inAppCameraLocationPermissionLauncher:
|
||||
ActivityResultLauncher<Array<String>>
|
||||
private lateinit var adapter: PlaceAdapter
|
||||
|
||||
private val cameraPickLauncherForResult =
|
||||
registerForActivityResult(StartActivityForResult()) { result ->
|
||||
contributionController.handleActivityResultWithCallback(
|
||||
requireActivity(),
|
||||
object: FilePicker.HandleActivityResult {
|
||||
override fun onHandleActivityResult(callbacks: FilePicker.Callbacks) {
|
||||
contributionController.onPictureReturnedFromCamera(
|
||||
result,
|
||||
requireActivity(),
|
||||
callbacks
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private val galleryPickLauncherForResult =
|
||||
registerForActivityResult(StartActivityForResult()) { result ->
|
||||
contributionController.handleActivityResultWithCallback(
|
||||
requireActivity(),
|
||||
object: FilePicker.HandleActivityResult {
|
||||
override fun onHandleActivityResult(callbacks: FilePicker.Callbacks) {
|
||||
contributionController.onPictureReturnedFromGallery(
|
||||
result,
|
||||
requireActivity(),
|
||||
callbacks
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun newInstance(): BookmarkLocationsFragment {
|
||||
return BookmarkLocationsFragment()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
binding = FragmentBookmarksLocationsBinding.inflate(inflater, container, false)
|
||||
return binding?.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
binding?.loadingImagesProgressBar?.visibility = View.VISIBLE
|
||||
binding?.listView?.layoutManager = LinearLayoutManager(context)
|
||||
|
||||
inAppCameraLocationPermissionLauncher =
|
||||
registerForActivityResult(RequestMultiplePermissions()) { result ->
|
||||
val areAllGranted = result.values.all { it }
|
||||
|
||||
if (areAllGranted) {
|
||||
contributionController.locationPermissionCallback?.onLocationPermissionGranted()
|
||||
} else {
|
||||
if (shouldShowRequestPermissionRationale(permission.ACCESS_FINE_LOCATION)) {
|
||||
contributionController.handleShowRationaleFlowCameraLocation(
|
||||
requireActivity(),
|
||||
inAppCameraLocationPermissionLauncher,
|
||||
cameraPickLauncherForResult
|
||||
)
|
||||
} else {
|
||||
contributionController.locationPermissionCallback
|
||||
?.onLocationPermissionDenied(
|
||||
getString(R.string.in_app_camera_location_permission_denied)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
adapter = PlaceAdapter(
|
||||
bookmarkLocationDao,
|
||||
lifecycleScope,
|
||||
{ },
|
||||
{ place, _ ->
|
||||
adapter.remove(place)
|
||||
},
|
||||
commonPlaceClickActions,
|
||||
inAppCameraLocationPermissionLauncher,
|
||||
galleryPickLauncherForResult,
|
||||
cameraPickLauncherForResult
|
||||
)
|
||||
binding?.listView?.adapter = adapter
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
initList()
|
||||
}
|
||||
|
||||
fun initList() {
|
||||
var places: List<Place>
|
||||
if(view != null) {
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
places = controller.loadFavoritesLocations()
|
||||
updateUIList(places)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateUIList(places: List<Place>) {
|
||||
adapter.items = places
|
||||
binding?.loadingImagesProgressBar?.visibility = View.GONE
|
||||
if (places.isEmpty()) {
|
||||
binding?.statusMessage?.text = getString(R.string.bookmark_empty)
|
||||
binding?.statusMessage?.visibility = View.VISIBLE
|
||||
} else {
|
||||
binding?.statusMessage?.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
// Make sure to null out the binding to avoid memory leaks
|
||||
binding = null
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package fr.free.nrw.commons.bookmarks.locations
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import fr.free.nrw.commons.nearby.Place
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
class BookmarkLocationsViewModel(
|
||||
private val bookmarkLocationsDao: BookmarkLocationsDao
|
||||
): ViewModel() {
|
||||
|
||||
// fun getAllBookmarkLocations(): List<Place> {
|
||||
// return bookmarkLocationsDao.getAllBookmarksLocationsPlace()
|
||||
// }
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
package fr.free.nrw.commons.bookmarks.locations
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import fr.free.nrw.commons.location.LatLng
|
||||
import fr.free.nrw.commons.nearby.Label
|
||||
import fr.free.nrw.commons.nearby.Place
|
||||
import fr.free.nrw.commons.nearby.Sitelinks
|
||||
|
||||
@Entity(tableName = "bookmarks_locations")
|
||||
data class BookmarksLocations(
|
||||
@PrimaryKey @ColumnInfo(name = "location_name") val locationName: String,
|
||||
@ColumnInfo(name = "location_language") val locationLanguage: String,
|
||||
@ColumnInfo(name = "location_description") val locationDescription: String,
|
||||
@ColumnInfo(name = "location_lat") val locationLat: Double,
|
||||
@ColumnInfo(name = "location_long") val locationLong: Double,
|
||||
@ColumnInfo(name = "location_category") val locationCategory: String,
|
||||
@ColumnInfo(name = "location_label_text") val locationLabelText: String,
|
||||
@ColumnInfo(name = "location_label_icon") val locationLabelIcon: Int?,
|
||||
@ColumnInfo(name = "location_image_url") val locationImageUrl: String,
|
||||
@ColumnInfo(name = "location_wikipedia_link") val locationWikipediaLink: String,
|
||||
@ColumnInfo(name = "location_wikidata_link") val locationWikidataLink: String,
|
||||
@ColumnInfo(name = "location_commons_link") val locationCommonsLink: String,
|
||||
@ColumnInfo(name = "location_pic") val locationPic: String,
|
||||
@ColumnInfo(name = "location_exists") val locationExists: Boolean
|
||||
)
|
||||
|
||||
fun BookmarksLocations.toPlace(): Place {
|
||||
val location = LatLng(
|
||||
locationLat,
|
||||
locationLong,
|
||||
1F
|
||||
)
|
||||
|
||||
val builder = Sitelinks.Builder().apply {
|
||||
setWikipediaLink(locationWikipediaLink)
|
||||
setWikidataLink(locationWikidataLink)
|
||||
setCommonsLink(locationCommonsLink)
|
||||
}
|
||||
|
||||
return Place(
|
||||
locationLanguage,
|
||||
locationName,
|
||||
Label.fromText(locationLabelText),
|
||||
locationDescription,
|
||||
location,
|
||||
locationCategory,
|
||||
builder.build(),
|
||||
locationPic,
|
||||
locationExists
|
||||
)
|
||||
}
|
||||
|
||||
fun Place.toBookmarksLocations(): BookmarksLocations {
|
||||
return BookmarksLocations(
|
||||
locationName = name,
|
||||
locationLanguage = language,
|
||||
locationDescription = longDescription,
|
||||
locationCategory = category,
|
||||
locationLat = location.latitude,
|
||||
locationLong = location.longitude,
|
||||
locationLabelText = label?.text ?: "",
|
||||
locationLabelIcon = label?.icon,
|
||||
locationImageUrl = pic,
|
||||
locationWikipediaLink = siteLinks.wikipediaLink.toString(),
|
||||
locationWikidataLink = siteLinks.wikidataLink.toString(),
|
||||
locationCommonsLink = siteLinks.commonsLink.toString(),
|
||||
locationPic = pic,
|
||||
locationExists = exists
|
||||
)
|
||||
}
|
||||
|
|
@ -18,8 +18,9 @@ class DBOpenHelper(
|
|||
|
||||
companion object {
|
||||
private const val DATABASE_NAME = "commons.db"
|
||||
private const val DATABASE_VERSION = 21
|
||||
private const val DATABASE_VERSION = 22
|
||||
const val CONTRIBUTIONS_TABLE = "contributions"
|
||||
const val BOOKMARKS_LOCATIONS = "bookmarksLocations"
|
||||
private const val DROP_TABLE_STATEMENT = "DROP TABLE IF EXISTS %s"
|
||||
}
|
||||
|
||||
|
|
@ -30,7 +31,6 @@ class DBOpenHelper(
|
|||
override fun onCreate(db: SQLiteDatabase) {
|
||||
CategoryDao.Table.onCreate(db)
|
||||
BookmarkPicturesDao.Table.onCreate(db)
|
||||
BookmarkLocationsDao.Table.onCreate(db)
|
||||
BookmarkItemsDao.Table.onCreate(db)
|
||||
RecentSearchesDao.Table.onCreate(db)
|
||||
RecentLanguagesDao.Table.onCreate(db)
|
||||
|
|
@ -39,11 +39,11 @@ class DBOpenHelper(
|
|||
override fun onUpgrade(db: SQLiteDatabase, from: Int, to: Int) {
|
||||
CategoryDao.Table.onUpdate(db, from, to)
|
||||
BookmarkPicturesDao.Table.onUpdate(db, from, to)
|
||||
BookmarkLocationsDao.Table.onUpdate(db, from, to)
|
||||
BookmarkItemsDao.Table.onUpdate(db, from, to)
|
||||
RecentSearchesDao.Table.onUpdate(db, from, to)
|
||||
RecentLanguagesDao.Table.onUpdate(db, from, to)
|
||||
deleteTable(db, CONTRIBUTIONS_TABLE)
|
||||
deleteTable(db, BOOKMARKS_LOCATIONS)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,10 +1,16 @@
|
|||
package fr.free.nrw.commons.db
|
||||
|
||||
import android.content.Context
|
||||
import androidx.room.Database
|
||||
import androidx.room.Room
|
||||
import androidx.room.RoomDatabase
|
||||
import androidx.room.TypeConverters
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import fr.free.nrw.commons.bookmarks.category.BookmarkCategoriesDao
|
||||
import fr.free.nrw.commons.bookmarks.category.BookmarksCategoryModal
|
||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao
|
||||
import fr.free.nrw.commons.bookmarks.locations.BookmarksLocations
|
||||
import fr.free.nrw.commons.contributions.Contribution
|
||||
import fr.free.nrw.commons.contributions.ContributionDao
|
||||
import fr.free.nrw.commons.customselector.database.NotForUploadStatus
|
||||
|
|
@ -23,8 +29,8 @@ import fr.free.nrw.commons.upload.depicts.DepictsDao
|
|||
*
|
||||
*/
|
||||
@Database(
|
||||
entities = [Contribution::class, Depicts::class, UploadedStatus::class, NotForUploadStatus::class, ReviewEntity::class, Place::class, BookmarksCategoryModal::class],
|
||||
version = 19,
|
||||
entities = [Contribution::class, Depicts::class, UploadedStatus::class, NotForUploadStatus::class, ReviewEntity::class, Place::class, BookmarksCategoryModal::class, BookmarksLocations::class],
|
||||
version = 20,
|
||||
exportSchema = false,
|
||||
)
|
||||
@TypeConverters(Converters::class)
|
||||
|
|
@ -42,4 +48,6 @@ abstract class AppDatabase : RoomDatabase() {
|
|||
abstract fun ReviewDao(): ReviewDao
|
||||
|
||||
abstract fun bookmarkCategoriesDao(): BookmarkCategoriesDao
|
||||
|
||||
abstract fun bookmarkLocationsDao(): BookmarkLocationsDao
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import android.app.Activity
|
|||
import android.content.ContentProviderClient
|
||||
import android.content.ContentResolver
|
||||
import android.content.Context
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import androidx.collection.LruCache
|
||||
import androidx.room.Room.databaseBuilder
|
||||
|
|
@ -16,6 +17,7 @@ import fr.free.nrw.commons.BuildConfig
|
|||
import fr.free.nrw.commons.R
|
||||
import fr.free.nrw.commons.auth.SessionManager
|
||||
import fr.free.nrw.commons.bookmarks.category.BookmarkCategoriesDao
|
||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao
|
||||
import fr.free.nrw.commons.contributions.ContributionDao
|
||||
import fr.free.nrw.commons.customselector.database.NotForUploadStatusDao
|
||||
import fr.free.nrw.commons.customselector.database.UploadedStatusDao
|
||||
|
|
@ -36,6 +38,7 @@ import fr.free.nrw.commons.wikidata.WikidataEditListenerImpl
|
|||
import io.reactivex.Scheduler
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import timber.log.Timber
|
||||
import java.util.Objects
|
||||
import javax.inject.Named
|
||||
import javax.inject.Singleton
|
||||
|
|
@ -49,6 +52,11 @@ import javax.inject.Singleton
|
|||
@Module
|
||||
@Suppress("unused")
|
||||
open class CommonsApplicationModule(private val applicationContext: Context) {
|
||||
|
||||
init {
|
||||
appContext = applicationContext
|
||||
}
|
||||
|
||||
@Provides
|
||||
fun providesImageFileLoader(context: Context): ImageFileLoader =
|
||||
ImageFileLoader(context)
|
||||
|
|
@ -110,11 +118,6 @@ open class CommonsApplicationModule(private val applicationContext: Context) {
|
|||
fun provideBookmarkContentProviderClient(context: Context): ContentProviderClient? =
|
||||
context.contentResolver.acquireContentProviderClient(BuildConfig.BOOKMARK_AUTHORITY)
|
||||
|
||||
@Provides
|
||||
@Named("bookmarksLocation")
|
||||
fun provideBookmarkLocationContentProviderClient(context: Context): ContentProviderClient? =
|
||||
context.contentResolver.acquireContentProviderClient(BuildConfig.BOOKMARK_LOCATIONS_AUTHORITY)
|
||||
|
||||
@Provides
|
||||
@Named("bookmarksItem")
|
||||
fun provideBookmarkItemContentProviderClient(context: Context): ContentProviderClient? =
|
||||
|
|
@ -196,7 +199,10 @@ open class CommonsApplicationModule(private val applicationContext: Context) {
|
|||
applicationContext,
|
||||
AppDatabase::class.java,
|
||||
"commons_room.db"
|
||||
).addMigrations(MIGRATION_1_2).fallbackToDestructiveMigration().build()
|
||||
).addMigrations(
|
||||
MIGRATION_1_2,
|
||||
MIGRATION_19_TO_20
|
||||
).fallbackToDestructiveMigration().build()
|
||||
|
||||
@Provides
|
||||
fun providesContributionsDao(appDatabase: AppDatabase): ContributionDao =
|
||||
|
|
@ -206,6 +212,10 @@ open class CommonsApplicationModule(private val applicationContext: Context) {
|
|||
fun providesPlaceDao(appDatabase: AppDatabase): PlaceDao =
|
||||
appDatabase.PlaceDao()
|
||||
|
||||
@Provides
|
||||
fun providesBookmarkLocationsDao(appDatabase: AppDatabase): BookmarkLocationsDao =
|
||||
appDatabase.bookmarkLocationsDao()
|
||||
|
||||
@Provides
|
||||
fun providesDepictDao(appDatabase: AppDatabase): DepictsDao =
|
||||
appDatabase.DepictsDao()
|
||||
|
|
@ -239,6 +249,9 @@ open class CommonsApplicationModule(private val applicationContext: Context) {
|
|||
const val IO_THREAD: String = "io_thread"
|
||||
const val MAIN_THREAD: String = "main_thread"
|
||||
|
||||
lateinit var appContext: Context
|
||||
private set
|
||||
|
||||
val MIGRATION_1_2: Migration = object : Migration(1, 2) {
|
||||
override fun migrate(db: SupportSQLiteDatabase) {
|
||||
db.execSQL(
|
||||
|
|
@ -246,5 +259,101 @@ open class CommonsApplicationModule(private val applicationContext: Context) {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
private val MIGRATION_19_TO_20 = object : Migration(19, 20) {
|
||||
override fun migrate(db: SupportSQLiteDatabase) {
|
||||
db.execSQL(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS bookmarks_locations (
|
||||
location_name TEXT NOT NULL PRIMARY KEY,
|
||||
location_language TEXT NOT NULL,
|
||||
location_description TEXT NOT NULL,
|
||||
location_lat REAL NOT NULL,
|
||||
location_long REAL NOT NULL,
|
||||
location_category TEXT NOT NULL,
|
||||
location_label_text TEXT NOT NULL,
|
||||
location_label_icon INTEGER,
|
||||
location_image_url TEXT NOT NULL DEFAULT '',
|
||||
location_wikipedia_link TEXT NOT NULL,
|
||||
location_wikidata_link TEXT NOT NULL,
|
||||
location_commons_link TEXT NOT NULL,
|
||||
location_pic TEXT NOT NULL,
|
||||
location_exists INTEGER NOT NULL CHECK(location_exists IN (0, 1))
|
||||
)
|
||||
"""
|
||||
)
|
||||
|
||||
val oldDbPath = appContext.getDatabasePath("commons.db").path
|
||||
val oldDb = SQLiteDatabase
|
||||
.openDatabase(oldDbPath, null, SQLiteDatabase.OPEN_READONLY)
|
||||
|
||||
val cursor = oldDb.rawQuery("SELECT * FROM bookmarksLocations", null)
|
||||
|
||||
while (cursor.moveToNext()) {
|
||||
val locationName =
|
||||
cursor.getString(cursor.getColumnIndexOrThrow("location_name"))
|
||||
val locationLanguage =
|
||||
cursor.getString(cursor.getColumnIndexOrThrow("location_language"))
|
||||
val locationDescription =
|
||||
cursor.getString(cursor.getColumnIndexOrThrow("location_description"))
|
||||
val locationCategory =
|
||||
cursor.getString(cursor.getColumnIndexOrThrow("location_category"))
|
||||
val locationLabelText =
|
||||
cursor.getString(cursor.getColumnIndexOrThrow("location_label_text"))
|
||||
val locationLabelIcon =
|
||||
cursor.getInt(cursor.getColumnIndexOrThrow("location_label_icon"))
|
||||
val locationLat =
|
||||
cursor.getDouble(cursor.getColumnIndexOrThrow("location_lat"))
|
||||
val locationLong =
|
||||
cursor.getDouble(cursor.getColumnIndexOrThrow("location_long"))
|
||||
|
||||
// Handle NULL values safely
|
||||
val locationImageUrl =
|
||||
cursor.getString(
|
||||
cursor.getColumnIndexOrThrow("location_image_url")
|
||||
) ?: ""
|
||||
val locationWikipediaLink =
|
||||
cursor.getString(
|
||||
cursor.getColumnIndexOrThrow("location_wikipedia_link")
|
||||
) ?: ""
|
||||
val locationWikidataLink =
|
||||
cursor.getString(
|
||||
cursor.getColumnIndexOrThrow("location_wikidata_link")
|
||||
) ?: ""
|
||||
val locationCommonsLink =
|
||||
cursor.getString(
|
||||
cursor.getColumnIndexOrThrow("location_commons_link")
|
||||
) ?: ""
|
||||
val locationPic =
|
||||
cursor.getString(
|
||||
cursor.getColumnIndexOrThrow("location_pic")
|
||||
) ?: ""
|
||||
val locationExists =
|
||||
cursor.getInt(
|
||||
cursor.getColumnIndexOrThrow("location_exists")
|
||||
)
|
||||
|
||||
db.execSQL(
|
||||
"""
|
||||
INSERT OR REPLACE INTO bookmarks_locations (
|
||||
location_name, location_language, location_description, location_category,
|
||||
location_label_text, location_label_icon, location_lat, location_long,
|
||||
location_image_url, location_wikipedia_link, location_wikidata_link,
|
||||
location_commons_link, location_pic, location_exists
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
arrayOf(
|
||||
locationName, locationLanguage, locationDescription, locationCategory,
|
||||
locationLabelText, locationLabelIcon, locationLat, locationLong,
|
||||
locationImageUrl, locationWikipediaLink, locationWikidataLink,
|
||||
locationCommonsLink, locationPic, locationExists
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
cursor.close()
|
||||
oldDb.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ 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
|
||||
import fr.free.nrw.commons.explore.recentsearches.RecentSearchesContentProvider
|
||||
|
|
@ -26,9 +25,6 @@ abstract class ContentProviderBuilderModule {
|
|||
@ContributesAndroidInjector
|
||||
abstract fun bindBookmarkContentProvider(): BookmarkPicturesContentProvider
|
||||
|
||||
@ContributesAndroidInjector
|
||||
abstract fun bindBookmarkLocationContentProvider(): BookmarkLocationsContentProvider
|
||||
|
||||
@ContributesAndroidInjector
|
||||
abstract fun bindBookmarkItemContentProvider(): BookmarkItemsContentProvider
|
||||
|
||||
|
|
|
|||
|
|
@ -68,7 +68,21 @@ class BottomSheetAdapter(
|
|||
item.imageResourceId == R.drawable.ic_round_star_border_24px
|
||||
) {
|
||||
item.imageResourceId = icon
|
||||
this.notifyItemChanged(index)
|
||||
notifyItemChanged(index)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun toggleBookmarkIcon() {
|
||||
itemList.forEachIndexed { index, item ->
|
||||
if(item.imageResourceId == R.drawable.ic_round_star_filled_24px) {
|
||||
item.imageResourceId = R.drawable.ic_round_star_border_24px
|
||||
notifyItemChanged(index)
|
||||
return
|
||||
} else if(item.imageResourceId == R.drawable.ic_round_star_border_24px){
|
||||
item.imageResourceId = R.drawable.ic_round_star_filled_24px
|
||||
notifyItemChanged(index)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
|
|||
28
app/src/main/java/fr/free/nrw/commons/nearby/NearbyUtil.kt
Normal file
28
app/src/main/java/fr/free/nrw/commons/nearby/NearbyUtil.kt
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
package fr.free.nrw.commons.nearby
|
||||
|
||||
import android.util.Log
|
||||
import androidx.lifecycle.LifecycleCoroutineScope
|
||||
import fr.free.nrw.commons.R
|
||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
|
||||
object NearbyUtil {
|
||||
|
||||
fun getBookmarkLocationExists(
|
||||
bookmarksLocationsDao: BookmarkLocationsDao,
|
||||
name: String,
|
||||
scope: LifecycleCoroutineScope?,
|
||||
bottomSheetAdapter: BottomSheetAdapter,
|
||||
) {
|
||||
scope?.launch {
|
||||
val isBookmarked = bookmarksLocationsDao.findBookmarkLocation(name)
|
||||
Timber.i("isBookmarked: $isBookmarked")
|
||||
if (isBookmarked) {
|
||||
bottomSheetAdapter.updateBookmarkIcon(R.drawable.ic_round_star_filled_24px)
|
||||
} else {
|
||||
bottomSheetAdapter.updateBookmarkIcon(R.drawable.ic_round_star_border_24px)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ import android.view.View.INVISIBLE
|
|||
import android.view.View.VISIBLE
|
||||
import android.widget.RelativeLayout
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.lifecycle.LifecycleCoroutineScope
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.transition.TransitionManager
|
||||
|
|
@ -16,9 +17,11 @@ import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
|
|||
import fr.free.nrw.commons.R
|
||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao
|
||||
import fr.free.nrw.commons.databinding.ItemPlaceBinding
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
fun placeAdapterDelegate(
|
||||
bookmarkLocationDao: BookmarkLocationsDao,
|
||||
scope: LifecycleCoroutineScope?,
|
||||
onItemClick: ((Place) -> Unit)? = null,
|
||||
onCameraClicked: (Place, ActivityResultLauncher<Array<String>>, ActivityResultLauncher<Intent>) -> Unit,
|
||||
onCameraLongPressed: () -> Boolean,
|
||||
|
|
@ -61,7 +64,10 @@ fun placeAdapterDelegate(
|
|||
nearbyButtonLayout.galleryButton.setOnClickListener { onGalleryClicked(item, galleryPickLauncherForResult) }
|
||||
nearbyButtonLayout.galleryButton.setOnLongClickListener { onGalleryLongPressed() }
|
||||
bookmarkButtonImage.setOnClickListener {
|
||||
val isBookmarked = bookmarkLocationDao.updateBookmarkLocation(item)
|
||||
var isBookmarked = false
|
||||
scope?.launch {
|
||||
isBookmarked = bookmarkLocationDao.updateBookmarkLocation(item)
|
||||
}
|
||||
bookmarkButtonImage.setImageResource(
|
||||
if (isBookmarked) R.drawable.ic_round_star_filled_24px else R.drawable.ic_round_star_border_24px,
|
||||
)
|
||||
|
|
@ -93,13 +99,15 @@ fun placeAdapterDelegate(
|
|||
GONE
|
||||
}
|
||||
|
||||
bookmarkButtonImage.setImageResource(
|
||||
if (bookmarkLocationDao.findBookmarkLocation(item)) {
|
||||
R.drawable.ic_round_star_filled_24px
|
||||
} else {
|
||||
R.drawable.ic_round_star_border_24px
|
||||
},
|
||||
)
|
||||
scope?.launch {
|
||||
bookmarkButtonImage.setImageResource(
|
||||
if (bookmarkLocationDao.findBookmarkLocation(item.name)) {
|
||||
R.drawable.ic_round_star_filled_24px
|
||||
} else {
|
||||
R.drawable.ic_round_star_border_24px
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
nearbyButtonLayout.directionsButton.setOnLongClickListener { onDirectionsLongPressed() }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ public interface NearbyParentFragmentContract {
|
|||
|
||||
void setAdvancedQuery(String query);
|
||||
|
||||
void toggleBookmarkedStatus(Place place);
|
||||
void toggleBookmarkedStatus(Place place, LifecycleCoroutineScope scope);
|
||||
|
||||
void handleMapScrolled(LifecycleCoroutineScope scope, boolean isNetworkAvailable);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ import fr.free.nrw.commons.nearby.MarkerPlaceGroup
|
|||
import fr.free.nrw.commons.nearby.NearbyController
|
||||
import fr.free.nrw.commons.nearby.NearbyFilterSearchRecyclerViewAdapter
|
||||
import fr.free.nrw.commons.nearby.NearbyFilterState
|
||||
import fr.free.nrw.commons.nearby.NearbyUtil
|
||||
import fr.free.nrw.commons.nearby.Place
|
||||
import fr.free.nrw.commons.nearby.PlacesRepository
|
||||
import fr.free.nrw.commons.nearby.WikidataFeedback
|
||||
|
|
@ -664,21 +665,23 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(),
|
|||
private fun initRvNearbyList() {
|
||||
binding!!.bottomSheetNearby.rvNearbyList.layoutManager = LinearLayoutManager(context)
|
||||
adapter = PlaceAdapter(
|
||||
bookmarkLocationDao!!,
|
||||
{ place: Place ->
|
||||
bookmarkLocationsDao = bookmarkLocationDao,
|
||||
scope = scope,
|
||||
onPlaceClicked = { place: Place ->
|
||||
moveCameraToPosition(
|
||||
GeoPoint(place.location.latitude, place.location.longitude)
|
||||
GeoPoint(
|
||||
place.location.latitude,
|
||||
place.location.longitude
|
||||
)
|
||||
)
|
||||
Unit
|
||||
},
|
||||
{ place: Place?, isBookmarked: Boolean? ->
|
||||
presenter!!.toggleBookmarkedStatus(place)
|
||||
Unit
|
||||
onBookmarkClicked = { place: Place?, _: Boolean? ->
|
||||
presenter!!.toggleBookmarkedStatus(place, scope)
|
||||
},
|
||||
commonPlaceClickActions!!,
|
||||
inAppCameraLocationPermissionLauncher,
|
||||
galleryPickLauncherForResult,
|
||||
cameraPickLauncherForResult
|
||||
commonPlaceClickActions = commonPlaceClickActions,
|
||||
inAppCameraLocationPermissionLauncher = inAppCameraLocationPermissionLauncher,
|
||||
galleryPickLauncherForResult = galleryPickLauncherForResult,
|
||||
cameraPickLauncherForResult = cameraPickLauncherForResult
|
||||
)
|
||||
binding!!.bottomSheetNearby.rvNearbyList.adapter = adapter
|
||||
}
|
||||
|
|
@ -2303,34 +2306,34 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(),
|
|||
// TODO: Decide button text for fitting in the screen
|
||||
(dataList as ArrayList<BottomSheetItem>).add(
|
||||
BottomSheetItem(
|
||||
fr.free.nrw.commons.R.drawable.ic_round_star_border_24px,
|
||||
R.drawable.ic_round_star_border_24px,
|
||||
""
|
||||
)
|
||||
)
|
||||
(dataList as ArrayList<BottomSheetItem>).add(
|
||||
BottomSheetItem(
|
||||
fr.free.nrw.commons.R.drawable.ic_directions_black_24dp,
|
||||
R.drawable.ic_directions_black_24dp,
|
||||
resources.getString(fr.free.nrw.commons.R.string.nearby_directions)
|
||||
)
|
||||
)
|
||||
if (place.hasWikidataLink()) {
|
||||
(dataList as ArrayList<BottomSheetItem>).add(
|
||||
BottomSheetItem(
|
||||
fr.free.nrw.commons.R.drawable.ic_wikidata_logo_24dp,
|
||||
R.drawable.ic_wikidata_logo_24dp,
|
||||
resources.getString(fr.free.nrw.commons.R.string.nearby_wikidata)
|
||||
)
|
||||
)
|
||||
}
|
||||
(dataList as ArrayList<BottomSheetItem>).add(
|
||||
BottomSheetItem(
|
||||
fr.free.nrw.commons.R.drawable.ic_feedback_black_24dp,
|
||||
R.drawable.ic_feedback_black_24dp,
|
||||
resources.getString(fr.free.nrw.commons.R.string.nearby_wikitalk)
|
||||
)
|
||||
)
|
||||
if (place.hasWikipediaLink()) {
|
||||
(dataList as ArrayList<BottomSheetItem>).add(
|
||||
BottomSheetItem(
|
||||
fr.free.nrw.commons.R.drawable.ic_wikipedia_logo_24dp,
|
||||
R.drawable.ic_wikipedia_logo_24dp,
|
||||
resources.getString(fr.free.nrw.commons.R.string.nearby_wikipedia)
|
||||
)
|
||||
)
|
||||
|
|
@ -2338,7 +2341,7 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(),
|
|||
if (selectedPlace!!.hasCommonsLink()) {
|
||||
(dataList as ArrayList<BottomSheetItem>).add(
|
||||
BottomSheetItem(
|
||||
fr.free.nrw.commons.R.drawable.ic_commons_icon_vector,
|
||||
R.drawable.ic_commons_icon_vector,
|
||||
resources.getString(fr.free.nrw.commons.R.string.nearby_commons)
|
||||
)
|
||||
)
|
||||
|
|
@ -2566,12 +2569,16 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(),
|
|||
}
|
||||
|
||||
private fun updateBookmarkButtonImage(place: Place) {
|
||||
val bookmarkIcon = if (bookmarkLocationDao!!.findBookmarkLocation(place)) {
|
||||
fr.free.nrw.commons.R.drawable.ic_round_star_filled_24px
|
||||
} else {
|
||||
fr.free.nrw.commons.R.drawable.ic_round_star_border_24px
|
||||
}
|
||||
bottomSheetAdapter!!.updateBookmarkIcon(bookmarkIcon)
|
||||
NearbyUtil.getBookmarkLocationExists(
|
||||
bookmarkLocationDao,
|
||||
place.getName(),
|
||||
scope,
|
||||
bottomSheetAdapter!!
|
||||
)
|
||||
}
|
||||
|
||||
private fun toggleBookmarkButtonImage() {
|
||||
bottomSheetAdapter?.toggleBookmarkIcon()
|
||||
}
|
||||
|
||||
override fun onAttach(context: Context) {
|
||||
|
|
@ -2749,26 +2756,31 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(),
|
|||
override fun onBottomSheetItemClick(view: View?, position: Int) {
|
||||
val item = dataList?.get(position) ?: return // Null check for dataList
|
||||
when (item.imageResourceId) {
|
||||
fr.free.nrw.commons.R.drawable.ic_round_star_border_24px,
|
||||
fr.free.nrw.commons.R.drawable.ic_round_star_filled_24px -> {
|
||||
presenter?.toggleBookmarkedStatus(selectedPlace)
|
||||
R.drawable.ic_round_star_border_24px -> {
|
||||
presenter?.toggleBookmarkedStatus(selectedPlace, scope)
|
||||
toggleBookmarkButtonImage()
|
||||
}
|
||||
|
||||
R.drawable.ic_round_star_filled_24px -> {
|
||||
presenter?.toggleBookmarkedStatus(selectedPlace, scope)
|
||||
toggleBookmarkButtonImage()
|
||||
selectedPlace?.let { updateBookmarkButtonImage(it) }
|
||||
}
|
||||
|
||||
fr.free.nrw.commons.R.drawable.ic_directions_black_24dp -> {
|
||||
R.drawable.ic_directions_black_24dp -> {
|
||||
selectedPlace?.let {
|
||||
Utils.handleGeoCoordinates(this.context, it.getLocation())
|
||||
binding?.map?.zoomLevelDouble ?: 0.0
|
||||
}
|
||||
}
|
||||
|
||||
fr.free.nrw.commons.R.drawable.ic_wikidata_logo_24dp -> {
|
||||
R.drawable.ic_wikidata_logo_24dp -> {
|
||||
selectedPlace?.siteLinks?.wikidataLink?.let {
|
||||
Utils.handleWebUrl(this.context, it)
|
||||
}
|
||||
}
|
||||
|
||||
fr.free.nrw.commons.R.drawable.ic_feedback_black_24dp -> {
|
||||
R.drawable.ic_feedback_black_24dp -> {
|
||||
selectedPlace?.let {
|
||||
val intent = Intent(this.context, WikidataFeedback::class.java).apply {
|
||||
putExtra("lat", it.location.latitude)
|
||||
|
|
@ -2780,13 +2792,13 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(),
|
|||
}
|
||||
}
|
||||
|
||||
fr.free.nrw.commons.R.drawable.ic_wikipedia_logo_24dp -> {
|
||||
R.drawable.ic_wikipedia_logo_24dp -> {
|
||||
selectedPlace?.siteLinks?.wikipediaLink?.let {
|
||||
Utils.handleWebUrl(this.context, it)
|
||||
}
|
||||
}
|
||||
|
||||
fr.free.nrw.commons.R.drawable.ic_commons_icon_vector -> {
|
||||
R.drawable.ic_commons_icon_vector -> {
|
||||
selectedPlace?.siteLinks?.commonsLink?.let {
|
||||
Utils.handleWebUrl(this.context, it)
|
||||
}
|
||||
|
|
@ -2800,13 +2812,13 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(),
|
|||
override fun onBottomSheetItemLongClick(view: View?, position: Int) {
|
||||
val item = dataList!![position]
|
||||
val message = when (item.imageResourceId) {
|
||||
fr.free.nrw.commons.R.drawable.ic_round_star_border_24px -> getString(fr.free.nrw.commons.R.string.menu_bookmark)
|
||||
fr.free.nrw.commons.R.drawable.ic_round_star_filled_24px -> getString(fr.free.nrw.commons.R.string.menu_bookmark)
|
||||
fr.free.nrw.commons.R.drawable.ic_directions_black_24dp -> getString(fr.free.nrw.commons.R.string.nearby_directions)
|
||||
fr.free.nrw.commons.R.drawable.ic_wikidata_logo_24dp -> getString(fr.free.nrw.commons.R.string.nearby_wikidata)
|
||||
fr.free.nrw.commons.R.drawable.ic_feedback_black_24dp -> getString(fr.free.nrw.commons.R.string.nearby_wikitalk)
|
||||
fr.free.nrw.commons.R.drawable.ic_wikipedia_logo_24dp -> getString(fr.free.nrw.commons.R.string.nearby_wikipedia)
|
||||
fr.free.nrw.commons.R.drawable.ic_commons_icon_vector -> getString(fr.free.nrw.commons.R.string.nearby_commons)
|
||||
R.drawable.ic_round_star_border_24px -> getString(fr.free.nrw.commons.R.string.menu_bookmark)
|
||||
R.drawable.ic_round_star_filled_24px -> getString(fr.free.nrw.commons.R.string.menu_bookmark)
|
||||
R.drawable.ic_directions_black_24dp -> getString(fr.free.nrw.commons.R.string.nearby_directions)
|
||||
R.drawable.ic_wikidata_logo_24dp -> getString(fr.free.nrw.commons.R.string.nearby_wikidata)
|
||||
R.drawable.ic_feedback_black_24dp -> getString(fr.free.nrw.commons.R.string.nearby_wikitalk)
|
||||
R.drawable.ic_wikipedia_logo_24dp -> getString(fr.free.nrw.commons.R.string.nearby_wikipedia)
|
||||
R.drawable.ic_commons_icon_vector -> getString(fr.free.nrw.commons.R.string.nearby_commons)
|
||||
else -> "Long click"
|
||||
}
|
||||
Toast.makeText(this.context, message, Toast.LENGTH_SHORT).show()
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package fr.free.nrw.commons.nearby.fragments
|
|||
|
||||
import android.content.Intent
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.lifecycle.LifecycleCoroutineScope
|
||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao
|
||||
import fr.free.nrw.commons.nearby.Place
|
||||
import fr.free.nrw.commons.nearby.placeAdapterDelegate
|
||||
|
|
@ -9,6 +10,7 @@ import fr.free.nrw.commons.upload.categories.BaseDelegateAdapter
|
|||
|
||||
class PlaceAdapter(
|
||||
bookmarkLocationsDao: BookmarkLocationsDao,
|
||||
scope: LifecycleCoroutineScope? = null,
|
||||
onPlaceClicked: ((Place) -> Unit)? = null,
|
||||
onBookmarkClicked: (Place, Boolean) -> Unit,
|
||||
commonPlaceClickActions: CommonPlaceClickActions,
|
||||
|
|
@ -18,6 +20,7 @@ class PlaceAdapter(
|
|||
) : BaseDelegateAdapter<Place>(
|
||||
placeAdapterDelegate(
|
||||
bookmarkLocationsDao,
|
||||
scope,
|
||||
onPlaceClicked,
|
||||
commonPlaceClickActions.onCameraClicked(),
|
||||
commonPlaceClickActions.onCameraLongPressed(),
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import kotlinx.coroutines.delay
|
|||
import kotlinx.coroutines.ensureActive
|
||||
import kotlinx.coroutines.job
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
import okhttp3.internal.wait
|
||||
import timber.log.Timber
|
||||
|
|
@ -136,25 +137,31 @@ class NearbyParentFragmentPresenter
|
|||
* @param place The place whose bookmarked status is to be toggled. If the place is `null`,
|
||||
* the operation is skipped.
|
||||
*/
|
||||
override fun toggleBookmarkedStatus(place: Place?) {
|
||||
override fun toggleBookmarkedStatus(
|
||||
place: Place?,
|
||||
scope: LifecycleCoroutineScope?
|
||||
) {
|
||||
if (place == null) return
|
||||
val nowBookmarked = bookmarkLocationDao.updateBookmarkLocation(place)
|
||||
bookmarkChangedPlaces.add(place)
|
||||
val placeIndex =
|
||||
NearbyController.markerLabelList.indexOfFirst { it.place.location == place.location }
|
||||
NearbyController.markerLabelList[placeIndex] = MarkerPlaceGroup(
|
||||
nowBookmarked,
|
||||
NearbyController.markerLabelList[placeIndex].place
|
||||
)
|
||||
nearbyParentFragmentView.setFilterState()
|
||||
var nowBookmarked: Boolean
|
||||
scope?.launch {
|
||||
nowBookmarked = bookmarkLocationDao.updateBookmarkLocation(place)
|
||||
bookmarkChangedPlaces.add(place)
|
||||
val placeIndex =
|
||||
NearbyController.markerLabelList.indexOfFirst { it.place.location == place.location }
|
||||
NearbyController.markerLabelList[placeIndex] = MarkerPlaceGroup(
|
||||
nowBookmarked,
|
||||
NearbyController.markerLabelList[placeIndex].place
|
||||
)
|
||||
nearbyParentFragmentView.setFilterState()
|
||||
}
|
||||
}
|
||||
|
||||
override fun attachView(view: NearbyParentFragmentContract.View) {
|
||||
this.nearbyParentFragmentView = view
|
||||
nearbyParentFragmentView = view
|
||||
}
|
||||
|
||||
override fun detachView() {
|
||||
this.nearbyParentFragmentView = DUMMY
|
||||
nearbyParentFragmentView = DUMMY
|
||||
}
|
||||
|
||||
override fun removeNearbyPreferences(applicationKvStore: JsonKvStore) {
|
||||
|
|
@ -337,7 +344,7 @@ class NearbyParentFragmentPresenter
|
|||
for (i in 0..updatedGroups.lastIndex) {
|
||||
val repoPlace = placesRepository.fetchPlace(updatedGroups[i].place.entityID)
|
||||
if (repoPlace != null && repoPlace.name != null && repoPlace.name != ""){
|
||||
updatedGroups[i].isBookmarked = bookmarkLocationDao.findBookmarkLocation(repoPlace)
|
||||
updatedGroups[i].isBookmarked = bookmarkLocationDao.findBookmarkLocation(repoPlace.name)
|
||||
updatedGroups[i].place.apply {
|
||||
name = repoPlace.name
|
||||
isMonument = repoPlace.isMonument
|
||||
|
|
@ -375,7 +382,7 @@ class NearbyParentFragmentPresenter
|
|||
collectResults.send(
|
||||
fetchedPlaces.mapIndexed { index, place ->
|
||||
Pair(indices[index], MarkerPlaceGroup(
|
||||
bookmarkLocationDao.findBookmarkLocation(place),
|
||||
bookmarkLocationDao.findBookmarkLocation(place.name),
|
||||
place
|
||||
))
|
||||
}
|
||||
|
|
@ -393,7 +400,10 @@ class NearbyParentFragmentPresenter
|
|||
|
||||
onePlaceBatch.add(Pair(i, MarkerPlaceGroup(
|
||||
bookmarkLocationDao.findBookmarkLocation(
|
||||
fetchedPlace[0]),fetchedPlace[0])))
|
||||
fetchedPlace[0].name
|
||||
),
|
||||
fetchedPlace[0]
|
||||
)))
|
||||
} catch (e: Exception) {
|
||||
Timber.tag("NearbyPinDetails").e(e)
|
||||
onePlaceBatch.add(Pair(i, updatedGroups[i]))
|
||||
|
|
@ -457,7 +467,7 @@ class NearbyParentFragmentPresenter
|
|||
if (bookmarkChangedPlacesBacklog.containsKey(group.place.location)) {
|
||||
updatedGroups[index] = MarkerPlaceGroup(
|
||||
bookmarkLocationDao
|
||||
.findBookmarkLocation(updatedGroups[index].place),
|
||||
.findBookmarkLocation(updatedGroups[index].place.name),
|
||||
updatedGroups[index].place
|
||||
)
|
||||
}
|
||||
|
|
@ -565,7 +575,7 @@ class NearbyParentFragmentPresenter
|
|||
).sortedBy { it.getDistanceInDouble(mapFocus) }.take(NearbyController.MAX_RESULTS)
|
||||
.map {
|
||||
MarkerPlaceGroup(
|
||||
bookmarkLocationDao.findBookmarkLocation(it), it
|
||||
bookmarkLocationDao.findBookmarkLocation(it.name), it
|
||||
)
|
||||
}
|
||||
ensureActive()
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
* 1917 Ekim Devrimi
|
||||
* Envlh
|
||||
* Gambollar
|
||||
* GolyatGeri
|
||||
* Gorizon
|
||||
* Gırd
|
||||
* Marmase
|
||||
|
|
@ -199,7 +200,7 @@
|
|||
<string name="navigation_item_review">Çım berze cı</string>
|
||||
<string name="no_description_found">İzahat nêvineya</string>
|
||||
<string name="nearby_info_menu_commons_article">Pela dosyay commonsi</string>
|
||||
<string name="nearby_info_menu_wikidata_article">Pbcey Wikidata</string>
|
||||
<string name="nearby_info_menu_wikidata_article">Pbcey Wikidayıt</string>
|
||||
<string name="nearby_info_menu_wikipedia_article">Meqaley Wikipedia</string>
|
||||
<string name="upload_problem_exist">Muhtemel problemê nê resımi</string>
|
||||
<string name="upload_problem_image_dark">Resım zehf tariyo.</string>
|
||||
|
|
@ -216,7 +217,7 @@
|
|||
<string name="skip_login">Ravêre</string>
|
||||
<string name="navigation_item_login">Cı kewe</string>
|
||||
<string name="nearby_directions">Telimati</string>
|
||||
<string name="nearby_wikidata">Wikidata</string>
|
||||
<string name="nearby_wikidata">Wikidayıt</string>
|
||||
<string name="nearby_wikipedia">Wikipediya</string>
|
||||
<string name="nearby_commons">Commons</string>
|
||||
<string name="about_rate_us">Rey bıdê</string>
|
||||
|
|
@ -246,7 +247,7 @@
|
|||
<string name="explore_tab_title_featured">Weçinaye</string>
|
||||
<string name="explore_tab_title_mobile">Raya mobiliya biyo bar</string>
|
||||
<string name="explore_tab_title_map">Xerita</string>
|
||||
<string name="successful_wikidata_edit">Resım , Wikidata dê biyo obcey %1$s miyan!</string>
|
||||
<string name="successful_wikidata_edit">Resım , Wikidayıt dê biyo obcey %1$s miyan!</string>
|
||||
<string name="menu_set_wallpaper">Wallpaper eyar kerê</string>
|
||||
<string name="wallpaper_set_successfully">Wallpaper eyar biyo!</string>
|
||||
<string name="quiz">Quiz</string>
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@
|
|||
<string name="menu_settings">امستنې</string>
|
||||
<string name="intent_share_upload_label">خونديځ ته راپورته کول</string>
|
||||
<string name="upload_in_progress">راپورته کول جريان لري</string>
|
||||
<string name="username">کارننوم</string>
|
||||
<string name="username">کارننوم</string>
|
||||
<string name="password">پټنوم</string>
|
||||
<string name="login_credential">خپل خونديځ بېټا ګڼون ته ورننوځئ</string>
|
||||
<string name="login">ننوتل</string>
|
||||
|
|
|
|||
|
|
@ -876,6 +876,7 @@
|
|||
<string name="account">Учётная запись</string>
|
||||
<string name="vanish_account">Удалить учётную запись</string>
|
||||
<string name="account_vanish_request_confirm_title">Предупреждение об удалении учётной записи</string>
|
||||
<string name="account_vanish_request_confirm">Удаление — это <b>крайняя мера</b>, и её следует <b>использовать только в том случае, если вы хотите навсегда прекратить редактирование</b>, а также скрыть как можно больше связанных с вами действий.<br/><br/> Удаление вашей учётной записи на Викискладе осуществляется путём изменения её имени, чтобы другие не могли определить ваши действия. <b>Удаление не гарантирует полной анонимности или удаления вклада в проектах</b>.</string>
|
||||
<string name="caption">Подпись</string>
|
||||
<string name="caption_copied_to_clipboard">Подпись скопирована в буфер обмена</string>
|
||||
<string name="congratulations_all_pictures_in_this_album_have_been_either_uploaded_or_marked_as_not_for_upload">Поздравляем, все фотографии в этом альбоме либо загружены, либо помечены как не предназначенные для загрузки.</string>
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ import android.database.MatrixCursor
|
|||
import android.database.sqlite.SQLiteDatabase
|
||||
import android.net.Uri
|
||||
import android.os.RemoteException
|
||||
import androidx.room.Room
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import com.nhaarman.mockitokotlin2.any
|
||||
import com.nhaarman.mockitokotlin2.anyOrNull
|
||||
import com.nhaarman.mockitokotlin2.argumentCaptor
|
||||
|
|
@ -18,36 +20,20 @@ import com.nhaarman.mockitokotlin2.mock
|
|||
import com.nhaarman.mockitokotlin2.verify
|
||||
import com.nhaarman.mockitokotlin2.whenever
|
||||
import fr.free.nrw.commons.TestCommonsApplication
|
||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsContentProvider.BASE_URI
|
||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_CATEGORY
|
||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_COMMONS_LINK
|
||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_DESCRIPTION
|
||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_EXISTS
|
||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_IMAGE_URL
|
||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_LABEL_ICON
|
||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_LABEL_TEXT
|
||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_LANGUAGE
|
||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_LAT
|
||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_LONG
|
||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_NAME
|
||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_PIC
|
||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_WIKIDATA_LINK
|
||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_WIKIPEDIA_LINK
|
||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.CREATE_TABLE_STATEMENT
|
||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.DROP_TABLE_STATEMENT
|
||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.onCreate
|
||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.onDelete
|
||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.onUpdate
|
||||
import fr.free.nrw.commons.db.AppDatabase
|
||||
import fr.free.nrw.commons.location.LatLng
|
||||
import fr.free.nrw.commons.nearby.Label
|
||||
import fr.free.nrw.commons.nearby.Place
|
||||
import fr.free.nrw.commons.nearby.Sitelinks
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.After
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.verifyNoInteractions
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
|
|
@ -55,28 +41,11 @@ import org.robolectric.annotation.Config
|
|||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(sdk = [21], application = TestCommonsApplication::class)
|
||||
class BookMarkLocationDaoTest {
|
||||
private val columns =
|
||||
arrayOf(
|
||||
COLUMN_NAME,
|
||||
COLUMN_LANGUAGE,
|
||||
COLUMN_DESCRIPTION,
|
||||
COLUMN_CATEGORY,
|
||||
COLUMN_LABEL_TEXT,
|
||||
COLUMN_LABEL_ICON,
|
||||
COLUMN_IMAGE_URL,
|
||||
COLUMN_WIKIPEDIA_LINK,
|
||||
COLUMN_WIKIDATA_LINK,
|
||||
COLUMN_COMMONS_LINK,
|
||||
COLUMN_LAT,
|
||||
COLUMN_LONG,
|
||||
COLUMN_PIC,
|
||||
COLUMN_EXISTS,
|
||||
)
|
||||
private val client: ContentProviderClient = mock()
|
||||
private val database: SQLiteDatabase = mock()
|
||||
private val captor = argumentCaptor<ContentValues>()
|
||||
|
||||
private lateinit var testObject: BookmarkLocationsDao
|
||||
private lateinit var bookmarkLocationsDao: BookmarkLocationsDao
|
||||
|
||||
private lateinit var database: AppDatabase
|
||||
|
||||
private lateinit var examplePlaceBookmark: Place
|
||||
private lateinit var exampleLabel: Label
|
||||
private lateinit var exampleUri: Uri
|
||||
|
|
@ -89,10 +58,18 @@ class BookMarkLocationDaoTest {
|
|||
exampleUri = Uri.parse("wikimedia/uri")
|
||||
exampleLocation = LatLng(40.0, 51.4, 1f)
|
||||
|
||||
builder = Sitelinks.Builder()
|
||||
builder.setWikipediaLink("wikipediaLink")
|
||||
builder.setWikidataLink("wikidataLink")
|
||||
builder.setCommonsLink("commonsLink")
|
||||
database = Room.inMemoryDatabaseBuilder(
|
||||
ApplicationProvider.getApplicationContext(),
|
||||
AppDatabase::class.java
|
||||
).allowMainThreadQueries().build()
|
||||
|
||||
bookmarkLocationsDao = database.bookmarkLocationsDao()
|
||||
|
||||
builder = Sitelinks.Builder().apply {
|
||||
setWikipediaLink("wikipediaLink")
|
||||
setWikidataLink("wikidataLink")
|
||||
setCommonsLink("commonsLink")
|
||||
}
|
||||
|
||||
examplePlaceBookmark =
|
||||
Place(
|
||||
|
|
@ -106,236 +83,75 @@ class BookMarkLocationDaoTest {
|
|||
"picName",
|
||||
false,
|
||||
)
|
||||
testObject = BookmarkLocationsDao { client }
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
database.close()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun createTable() {
|
||||
onCreate(database)
|
||||
verify(database).execSQL(CREATE_TABLE_STATEMENT)
|
||||
fun testForAddAndGetAllBookmarkLocations() = runBlocking {
|
||||
bookmarkLocationsDao.addBookmarkLocation(examplePlaceBookmark.toBookmarksLocations())
|
||||
|
||||
val bookmarks = bookmarkLocationsDao.getAllBookmarksLocations()
|
||||
|
||||
assertEquals(1, bookmarks.size)
|
||||
val retrievedBookmark = bookmarks.first()
|
||||
assertEquals(examplePlaceBookmark.name, retrievedBookmark.locationName)
|
||||
assertEquals(examplePlaceBookmark.language, retrievedBookmark.locationLanguage)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun deleteTable() {
|
||||
onDelete(database)
|
||||
inOrder(database) {
|
||||
verify(database).execSQL(DROP_TABLE_STATEMENT)
|
||||
verify(database).execSQL(CREATE_TABLE_STATEMENT)
|
||||
}
|
||||
fun testFindBookmarkByNameForTrue() = runBlocking {
|
||||
bookmarkLocationsDao.addBookmarkLocation(examplePlaceBookmark.toBookmarksLocations())
|
||||
|
||||
val exists = bookmarkLocationsDao.findBookmarkLocation(examplePlaceBookmark.name)
|
||||
assertTrue(exists)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun createFromCursor() {
|
||||
createCursor(1).let { cursor ->
|
||||
cursor.moveToFirst()
|
||||
testObject.fromCursor(cursor).let {
|
||||
assertEquals("en", it.language)
|
||||
assertEquals("placeName", it.name)
|
||||
assertEquals(Label.FOREST, it.label)
|
||||
assertEquals("placeDescription", it.longDescription)
|
||||
assertEquals(40.0, it.location.latitude, 0.001)
|
||||
assertEquals(51.4, it.location.longitude, 0.001)
|
||||
assertEquals("placeCategory", it.category)
|
||||
assertEquals(builder.build().wikipediaLink, it.siteLinks.wikipediaLink)
|
||||
assertEquals(builder.build().wikidataLink, it.siteLinks.wikidataLink)
|
||||
assertEquals(builder.build().commonsLink, it.siteLinks.commonsLink)
|
||||
assertEquals("picName", it.pic)
|
||||
assertEquals(false, it.exists)
|
||||
}
|
||||
}
|
||||
fun testFindBookmarkByNameForFalse() = runBlocking {
|
||||
bookmarkLocationsDao.addBookmarkLocation(examplePlaceBookmark.toBookmarksLocations())
|
||||
|
||||
val exists = bookmarkLocationsDao.findBookmarkLocation("xyz")
|
||||
assertFalse(exists)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getAllLocationBookmarks() {
|
||||
whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull())).thenReturn(createCursor(14))
|
||||
fun testDeleteBookmark() = runBlocking {
|
||||
val bookmarkLocation = examplePlaceBookmark.toBookmarksLocations()
|
||||
bookmarkLocationsDao.addBookmarkLocation(bookmarkLocation)
|
||||
|
||||
var result = testObject.allBookmarksLocations
|
||||
bookmarkLocationsDao.deleteBookmarkLocation(bookmarkLocation)
|
||||
|
||||
assertEquals(14, result.size)
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException::class)
|
||||
fun getAllLocationBookmarksTranslatesExceptions() {
|
||||
whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull())).thenThrow(RemoteException(""))
|
||||
testObject.allBookmarksLocations
|
||||
val bookmarks = bookmarkLocationsDao.getAllBookmarksLocations()
|
||||
assertTrue(bookmarks.isEmpty())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getAllLocationBookmarksReturnsEmptyList_emptyCursor() {
|
||||
whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull())).thenReturn(createCursor(0))
|
||||
assertTrue(testObject.allBookmarksLocations.isEmpty())
|
||||
fun testUpdateBookmarkForTrue() = runBlocking {
|
||||
val exists = bookmarkLocationsDao.updateBookmarkLocation(examplePlaceBookmark)
|
||||
|
||||
assertTrue(exists)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getAllLocationBookmarksReturnsEmptyList_nullCursor() {
|
||||
whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull())).thenReturn(null)
|
||||
assertTrue(testObject.allBookmarksLocations.isEmpty())
|
||||
fun testUpdateBookmarkForFalse() = runBlocking {
|
||||
val newBookmark = examplePlaceBookmark.toBookmarksLocations()
|
||||
bookmarkLocationsDao.addBookmarkLocation(newBookmark)
|
||||
|
||||
val exists = bookmarkLocationsDao.updateBookmarkLocation(examplePlaceBookmark)
|
||||
assertFalse(exists)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun cursorsAreClosedAfterGetAllLocationBookmarksQuery() {
|
||||
val mockCursor: Cursor = mock()
|
||||
whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull())).thenReturn(mockCursor)
|
||||
whenever(mockCursor.moveToFirst()).thenReturn(false)
|
||||
fun testGetAllBookmarksLocationsPlace() = runBlocking {
|
||||
val bookmarkLocation = examplePlaceBookmark.toBookmarksLocations()
|
||||
bookmarkLocationsDao.addBookmarkLocation(bookmarkLocation)
|
||||
|
||||
testObject.allBookmarksLocations
|
||||
|
||||
verify(mockCursor).close()
|
||||
val bookmarks = bookmarkLocationsDao.getAllBookmarksLocationsPlace()
|
||||
assertEquals(1, bookmarks.size)
|
||||
assertEquals(examplePlaceBookmark.name, bookmarks.first().name)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun updateNewLocationBookmark() {
|
||||
whenever(client.insert(any(), any())).thenReturn(Uri.EMPTY)
|
||||
whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(null)
|
||||
|
||||
assertTrue(testObject.updateBookmarkLocation(examplePlaceBookmark))
|
||||
verify(client).insert(eq(BASE_URI), captor.capture())
|
||||
captor.firstValue.let { cv ->
|
||||
assertEquals(13, cv.size())
|
||||
assertEquals(examplePlaceBookmark.name, cv.getAsString(COLUMN_NAME))
|
||||
assertEquals(examplePlaceBookmark.language, cv.getAsString(COLUMN_LANGUAGE))
|
||||
assertEquals(examplePlaceBookmark.longDescription, cv.getAsString(COLUMN_DESCRIPTION))
|
||||
assertEquals(examplePlaceBookmark.label.text, cv.getAsString(COLUMN_LABEL_TEXT))
|
||||
assertEquals(examplePlaceBookmark.category, cv.getAsString(COLUMN_CATEGORY))
|
||||
assertEquals(examplePlaceBookmark.location.latitude, cv.getAsDouble(COLUMN_LAT), 0.001)
|
||||
assertEquals(examplePlaceBookmark.location.longitude, cv.getAsDouble(COLUMN_LONG), 0.001)
|
||||
assertEquals(examplePlaceBookmark.siteLinks.wikipediaLink.toString(), cv.getAsString(COLUMN_WIKIPEDIA_LINK))
|
||||
assertEquals(examplePlaceBookmark.siteLinks.wikidataLink.toString(), cv.getAsString(COLUMN_WIKIDATA_LINK))
|
||||
assertEquals(examplePlaceBookmark.siteLinks.commonsLink.toString(), cv.getAsString(COLUMN_COMMONS_LINK))
|
||||
assertEquals(examplePlaceBookmark.pic, cv.getAsString(COLUMN_PIC))
|
||||
assertEquals(examplePlaceBookmark.exists.toString(), cv.getAsString(COLUMN_EXISTS))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun updateExistingLocationBookmark() {
|
||||
whenever(client.delete(isA(), isNull(), isNull())).thenReturn(1)
|
||||
whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(createCursor(1))
|
||||
|
||||
assertFalse(testObject.updateBookmarkLocation(examplePlaceBookmark))
|
||||
verify(client).delete(eq(BookmarkLocationsContentProvider.uriForName(examplePlaceBookmark.name)), isNull(), isNull())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun findExistingLocationBookmark() {
|
||||
whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(createCursor(1))
|
||||
assertTrue(testObject.findBookmarkLocation(examplePlaceBookmark))
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException::class)
|
||||
fun findLocationBookmarkTranslatesExceptions() {
|
||||
whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull())).thenThrow(RemoteException(""))
|
||||
testObject.findBookmarkLocation(examplePlaceBookmark)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun findNotExistingLocationBookmarkReturnsNull_emptyCursor() {
|
||||
whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(createCursor(0))
|
||||
assertFalse(testObject.findBookmarkLocation(examplePlaceBookmark))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun findNotExistingLocationBookmarkReturnsNull_nullCursor() {
|
||||
whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(null)
|
||||
assertFalse(testObject.findBookmarkLocation(examplePlaceBookmark))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun cursorsAreClosedAfterFindLocationBookmarkQuery() {
|
||||
val mockCursor: Cursor = mock()
|
||||
whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull())).thenReturn(mockCursor)
|
||||
whenever(mockCursor.moveToFirst()).thenReturn(false)
|
||||
|
||||
testObject.findBookmarkLocation(examplePlaceBookmark)
|
||||
|
||||
verify(mockCursor).close()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrateTableVersionFrom_v1_to_v2() {
|
||||
onUpdate(database, 1, 2)
|
||||
// Table didn't exist before v5
|
||||
verifyNoInteractions(database)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrateTableVersionFrom_v2_to_v3() {
|
||||
onUpdate(database, 2, 3)
|
||||
// Table didn't exist before v5
|
||||
verifyNoInteractions(database)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrateTableVersionFrom_v3_to_v4() {
|
||||
onUpdate(database, 3, 4)
|
||||
// Table didnt exist before v5
|
||||
verifyNoInteractions(database)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrateTableVersionFrom_v4_to_v5() {
|
||||
onUpdate(database, 4, 5)
|
||||
// Table didnt change in version 5
|
||||
verifyNoInteractions(database)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrateTableVersionFrom_v5_to_v6() {
|
||||
onUpdate(database, 5, 6)
|
||||
// Table didnt change in version 6
|
||||
verifyNoInteractions(database)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrateTableVersionFrom_v6_to_v7() {
|
||||
onUpdate(database, 6, 7)
|
||||
// Table didnt change in version 7
|
||||
verifyNoInteractions(database)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrateTableVersionFrom_v7_to_v8() {
|
||||
onUpdate(database, 7, 8)
|
||||
verify(database).execSQL(CREATE_TABLE_STATEMENT)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrateTableVersionFrom_v12_to_v13() {
|
||||
onUpdate(database, 12, 13)
|
||||
verify(database).execSQL("ALTER TABLE bookmarksLocations ADD COLUMN location_destroyed STRING;")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrateTableVersionFrom_v13_to_v14() {
|
||||
onUpdate(database, 13, 14)
|
||||
verify(database).execSQL("ALTER TABLE bookmarksLocations ADD COLUMN location_language STRING;")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrateTableVersionFrom_v14_to_v15() {
|
||||
onUpdate(database, 14, 15)
|
||||
verify(database).execSQL("ALTER TABLE bookmarksLocations ADD COLUMN location_exists STRING;")
|
||||
}
|
||||
|
||||
private fun createCursor(rows: Int): Cursor =
|
||||
MatrixCursor(columns, rows).apply {
|
||||
repeat(rows) {
|
||||
newRow().apply {
|
||||
add("placeName")
|
||||
add("en")
|
||||
add("placeDescription")
|
||||
add("placeCategory")
|
||||
add(Label.FOREST.text)
|
||||
add(Label.FOREST.icon)
|
||||
add("placeImage")
|
||||
add("wikipediaLink")
|
||||
add("wikidataLink")
|
||||
add("commonsLink")
|
||||
add(40.0)
|
||||
add(51.4)
|
||||
add("picName")
|
||||
add(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package fr.free.nrw.commons.bookmarks.locations
|
|||
|
||||
import com.nhaarman.mockitokotlin2.whenever
|
||||
import fr.free.nrw.commons.nearby.Place
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Assert
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
|
@ -19,9 +20,11 @@ class BookmarkLocationControllerTest {
|
|||
|
||||
@Before
|
||||
fun setup() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
whenever(bookmarkDao!!.allBookmarksLocations)
|
||||
.thenReturn(mockBookmarkList)
|
||||
MockitoAnnotations.openMocks(this)
|
||||
runBlocking {
|
||||
whenever(bookmarkDao!!.getAllBookmarksLocationsPlace())
|
||||
.thenReturn(mockBookmarkList)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -66,7 +69,7 @@ class BookmarkLocationControllerTest {
|
|||
* Test case where all bookmark locations are fetched and media is found against it
|
||||
*/
|
||||
@Test
|
||||
fun loadBookmarkedLocations() {
|
||||
fun loadBookmarkedLocations() = runBlocking {
|
||||
val bookmarkedLocations =
|
||||
bookmarkLocationsController.loadFavoritesLocations()
|
||||
Assert.assertEquals(2, bookmarkedLocations.size.toLong())
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import androidx.fragment.app.FragmentManager
|
|||
import androidx.fragment.app.FragmentTransaction
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import com.nhaarman.mockitokotlin2.verify
|
||||
import com.nhaarman.mockitokotlin2.whenever
|
||||
import fr.free.nrw.commons.OkHttpConnectionFactory
|
||||
import fr.free.nrw.commons.R
|
||||
|
|
@ -22,11 +23,14 @@ import fr.free.nrw.commons.nearby.Place
|
|||
import fr.free.nrw.commons.nearby.fragments.CommonPlaceClickActions
|
||||
import fr.free.nrw.commons.nearby.fragments.PlaceAdapter
|
||||
import fr.free.nrw.commons.profile.ProfileActivity
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Assert
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.spy
|
||||
import org.mockito.MockitoAnnotations
|
||||
import org.powermock.reflect.Whitebox
|
||||
import org.robolectric.Robolectric
|
||||
|
|
@ -129,11 +133,13 @@ class BookmarkLocationFragmentUnitTests {
|
|||
*/
|
||||
@Test
|
||||
fun testInitNonEmpty() {
|
||||
whenever(controller.loadFavoritesLocations()).thenReturn(mockBookmarkList)
|
||||
val method: Method =
|
||||
BookmarkLocationsFragment::class.java.getDeclaredMethod("initList")
|
||||
method.isAccessible = true
|
||||
method.invoke(fragment)
|
||||
runBlocking {
|
||||
whenever(controller.loadFavoritesLocations()).thenReturn(mockBookmarkList)
|
||||
val method: Method =
|
||||
BookmarkLocationsFragment::class.java.getDeclaredMethod("initList")
|
||||
method.isAccessible = true
|
||||
method.invoke(fragment)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -168,7 +174,11 @@ class BookmarkLocationFragmentUnitTests {
|
|||
*/
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun testOnResume() {
|
||||
fragment.onResume()
|
||||
fun testOnResume() = runBlocking {
|
||||
val fragmentSpy = spy(fragment)
|
||||
whenever(controller.loadFavoritesLocations()).thenReturn(mockBookmarkList)
|
||||
|
||||
fragmentSpy.onResume()
|
||||
verify(fragmentSpy).initList()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import fr.free.nrw.commons.location.LatLng
|
|||
import fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType
|
||||
import fr.free.nrw.commons.nearby.contract.NearbyParentFragmentContract
|
||||
import fr.free.nrw.commons.nearby.presenter.NearbyParentFragmentPresenter
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
|
|
@ -463,7 +464,9 @@ class NearbyParentFragmentPresenterTest {
|
|||
nearbyPlacesInfo.searchLatLng = latestLocation
|
||||
nearbyPlacesInfo.placeList = emptyList<Place>()
|
||||
|
||||
whenever(bookmarkLocationsDao.allBookmarksLocations).thenReturn(Collections.emptyList())
|
||||
runBlocking {
|
||||
whenever(bookmarkLocationsDao.getAllBookmarksLocations()).thenReturn(Collections.emptyList())
|
||||
}
|
||||
nearbyPresenter.updateMapMarkers(nearbyPlacesInfo.placeList, latestLocation, null)
|
||||
Mockito.verify(nearbyParentFragmentView).setProgressBarVisibility(false)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue