Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 0 additions & 30 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -213,36 +213,6 @@
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
</provider>
<provider
android:name=".category.CategoryContentProvider"
android:authorities="${applicationId}.categories.contentprovider"
android:exported="false"
android:label="@string/provider_categories"
android:syncable="false" />
<provider
android:name=".explore.recentsearches.RecentSearchesContentProvider"
android:authorities="${applicationId}.explore.recentsearches.contentprovider"
android:exported="false"
android:label="@string/provider_searches"
android:syncable="false" />
<provider
android:name=".recentlanguages.RecentLanguagesContentProvider"
android:authorities="${applicationId}.recentlanguages.contentprovider"
android:exported="false"
android:label="@string/provider_recent_languages"
android:syncable="false" />
<provider
android:name=".bookmarks.pictures.BookmarkPicturesContentProvider"
android:authorities="${applicationId}.bookmarks.contentprovider"
android:exported="false"
android:label="@string/provider_bookmarks"
android:syncable="false" />
<provider
android:name=".bookmarks.items.BookmarkItemsContentProvider"
android:authorities="${applicationId}.bookmarks.items.contentprovider"
android:exported="false"
android:label="@string/provider_bookmarks_location"
android:syncable="false" />

<receiver
android:name=".widget.PicOfDayAppWidget"
Expand Down
13 changes: 5 additions & 8 deletions app/src/main/java/fr/free/nrw/commons/CommonsApplication.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,11 @@ import com.facebook.drawee.backends.pipeline.Fresco
import com.facebook.imagepipeline.core.ImagePipelineConfig
import fr.free.nrw.commons.auth.LoginActivity
import fr.free.nrw.commons.auth.SessionManager
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsTable
import fr.free.nrw.commons.bookmarks.pictures.BookmarksTable
import fr.free.nrw.commons.category.CategoryDao
import fr.free.nrw.commons.category.CategoryTable
import fr.free.nrw.commons.concurrency.BackgroundPoolExceptionHandler
import fr.free.nrw.commons.concurrency.ThreadPoolService
import fr.free.nrw.commons.contributions.ContributionDao
import fr.free.nrw.commons.data.DBOpenHelper
import fr.free.nrw.commons.db.AppDatabase
import fr.free.nrw.commons.di.ApplicationlessInjection
import fr.free.nrw.commons.kvstore.JsonKvStore
import fr.free.nrw.commons.language.AppLanguageLookUpTable
Expand Down Expand Up @@ -72,6 +69,8 @@ class CommonsApplication : MultiDexApplication() {
@Inject
lateinit var sessionManager: SessionManager

@Inject
lateinit var appDatabase: AppDatabase
@Inject
lateinit var dbOpenHelper: DBOpenHelper

Expand Down Expand Up @@ -241,7 +240,6 @@ class CommonsApplication : MultiDexApplication() {
dbOpenHelper.readableDatabase.close()
val db = dbOpenHelper.writableDatabase

CategoryTable.onDelete(db)
dbOpenHelper.deleteTable(
db,
DBOpenHelper.CONTRIBUTIONS_TABLE
Expand All @@ -254,11 +252,10 @@ class CommonsApplication : MultiDexApplication() {

try {
contributionDao.deleteAll()
} catch (e: SQLiteException) {
appDatabase.clearAllTables()
} catch (e: Exception) {
Timber.e(e)
}
BookmarksTable.onDelete(db)
BookmarkItemsTable.onDelete(db)
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,39 @@ import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map

/**
* Bookmark categories dao
*
* @constructor Create empty Bookmark categories dao
*/
@Dao
interface BookmarkCategoriesDao {
abstract class BookmarkCategoriesDao {

/**
* Insert or Delete category bookmark into DB
*
* @param bookmarksCategoryModal
*/
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(bookmarksCategoryModal: BookmarksCategoryModal)
protected abstract suspend fun insertInternal(bookmarkCategoryRoomEntity: BookmarkCategoryRoomEntity)

suspend fun insert(bookmarksCategoryModal: BookmarksCategoryModal) {
insertInternal(toEntity(bookmarksCategoryModal))
}

/**
* Delete category bookmark from DB
*
* @param bookmarksCategoryModal
*/
@Delete
suspend fun delete(bookmarksCategoryModal: BookmarksCategoryModal)
protected abstract suspend fun deleteInternal(bookmarkCategoryRoomEntity: BookmarkCategoryRoomEntity)

suspend fun delete(bookmarksCategoryModal: BookmarksCategoryModal) {
deleteInternal(toEntity(bookmarksCategoryModal))
}

/**
* Checks if given category exist in DB
Expand All @@ -39,14 +47,22 @@ interface BookmarkCategoriesDao {
* @return
*/
@Query("SELECT EXISTS (SELECT 1 FROM bookmarks_categories WHERE categoryName = :categoryName)")
suspend fun doesExist(categoryName: String): Boolean
abstract suspend fun doesExist(categoryName: String): Boolean

/**
* Get all categories
*
* @return
*/
@Query("SELECT * FROM bookmarks_categories")
fun getAllCategories(): Flow<List<BookmarksCategoryModal>>
protected abstract fun getAllCategoriesInternal(): Flow<List<BookmarkCategoryRoomEntity>>

fun getAllCategories(): Flow<List<BookmarksCategoryModal>> =
getAllCategoriesInternal().map { entities -> entities.map { fromEntity(it) } }

private fun toEntity(model: BookmarksCategoryModal): BookmarkCategoryRoomEntity =
BookmarkCategoryRoomEntity(categoryName = model.categoryName)

private fun fromEntity(entity: BookmarkCategoryRoomEntity): BookmarksCategoryModal =
BookmarksCategoryModal(categoryName = entity.categoryName)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package fr.free.nrw.commons.bookmarks.category

import androidx.room.Entity
import androidx.room.PrimaryKey

/**
* Room entity for bookmarked category in DB
*/
@Entity(tableName = "bookmarks_categories")
data class BookmarkCategoryRoomEntity(
@PrimaryKey val categoryName: String
)
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
package fr.free.nrw.commons.bookmarks.category

import androidx.room.Entity
import androidx.room.PrimaryKey

/**
* Data class representing bookmarked category in DB
*
* @property categoryName
* @constructor Create empty Bookmarks category modal
*/
@Entity(tableName = "bookmarks_categories")
data class BookmarksCategoryModal(
@PrimaryKey val categoryName: String
val categoryName: String
)
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,14 @@ import javax.inject.Singleton
* Handles loading bookmarked items from Database
*/
@Singleton
class BookmarkItemsController @Inject constructor() {
@JvmField
@Inject
var bookmarkItemsDao: BookmarkItemsDao? = null

class BookmarkItemsController @Inject constructor(
val bookmarkItemsRoomDao: BookmarkItemsRoomDao
) {
/**
* Load from DB the bookmarked items
* @return a list of DepictedItem objects.
*/
fun loadFavoritesItems(): List<DepictedItem> {
return bookmarkItemsDao?.getAllBookmarksItems() ?: emptyList()
return bookmarkItemsRoomDao.getAllBookmarksItems().blockingGet()
}
Comment on lines 16 to 20
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

loadFavoritesItems() calls getAllBookmarksItems().blockingGet(), which can block the calling thread. Consider returning Single<List<DepictedItem>> (or making it suspend) so callers can execute DB work off the main thread without blocking.

Copilot uses AI. Check for mistakes.
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,84 @@ import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import fr.free.nrw.commons.category.CategoryItem
import fr.free.nrw.commons.upload.structure.depictions.DepictedItem
import fr.free.nrw.commons.utils.arrayToString
import fr.free.nrw.commons.utils.stringToArray
import io.reactivex.Completable
import io.reactivex.Single

@Dao
interface BookmarkItemsRoomDao {
abstract class BookmarkItemsRoomDao {

@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(depictedItem: BookmarkItemsRoomEntity)
abstract fun insert(depictedItem: BookmarkItemsRoomEntity): Completable

@Delete
fun delete(depictedItem: BookmarkItemsRoomEntity)
abstract fun delete(depictedItem: BookmarkItemsRoomEntity): Completable

@Query("SELECT * FROM bookmarksItems")
fun getAll(): Single<List<BookmarkItemsRoomEntity>>
abstract fun getAll(): Single<List<BookmarkItemsRoomEntity>>

@Query("SELECT EXISTS (SELECT 1 FROM bookmarksItems WHERE item_id = :itemId)")
fun findBookmarkItem(itemId: String?): Boolean
abstract fun findBookmarkItem(itemId: String?): Single<Boolean>

fun getAllBookmarksItems(): Single<List<DepictedItem>> {
return getAll().map { entities ->
entities.map { fromEntity(it) }
}
}

fun updateBookmarkItem(depictedItem: DepictedItem): Single<Boolean> {
return findBookmarkItem(depictedItem.id).flatMap { exists ->
if (exists) {
delete(toEntity(depictedItem)).andThen(Single.just(false))
} else {
insert(toEntity(depictedItem)).andThen(Single.just(true))
}
}
}

private fun fromEntity(entity: BookmarkItemsRoomEntity): DepictedItem {
return DepictedItem(
entity.name,
entity.description,
entity.imageUrl,
stringToArray(entity.instanceOfs),
convertToCategoryItems(
stringToArray(entity.categoryNames),
stringToArray(entity.categoryDescriptions),
stringToArray(entity.categoryThumbnails)
),
entity.isSelected,
entity.id
)
}

private fun toEntity(depictedItem: DepictedItem): BookmarkItemsRoomEntity {
return BookmarkItemsRoomEntity(
depictedItem.name,
depictedItem.description,
depictedItem.imageUrl,
arrayToString(depictedItem.instanceOfs) ?: "",
arrayToString(depictedItem.commonsCategories.map { it.name }) ?: "",
arrayToString(depictedItem.commonsCategories.map { it.description ?: "" }) ?: "",
arrayToString(depictedItem.commonsCategories.map { it.thumbnail ?: "" }) ?: "",
depictedItem.isSelected,
depictedItem.id
)
}

private fun convertToCategoryItems(
categoryNameList: List<String>,
categoryDescriptionList: List<String>,
categoryThumbnailList: List<String>
): List<CategoryItem> = categoryNameList.mapIndexed { index, name ->
CategoryItem(
name = name,
description = categoryDescriptionList.getOrNull(index),
thumbnail = categoryThumbnailList.getOrNull(index),
isSelected = false
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ abstract class BookmarkLocationsDao {
val exists = findBookmarkLocation(bookmarkLocation.name)

if (exists) {
deleteBookmarkLocation(bookmarkLocation.toBookmarksLocations())
deleteBookmarkLocation(toEntity(bookmarkLocation))
NearbyController.updateMarkerLabelListBookmark(bookmarkLocation, false)
} else {
addBookmarkLocation(bookmarkLocation.toBookmarksLocations())
addBookmarkLocation(toEntity(bookmarkLocation))
NearbyController.updateMarkerLabelListBookmark(bookmarkLocation, true)
}

Expand All @@ -60,6 +60,51 @@ abstract class BookmarkLocationsDao {
* Fetches all bookmark locations as `Place` objects.
*/
suspend fun getAllBookmarksLocationsPlace(): List<Place> {
return getAllBookmarksLocations().map { it.toPlace() }
return getAllBookmarksLocations().map { fromEntity(it) }
}

fun toEntity(place: Place): BookmarksLocations {
return BookmarksLocations(
locationName = place.name,
locationLanguage = place.language,
locationDescription = place.longDescription,
locationCategory = place.category,
locationLat = place.location.latitude,
locationLong = place.location.longitude,
locationLabelText = place.label?.text ?: "",
locationLabelIcon = place.label?.icon,
locationImageUrl = place.pic,
locationWikipediaLink = place.siteLinks.wikipediaLink.toString(),
locationWikidataLink = place.siteLinks.wikidataLink.toString(),
locationCommonsLink = place.siteLinks.commonsLink.toString(),
locationPic = place.pic,
locationExists = place.exists
)
}

private fun fromEntity(entity: BookmarksLocations): Place {
val location = fr.free.nrw.commons.location.LatLng(
entity.locationLat,
entity.locationLong,
1F
)

val builder = fr.free.nrw.commons.nearby.Sitelinks.Builder().apply {
setWikipediaLink(entity.locationWikipediaLink)
setWikidataLink(entity.locationWikidataLink)
setCommonsLink(entity.locationCommonsLink)
}

return Place(
entity.locationLanguage,
entity.locationName,
fr.free.nrw.commons.nearby.Label.fromText(entity.locationLabelText),
entity.locationDescription,
location,
entity.locationCategory,
builder.build(),
entity.locationPic,
entity.locationExists
)
}
}
Loading
Loading