mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-29 05:43:55 +01:00
Migrated bookmarks locations to Kotlin and adapt room database (#6148)
* Rename .java to .kt
* Refactor: Migrate bookmark location logic to Kotlin
This commit migrates the bookmark location logic to Kotlin, enhancing code maintainability and readability.
- Removes the `BookmarkLocationsContentProvider`, `BookmarkLocationsController`, and `BookmarkLocationsDao` Java classes.
- Creates `BookmarkLocationsDao.kt` and `BookmarkLocationsContentProvider.kt` in Kotlin.
- Migrates the logic from `BookmarkLocationsFragment.java` to `BookmarkLocationsFragment.kt`.
- Updates test files to reflect these changes.
- Addresses associated code review comments.
* Refactor: Migrate to Room Database for Bookmark Locations
This commit migrates the bookmark locations functionality from a custom content provider to Room database.
Key changes:
* **Removal of `BookmarkLocationsContentProvider`:** This class, which previously handled data storage, has been removed.
* **Introduction of `BookmarksLocations`:** This data class now represents a bookmarked location, serving as the Room entity.
* **Creation of `BookmarkLocationsDao`:** This Room DAO handles database interactions for bookmark locations, including:
* Adding, deleting, and querying bookmarked locations.
* Checking if a location is already bookmarked.
* Updating the bookmark status of a location.
* Retrieving all bookmarked locations as `Place` objects.
* **`BookmarkLocationsViewModel`:** Added to manage the data layer for bookmark locations
* **`NearbyUtil`:** Created a Util class for Nearby to manage the bookmark locations.
* **Updates in `PlaceAdapter` and `PlaceAdapterDelegate`:** These classes have been modified to work with the new Room-based data layer.
* **Updates in `AppDatabase`:** The database now includes `BookmarksLocations` as an entity and exposes the `bookmarkLocationsDao`.
* **Updates in `FragmentBuilderModule` and `CommonsApplicationModule`**: for DI
* **Removal of `DBOpenHelper` upgrade for locations**: as it is no longer needed
* **Updates in `NearbyParentFragmentPresenter`**: refactored the logic to use the dao functions
* **Updates in `NearbyParentFragment`**: refactored the logic to use the util and dao functions
* **Update in `BookmarkLocationsController`**: removed as its no longer needed
* **Add `toPlace` and `toBookmarksLocations`**: extension functions to map between data class and entities
* **Update in `CommonsApplication`**: to remove old db table.
* Refactor: Improve bookmark location handling and update database version
This commit includes the following changes:
- Updates the database version to 20.
- Refactors bookmark location handling within `NearbyParentFragment` to improve logic and efficiency.
- Introduces `getBookmarkLocationExists` in `NearbyUtil` to directly update bookmark icons in the bottom sheet adapter.
- Removes unused provider.
- Adjusts `BookmarkLocationsFragment`'s `PlaceAdapter` to use `lifecycleScope` for better coroutine management.
- Refactors `updateBookmarkLocation` in `NearbyParentFragmentPresenter`.
* Toggle bookmark icon in BottomSheetAdapter instead of finding the location each time in the bookmark
* Update bookmark button image in `BottomSheetAdapter`
* Add new toggle function to `BottomSheetAdapter`
* Call the toggle function in `NearbyParentFragment`
* Refactor: Load bookmarked locations using Flow
* `BookmarkLocationsController`: Changed to use `Flow` to load bookmarked locations.
* `BookmarkLocationsDao`: Changed to return `Flow` of bookmark location instead of a list.
* `BookmarkLocationsFragment`: Used `LifecycleScope` to collect data from flow and display it.
* Removed unused `getAllBookmarkLocations()` from `BookmarkLocationsViewModel`.
* Used `map` in `BookmarkLocationsDao` to convert from `BookmarksLocations` to `Place` list.
* Loading locations data in fragment
* BookmarkLocationsController: Changed `loadFavoritesLocations` to be a suspend function.
* BookmarkLocationsFragment: Updated the `initList` function to call the controller's suspend function.
* BookmarkLocationsDao: Changed `getAllBookmarksLocations` and `getAllBookmarksLocationsPlace` to be suspend functions.
* Refactor BookmarkLocationControllerTest and related files to use coroutines
* Migrated `bookmarkDao!!.getAllBookmarksLocations()` to `bookmarkDao!!.getAllBookmarksLocationsPlace()` and added `runBlocking`
* Added `runBlocking` for `loadBookmarkedLocations()` and `testInitNonEmpty()`
* Added `runBlocking` for `getAllBookmarksLocations()` and update `updateMapMarkers`
These changes improve the test structure by ensuring the database functions are executed within a coroutine context.
* Refactor BookmarkLocationsFragment and add tests for BookmarkLocationsDao
* Moved `initList` to `BookmarkLocationsFragment` for better lifecycle handling.
* Added test case for `BookmarkLocationsFragment`'s onResume.
* Added test cases for `BookmarkLocationsDao` operations like adding, retrieving, finding, deleting and updating bookmarks.
* Refactor BookmarkLocationsFragment to load favorites only when view is not null
* BookmarkLocationsFragment: load favorites locations only when view is not null.
* BookmarkLocationsFragmentTest: added spy and verify to test onResume() call initList() method.
* Refactor database and add migration
* `AppDatabase`: Updated to use room migration.
* `CommonsApplicationModule`: added migration from version 19 to 20 to `appDatabase`
* Rename .java to .kt
* Refactor: Migrate bookmark location logic to Kotlin
This commit migrates the bookmark location logic to Kotlin, enhancing code maintainability and readability.
- Removes the `BookmarkLocationsContentProvider`, `BookmarkLocationsController`, and `BookmarkLocationsDao` Java classes.
- Creates `BookmarkLocationsDao.kt` and `BookmarkLocationsContentProvider.kt` in Kotlin.
- Migrates the logic from `BookmarkLocationsFragment.java` to `BookmarkLocationsFragment.kt`.
- Updates test files to reflect these changes.
- Addresses associated code review comments.
* Refactor: Migrate to Room Database for Bookmark Locations
This commit migrates the bookmark locations functionality from a custom content provider to Room database.
Key changes:
* **Removal of `BookmarkLocationsContentProvider`:** This class, which previously handled data storage, has been removed.
* **Introduction of `BookmarksLocations`:** This data class now represents a bookmarked location, serving as the Room entity.
* **Creation of `BookmarkLocationsDao`:** This Room DAO handles database interactions for bookmark locations, including:
* Adding, deleting, and querying bookmarked locations.
* Checking if a location is already bookmarked.
* Updating the bookmark status of a location.
* Retrieving all bookmarked locations as `Place` objects.
* **`BookmarkLocationsViewModel`:** Added to manage the data layer for bookmark locations
* **`NearbyUtil`:** Created a Util class for Nearby to manage the bookmark locations.
* **Updates in `PlaceAdapter` and `PlaceAdapterDelegate`:** These classes have been modified to work with the new Room-based data layer.
* **Updates in `AppDatabase`:** The database now includes `BookmarksLocations` as an entity and exposes the `bookmarkLocationsDao`.
* **Updates in `FragmentBuilderModule` and `CommonsApplicationModule`**: for DI
* **Removal of `DBOpenHelper` upgrade for locations**: as it is no longer needed
* **Updates in `NearbyParentFragmentPresenter`**: refactored the logic to use the dao functions
* **Updates in `NearbyParentFragment`**: refactored the logic to use the util and dao functions
* **Update in `BookmarkLocationsController`**: removed as its no longer needed
* **Add `toPlace` and `toBookmarksLocations`**: extension functions to map between data class and entities
* **Update in `CommonsApplication`**: to remove old db table.
* Refactor: Improve bookmark location handling and update database version
This commit includes the following changes:
- Updates the database version to 20.
- Refactors bookmark location handling within `NearbyParentFragment` to improve logic and efficiency.
- Introduces `getBookmarkLocationExists` in `NearbyUtil` to directly update bookmark icons in the bottom sheet adapter.
- Removes unused provider.
- Adjusts `BookmarkLocationsFragment`'s `PlaceAdapter` to use `lifecycleScope` for better coroutine management.
- Refactors `updateBookmarkLocation` in `NearbyParentFragmentPresenter`.
* Toggle bookmark icon in BottomSheetAdapter instead of finding the location each time in the bookmark
* Update bookmark button image in `BottomSheetAdapter`
* Add new toggle function to `BottomSheetAdapter`
* Call the toggle function in `NearbyParentFragment`
* Refactor: Load bookmarked locations using Flow
* `BookmarkLocationsController`: Changed to use `Flow` to load bookmarked locations.
* `BookmarkLocationsDao`: Changed to return `Flow` of bookmark location instead of a list.
* `BookmarkLocationsFragment`: Used `LifecycleScope` to collect data from flow and display it.
* Removed unused `getAllBookmarkLocations()` from `BookmarkLocationsViewModel`.
* Used `map` in `BookmarkLocationsDao` to convert from `BookmarksLocations` to `Place` list.
* Loading locations data in fragment
* BookmarkLocationsController: Changed `loadFavoritesLocations` to be a suspend function.
* BookmarkLocationsFragment: Updated the `initList` function to call the controller's suspend function.
* BookmarkLocationsDao: Changed `getAllBookmarksLocations` and `getAllBookmarksLocationsPlace` to be suspend functions.
* Refactor BookmarkLocationControllerTest and related files to use coroutines
* Migrated `bookmarkDao!!.getAllBookmarksLocations()` to `bookmarkDao!!.getAllBookmarksLocationsPlace()` and added `runBlocking`
* Added `runBlocking` for `loadBookmarkedLocations()` and `testInitNonEmpty()`
* Added `runBlocking` for `getAllBookmarksLocations()` and update `updateMapMarkers`
These changes improve the test structure by ensuring the database functions are executed within a coroutine context.
* Refactor BookmarkLocationsFragment and add tests for BookmarkLocationsDao
* Moved `initList` to `BookmarkLocationsFragment` for better lifecycle handling.
* Added test case for `BookmarkLocationsFragment`'s onResume.
* Added test cases for `BookmarkLocationsDao` operations like adding, retrieving, finding, deleting and updating bookmarks.
* Refactor BookmarkLocationsFragment to load favorites only when view is not null
* BookmarkLocationsFragment: load favorites locations only when view is not null.
* BookmarkLocationsFragmentTest: added spy and verify to test onResume() call initList() method.
* Refactor database and add migration
* `AppDatabase`: Updated to use room migration.
* `CommonsApplicationModule`: added migration from version 19 to 20 to `appDatabase`
* Resolve conflicts and attach the `commons.db` with `common_room.db` during the migration to persist the data
* Refactor database migration to handle null values and use direct insertion
* Modify the database migration from version 19 to 20 to properly handle null values and use direct data insertion.
* Create a new table `bookmarks_locations` with `NOT NULL` constraints.
* Directly insert data into the new table from old database, safely handling `NULL` values by using `DEFAULT` empty string value.
* Close old database cursor and the database connection.
* Drop the old `bookmarksLocations` table.
* Refactor database schema to delete `bookmarksLocations` table and migrate data
* Delete `bookmarksLocations` table from the database during schema upgrade
* Migrate data from `bookmarksLocations` to `bookmarks_locations` in new schema
* Add `INSERT OR REPLACE` to prevent duplication during migration
* Delete `CONTRIBUTIONS_TABLE` and `BOOKMARKS_LOCATIONS` in the application start-up to have a fresh DB for first start-up after update
* Update sqlite-based database version to 22.
* Update sqlite-based database version to 22.
* Refactor CommonsApplicationModule to utilize application context
* Initialize and use application context directly
* Utilize lateinit for application context
* Added line breaks for improved readability.
---------
Co-authored-by: Nicolas Raoul <nicolas.raoul@gmail.com>
This commit is contained in:
parent
1c4797d3aa
commit
1c7dce9e12
26 changed files with 702 additions and 946 deletions
|
|
@ -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
|
||||
)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue