diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 17fad9d8175..1df7a1e3d04 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -213,36 +213,6 @@
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
-
-
-
-
-
>
+ protected abstract fun getAllCategoriesInternal(): Flow>
+
+ fun getAllCategories(): Flow> =
+ 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)
}
diff --git a/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarkCategoryRoomEntity.kt b/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarkCategoryRoomEntity.kt
new file mode 100644
index 00000000000..1c57450b59f
--- /dev/null
+++ b/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarkCategoryRoomEntity.kt
@@ -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
+)
diff --git a/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarksCategoryModal.kt b/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarksCategoryModal.kt
index ab679611f0a..41b7de6ac30 100644
--- a/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarksCategoryModal.kt
+++ b/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarksCategoryModal.kt
@@ -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
)
diff --git a/app/src/main/java/fr/free/nrw/commons/bookmarks/items/BookmarkItemsController.kt b/app/src/main/java/fr/free/nrw/commons/bookmarks/items/BookmarkItemsController.kt
index d1a9ef785e0..f4e9b87e57b 100644
--- a/app/src/main/java/fr/free/nrw/commons/bookmarks/items/BookmarkItemsController.kt
+++ b/app/src/main/java/fr/free/nrw/commons/bookmarks/items/BookmarkItemsController.kt
@@ -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 {
- return bookmarkItemsDao?.getAllBookmarksItems() ?: emptyList()
+ return bookmarkItemsRoomDao.getAllBookmarksItems().blockingGet()
}
}
diff --git a/app/src/main/java/fr/free/nrw/commons/bookmarks/items/BookmarkItemsRoomDao.kt b/app/src/main/java/fr/free/nrw/commons/bookmarks/items/BookmarkItemsRoomDao.kt
index 11fd77b9c9a..b394dbc1a9c 100644
--- a/app/src/main/java/fr/free/nrw/commons/bookmarks/items/BookmarkItemsRoomDao.kt
+++ b/app/src/main/java/fr/free/nrw/commons/bookmarks/items/BookmarkItemsRoomDao.kt
@@ -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>
+ abstract fun getAll(): Single>
@Query("SELECT EXISTS (SELECT 1 FROM bookmarksItems WHERE item_id = :itemId)")
- fun findBookmarkItem(itemId: String?): Boolean
+ abstract fun findBookmarkItem(itemId: String?): Single
+
+ fun getAllBookmarksItems(): Single> {
+ return getAll().map { entities ->
+ entities.map { fromEntity(it) }
+ }
+ }
+
+ fun updateBookmarkItem(depictedItem: DepictedItem): Single {
+ 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,
+ categoryDescriptionList: List,
+ categoryThumbnailList: List
+ ): List = categoryNameList.mapIndexed { index, name ->
+ CategoryItem(
+ name = name,
+ description = categoryDescriptionList.getOrNull(index),
+ thumbnail = categoryThumbnailList.getOrNull(index),
+ isSelected = false
+ )
+ }
}
diff --git a/app/src/main/java/fr/free/nrw/commons/bookmarks/locations/BookmarkLocationsDao.kt b/app/src/main/java/fr/free/nrw/commons/bookmarks/locations/BookmarkLocationsDao.kt
index 2fa65b2d942..ba94eb77502 100644
--- a/app/src/main/java/fr/free/nrw/commons/bookmarks/locations/BookmarkLocationsDao.kt
+++ b/app/src/main/java/fr/free/nrw/commons/bookmarks/locations/BookmarkLocationsDao.kt
@@ -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)
}
@@ -60,6 +60,51 @@ abstract class BookmarkLocationsDao {
* Fetches all bookmark locations as `Place` objects.
*/
suspend fun getAllBookmarksLocationsPlace(): List {
- 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
+ )
}
}
diff --git a/app/src/main/java/fr/free/nrw/commons/bookmarks/locations/BookmarksLocations.kt b/app/src/main/java/fr/free/nrw/commons/bookmarks/locations/BookmarksLocations.kt
index 66d670169a7..7d3db2c0597 100644
--- a/app/src/main/java/fr/free/nrw/commons/bookmarks/locations/BookmarksLocations.kt
+++ b/app/src/main/java/fr/free/nrw/commons/bookmarks/locations/BookmarksLocations.kt
@@ -1,72 +1,28 @@
-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
- )
-}
\ No newline at end of file
+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
+)
+
\ No newline at end of file
diff --git a/app/src/main/java/fr/free/nrw/commons/bookmarks/models/Bookmark.kt b/app/src/main/java/fr/free/nrw/commons/bookmarks/models/Bookmark.kt
index 630889c011f..f7bf9b4dd67 100644
--- a/app/src/main/java/fr/free/nrw/commons/bookmarks/models/Bookmark.kt
+++ b/app/src/main/java/fr/free/nrw/commons/bookmarks/models/Bookmark.kt
@@ -5,22 +5,7 @@ import android.net.Uri
class Bookmark(
mediaName: String?,
mediaCreator: String?,
- /**
- * Gets or Sets the content URI - marking this bookmark as already saved in the database
- * @return content URI
- * contentUri the content URI
- */
- var contentUri: Uri?,
) {
- /**
- * Gets the media name
- * @return the media name
- */
val mediaName: String = mediaName ?: ""
-
- /**
- * Gets media creator
- * @return creator name
- */
val mediaCreator: String = mediaCreator ?: ""
}
diff --git a/app/src/main/java/fr/free/nrw/commons/bookmarks/pictures/BookmarkPicturesController.kt b/app/src/main/java/fr/free/nrw/commons/bookmarks/pictures/BookmarkPicturesController.kt
index 5ee88d973c5..42ecbec032e 100644
--- a/app/src/main/java/fr/free/nrw/commons/bookmarks/pictures/BookmarkPicturesController.kt
+++ b/app/src/main/java/fr/free/nrw/commons/bookmarks/pictures/BookmarkPicturesController.kt
@@ -11,7 +11,7 @@ import javax.inject.Singleton
@Singleton
class BookmarkPicturesController @Inject constructor(
private val mediaClient: MediaClient,
- private val bookmarkDao: BookmarkPicturesDao
+ private val bookmarkDao: BookmarkPicturesRoomDao
) {
private var currentBookmarks: List = listOf()
@@ -20,7 +20,7 @@ class BookmarkPicturesController @Inject constructor(
* @return a list of bookmarked Media object
*/
fun loadBookmarkedPictures(): Single> {
- val bookmarks = bookmarkDao.getAllBookmarks()
+ val bookmarks = bookmarkDao.getAllBookmarks().blockingGet()
currentBookmarks = bookmarks
return Observable.fromIterable(bookmarks).flatMap {
mediaClient.getMedia(it.mediaName)
@@ -30,7 +30,7 @@ class BookmarkPicturesController @Inject constructor(
}
fun needRefreshBookmarkedPictures(): Boolean {
- val bookmarks = bookmarkDao.getAllBookmarks()
+ val bookmarks = bookmarkDao.getAllBookmarks().blockingGet()
return bookmarks.size != currentBookmarks.size
}
diff --git a/app/src/main/java/fr/free/nrw/commons/bookmarks/pictures/BookmarkPicturesDao.kt b/app/src/main/java/fr/free/nrw/commons/bookmarks/pictures/BookmarkPicturesDao.kt
index 00c8e3228b4..c7d45482d97 100644
--- a/app/src/main/java/fr/free/nrw/commons/bookmarks/pictures/BookmarkPicturesDao.kt
+++ b/app/src/main/java/fr/free/nrw/commons/bookmarks/pictures/BookmarkPicturesDao.kt
@@ -86,11 +86,7 @@ class BookmarkPicturesDao @Inject constructor(
private fun deleteBookmark(bookmark: Bookmark) {
val db = clientProvider.get()
try {
- if (bookmark.contentUri == null) {
- throw RuntimeException("tried to delete item with no content URI")
- } else {
- db.delete(bookmark.contentUri!!, null, null)
- }
+ db.delete(BASE_URI, "$COLUMN_MEDIA_NAME=?", arrayOf(bookmark.mediaName))
} catch (e: RemoteException) {
throw RuntimeException(e)
} finally {
@@ -133,7 +129,7 @@ class BookmarkPicturesDao @Inject constructor(
fileName = ""
}
return Bookmark(
- fileName, cursor.getString(COLUMN_CREATOR), uriForName(fileName)
+ fileName, cursor.getString(COLUMN_CREATOR)
)
}
diff --git a/app/src/main/java/fr/free/nrw/commons/bookmarks/pictures/BookmarkPicturesRoomDao.kt b/app/src/main/java/fr/free/nrw/commons/bookmarks/pictures/BookmarkPicturesRoomDao.kt
index 3fb743ed8fe..a4f12fcc717 100644
--- a/app/src/main/java/fr/free/nrw/commons/bookmarks/pictures/BookmarkPicturesRoomDao.kt
+++ b/app/src/main/java/fr/free/nrw/commons/bookmarks/pictures/BookmarkPicturesRoomDao.kt
@@ -5,20 +5,52 @@ import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
+import fr.free.nrw.commons.bookmarks.models.Bookmark
+import io.reactivex.Completable
import io.reactivex.Single
@Dao
-interface BookmarkPicturesRoomDao {
+abstract class BookmarkPicturesRoomDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
- fun insert(bookmark: BookmarkPictureRoomEntity)
+ abstract fun insert(bookmark: BookmarkPictureRoomEntity): Completable
@Delete
- fun delete(bookmark: BookmarkPictureRoomEntity)
+ abstract fun delete(bookmark: BookmarkPictureRoomEntity): Completable
@Query("SELECT * FROM bookmarks")
- fun getAll(): Single>
+ abstract fun getAll(): Single>
@Query("SELECT EXISTS (SELECT 1 FROM bookmarks WHERE media_name = :mediaName)")
- fun findBookmarkByName(mediaName: String): Boolean
+ abstract fun findBookmarkByName(mediaName: String): Single
+
+ fun getAllBookmarks(): Single> {
+ return getAll().map { entities ->
+ entities.map { fromEntity(it) }
+ }
+ }
+
+ fun findBookmark(bookmark: Bookmark?): Single {
+ if (bookmark?.mediaName == null) return Single.just(false)
+ return findBookmarkByName(bookmark.mediaName!!)
+ }
+
+ fun updateBookmark(bookmark: Bookmark): Single {
+ val entity = toEntity(bookmark)
+ return findBookmarkByName(bookmark.mediaName!!).flatMap { exists ->
+ if (exists) {
+ delete(entity).andThen(Single.just(false))
+ } else {
+ insert(entity).andThen(Single.just(true))
+ }
+ }
+ }
+
+ private fun toEntity(bookmark: Bookmark): BookmarkPictureRoomEntity {
+ return BookmarkPictureRoomEntity(bookmark.mediaName!!, bookmark.mediaCreator!!)
+ }
+
+ private fun fromEntity(entity: BookmarkPictureRoomEntity): Bookmark {
+ return Bookmark(entity.mediaName, entity.mediaCreator)
+ }
}
diff --git a/app/src/main/java/fr/free/nrw/commons/category/CategoriesModel.kt b/app/src/main/java/fr/free/nrw/commons/category/CategoriesModel.kt
index 47147944c67..d3f26c1e0ba 100644
--- a/app/src/main/java/fr/free/nrw/commons/category/CategoriesModel.kt
+++ b/app/src/main/java/fr/free/nrw/commons/category/CategoriesModel.kt
@@ -15,11 +15,10 @@ import javax.inject.Inject
/**
* The model class for categories in upload
*/
-class CategoriesModel
- @Inject
+class CategoriesModel @Inject
constructor(
private val categoryClient: CategoryClient,
- private val categoryDao: CategoryDao,
+ private val categoryDao: CategoryRoomDao,
private val gpsCategoryModel: GpsCategoryModel,
) {
private val selectedCategories: MutableList = mutableListOf()
@@ -72,20 +71,15 @@ class CategoriesModel
* @param item
*/
fun updateCategoryCount(item: CategoryItem) {
- var category = categoryDao.find(item.name)
-
- // Newly used category...
- if (category == null) {
- category = Category(
- null, item.name,
- item.description,
- item.thumbnail,
- Date(),
- 0
- )
- }
+ val category = Category(
+ item.name,
+ item.description,
+ item.thumbnail,
+ Date(),
+ 0
+ )
category.incTimesUsed()
- categoryDao.save(category)
+ categoryDao.save(category).blockingAwait()
}
/**
@@ -112,7 +106,7 @@ class CategoriesModel
categoriesFromDepiction(selectedDepictions),
gpsCategoryModel.categoriesFromLocation,
titleCategories(imageTitleList),
- Observable.just(categoryDao.recentCategories(SEARCH_CATS_LIMIT)),
+ Observable.just(categoryDao.recentCategories(SEARCH_CATS_LIMIT).blockingGet()),
Function4(::combine),
)
} else {
diff --git a/app/src/main/java/fr/free/nrw/commons/category/Category.kt b/app/src/main/java/fr/free/nrw/commons/category/Category.kt
index e4bfb957a29..3cbbaa02485 100644
--- a/app/src/main/java/fr/free/nrw/commons/category/Category.kt
+++ b/app/src/main/java/fr/free/nrw/commons/category/Category.kt
@@ -4,7 +4,8 @@ import android.net.Uri
import java.util.Date
data class Category(
- var contentUri: Uri? = null,
+// @Deprecated("Required for legacy ContentProvider DAO compatibility only")
+// var contentUri: Uri? = null,
val name: String? = null,
val description: String? = null,
val thumbnail: String? = null,
diff --git a/app/src/main/java/fr/free/nrw/commons/category/CategoryDao.kt b/app/src/main/java/fr/free/nrw/commons/category/CategoryDao.kt
index 28e77f2c029..ba653b20939 100644
--- a/app/src/main/java/fr/free/nrw/commons/category/CategoryDao.kt
+++ b/app/src/main/java/fr/free/nrw/commons/category/CategoryDao.kt
@@ -1,139 +1,139 @@
-package fr.free.nrw.commons.category
-
-import android.annotation.SuppressLint
-import android.content.ContentProviderClient
-import android.content.ContentValues
-import android.database.Cursor
-import android.os.RemoteException
-import fr.free.nrw.commons.category.CategoryTable.ALL_FIELDS
-import fr.free.nrw.commons.category.CategoryTable.COLUMN_DESCRIPTION
-import fr.free.nrw.commons.category.CategoryTable.COLUMN_ID
-import fr.free.nrw.commons.category.CategoryTable.COLUMN_LAST_USED
-import fr.free.nrw.commons.category.CategoryTable.COLUMN_NAME
-import fr.free.nrw.commons.category.CategoryTable.COLUMN_THUMBNAIL
-import fr.free.nrw.commons.category.CategoryTable.COLUMN_TIMES_USED
-
-import java.util.ArrayList
-import java.util.Date
-import javax.inject.Inject
-import javax.inject.Named
-import javax.inject.Provider
-
-class CategoryDao @Inject constructor(
- @Named("category") private val clientProvider: Provider
-) {
-
- fun save(category: Category) {
- val db = clientProvider.get()
- try {
- if (category.contentUri == null) {
- category.contentUri = db.insert(
- CategoryContentProvider.BASE_URI,
- toContentValues(category)
- )
- } else {
- db.update(
- category.contentUri!!,
- toContentValues(category),
- null,
- null
- )
- }
- } catch (e: RemoteException) {
- throw RuntimeException(e)
- } finally {
- db.release()
- }
- }
-
- /**
- * Find persisted category in database, based on its name.
- *
- * @param name Category's name
- * @return category from database, or null if not found
- */
- fun find(name: String): Category? {
- var cursor: Cursor? = null
- val db = clientProvider.get()
- try {
- cursor = db.query(
- CategoryContentProvider.BASE_URI,
- ALL_FIELDS,
- "${COLUMN_NAME}=?",
- arrayOf(name),
- null
- )
- if (cursor != null && cursor.moveToFirst()) {
- return fromCursor(cursor)
- }
- } catch (e: RemoteException) {
- throw RuntimeException(e)
- } finally {
- cursor?.close()
- db.release()
- }
- return null
- }
-
- /**
- * Retrieve recently-used categories, ordered by descending date.
- *
- * @return a list containing recent categories
- */
- fun recentCategories(limit: Int): List {
- val items = ArrayList()
- var cursor: Cursor? = null
- val db = clientProvider.get()
- try {
- cursor = db.query(
- CategoryContentProvider.BASE_URI,
- ALL_FIELDS,
- null,
- emptyArray(),
- "$COLUMN_LAST_USED DESC"
- )
- while (cursor != null && cursor.moveToNext() && cursor.position < limit) {
- val category = fromCursor(cursor)
- if (category.name != null) {
- items.add(
- CategoryItem(
- category.name,
- category.description,
- category.thumbnail,
- false
- )
- )
- }
- }
- } catch (e: RemoteException) {
- throw RuntimeException(e)
- } finally {
- cursor?.close()
- db.release()
- }
- return items
- }
-
- @SuppressLint("Range")
- fun fromCursor(cursor: Cursor): Category {
- // Hardcoding column positions!
- return Category(
- CategoryContentProvider.uriForId(cursor.getInt(cursor.getColumnIndex(COLUMN_ID))),
- cursor.getString(cursor.getColumnIndex(COLUMN_NAME)),
- cursor.getString(cursor.getColumnIndex(COLUMN_DESCRIPTION)),
- cursor.getString(cursor.getColumnIndex(COLUMN_THUMBNAIL)),
- Date(cursor.getLong(cursor.getColumnIndex(COLUMN_LAST_USED))),
- cursor.getInt(cursor.getColumnIndex(COLUMN_TIMES_USED))
- )
- }
-
- private fun toContentValues(category: Category): ContentValues {
- return ContentValues().apply {
- put(COLUMN_NAME, category.name)
- put(COLUMN_DESCRIPTION, category.description)
- put(COLUMN_THUMBNAIL, category.thumbnail)
- put(COLUMN_LAST_USED, category.lastUsed?.time)
- put(COLUMN_TIMES_USED, category.timesUsed)
- }
- }
-}
+//package fr.free.nrw.commons.category
+//
+//import android.annotation.SuppressLint
+//import android.content.ContentProviderClient
+//import android.content.ContentValues
+//import android.database.Cursor
+//import android.os.RemoteException
+//import fr.free.nrw.commons.category.CategoryTable.ALL_FIELDS
+//import fr.free.nrw.commons.category.CategoryTable.COLUMN_DESCRIPTION
+//import fr.free.nrw.commons.category.CategoryTable.COLUMN_ID
+//import fr.free.nrw.commons.category.CategoryTable.COLUMN_LAST_USED
+//import fr.free.nrw.commons.category.CategoryTable.COLUMN_NAME
+//import fr.free.nrw.commons.category.CategoryTable.COLUMN_THUMBNAIL
+//import fr.free.nrw.commons.category.CategoryTable.COLUMN_TIMES_USED
+//
+//import java.util.ArrayList
+//import java.util.Date
+//import javax.inject.Inject
+//import javax.inject.Named
+//import javax.inject.Provider
+//
+//class CategoryDao @Inject constructor(
+// @Named("category") private val clientProvider: Provider
+//) {
+//
+// fun save(category: Category) {
+// val db = clientProvider.get()
+// try {
+// if (category.contentUri == null) {
+// category.contentUri = db.insert(
+// CategoryContentProvider.BASE_URI,
+// toContentValues(category)
+// )
+// } else {
+// db.update(
+// category.contentUri!!,
+// toContentValues(category),
+// null,
+// null
+// )
+// }
+// } catch (e: RemoteException) {
+// throw RuntimeException(e)
+// } finally {
+// db.release()
+// }
+// }
+//
+// /**
+// * Find persisted category in database, based on its name.
+// *
+// * @param name Category's name
+// * @return category from database, or null if not found
+// */
+// fun find(name: String): Category? {
+// var cursor: Cursor? = null
+// val db = clientProvider.get()
+// try {
+// cursor = db.query(
+// CategoryContentProvider.BASE_URI,
+// ALL_FIELDS,
+// "${COLUMN_NAME}=?",
+// arrayOf(name),
+// null
+// )
+// if (cursor != null && cursor.moveToFirst()) {
+// return fromCursor(cursor)
+// }
+// } catch (e: RemoteException) {
+// throw RuntimeException(e)
+// } finally {
+// cursor?.close()
+// db.release()
+// }
+// return null
+// }
+//
+// /**
+// * Retrieve recently-used categories, ordered by descending date.
+// *
+// * @return a list containing recent categories
+// */
+// fun recentCategories(limit: Int): List {
+// val items = ArrayList()
+// var cursor: Cursor? = null
+// val db = clientProvider.get()
+// try {
+// cursor = db.query(
+// CategoryContentProvider.BASE_URI,
+// ALL_FIELDS,
+// null,
+// emptyArray(),
+// "$COLUMN_LAST_USED DESC"
+// )
+// while (cursor != null && cursor.moveToNext() && cursor.position < limit) {
+// val category = fromCursor(cursor)
+// if (category.name != null) {
+// items.add(
+// CategoryItem(
+// category.name,
+// category.description,
+// category.thumbnail,
+// false
+// )
+// )
+// }
+// }
+// } catch (e: RemoteException) {
+// throw RuntimeException(e)
+// } finally {
+// cursor?.close()
+// db.release()
+// }
+// return items
+// }
+//
+// @SuppressLint("Range")
+// fun fromCursor(cursor: Cursor): Category {
+// // Hardcoding column positions!
+// return Category(
+// CategoryContentProvider.uriForId(cursor.getInt(cursor.getColumnIndex(COLUMN_ID))),
+// cursor.getString(cursor.getColumnIndex(COLUMN_NAME)),
+// cursor.getString(cursor.getColumnIndex(COLUMN_DESCRIPTION)),
+// cursor.getString(cursor.getColumnIndex(COLUMN_THUMBNAIL)),
+// Date(cursor.getLong(cursor.getColumnIndex(COLUMN_LAST_USED))),
+// cursor.getInt(cursor.getColumnIndex(COLUMN_TIMES_USED))
+// )
+// }
+//
+// private fun toContentValues(category: Category): ContentValues {
+// return ContentValues().apply {
+// put(COLUMN_NAME, category.name)
+// put(COLUMN_DESCRIPTION, category.description)
+// put(COLUMN_THUMBNAIL, category.thumbnail)
+// put(COLUMN_LAST_USED, category.lastUsed?.time)
+// put(COLUMN_TIMES_USED, category.timesUsed)
+// }
+// }
+//}
diff --git a/app/src/main/java/fr/free/nrw/commons/category/CategoryItem.kt b/app/src/main/java/fr/free/nrw/commons/category/CategoryItem.kt
index d0ee8d53cd9..3cfd3d37404 100644
--- a/app/src/main/java/fr/free/nrw/commons/category/CategoryItem.kt
+++ b/app/src/main/java/fr/free/nrw/commons/category/CategoryItem.kt
@@ -2,6 +2,7 @@ package fr.free.nrw.commons.category
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
+import java.util.Date
@Parcelize
data class CategoryItem(
diff --git a/app/src/main/java/fr/free/nrw/commons/category/CategoryRoomDao.kt b/app/src/main/java/fr/free/nrw/commons/category/CategoryRoomDao.kt
index ad2d8152ff7..896c701e704 100644
--- a/app/src/main/java/fr/free/nrw/commons/category/CategoryRoomDao.kt
+++ b/app/src/main/java/fr/free/nrw/commons/category/CategoryRoomDao.kt
@@ -1,27 +1,65 @@
package fr.free.nrw.commons.category
-import androidx.room.Dao
-import androidx.room.Insert
-import androidx.room.OnConflictStrategy
-import androidx.room.Query
+import androidx.room.*
import io.reactivex.Completable
import io.reactivex.Single
+import java.util.*
@Dao
-interface CategoryRoomDao {
+abstract class CategoryRoomDao {
@Query("SELECT * FROM categories ORDER BY last_used DESC LIMIT :limit")
- fun getAll(limit: Int): Single>
+ abstract fun getAll(limit: Int): Single>
@Insert(onConflict = OnConflictStrategy.REPLACE)
- fun insert(category: CategoryRoomEntity)
+ abstract fun insert(category: CategoryRoomEntity): Single
+
+ @Update
+ abstract fun update(category: CategoryRoomEntity): Completable
@Query("SELECT * FROM categories WHERE name = :name")
- fun findEntity(name: String): CategoryRoomEntity?
+ abstract fun findEntity(name: String): Single>
@Query("SELECT EXISTS (SELECT 1 FROM categories WHERE name = :name)")
- fun findCategory(name: String): Boolean
+ abstract fun findCategory(name: String): Single
@Query("DELETE FROM categories")
- fun deleteAll(): Completable
+ abstract fun deleteAll(): Completable
+
+ fun recentCategories(limit: Int): Single> {
+ return getAll(limit).map { entities ->
+ entities.map { fromEntity(it) }
+ }
+ }
+
+ fun save(category: Category): Completable {
+ return findEntity(category.name ?: "").flatMapCompletable { entities ->
+ if (entities.isNotEmpty()) {
+ update(toEntity(category, entities[0].id))
+ } else {
+ insert(toEntity(category)).ignoreElement()
+ }
+ }
+ }
+
+ fun toEntity(
+ category: Category,
+ id: Long = 0
+ ): CategoryRoomEntity = CategoryRoomEntity(
+ id = id,
+ name = category.name ?: "",
+ description = category.description,
+ thumbnail = category.thumbnail,
+ lastUsed = category.lastUsed ?: Date(),
+ timesUsed = category.timesUsed
+ )
+
+ private fun fromEntity(
+ entity: CategoryRoomEntity
+ ): CategoryItem = CategoryItem(
+ name = entity.name,
+ description = entity.description,
+ thumbnail = entity.thumbnail,
+ isSelected = false,
+ )
}
diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/Contribution.kt b/app/src/main/java/fr/free/nrw/commons/contributions/Contribution.kt
index d623730abf5..c40c9284c64 100644
--- a/app/src/main/java/fr/free/nrw/commons/contributions/Contribution.kt
+++ b/app/src/main/java/fr/free/nrw/commons/contributions/Contribution.kt
@@ -2,9 +2,6 @@ package fr.free.nrw.commons.contributions
import android.net.Uri
import android.os.Parcelable
-import androidx.room.Embedded
-import androidx.room.Entity
-import androidx.room.PrimaryKey
import fr.free.nrw.commons.Media
import fr.free.nrw.commons.auth.SessionManager
import fr.free.nrw.commons.upload.UploadItem
@@ -16,11 +13,10 @@ import kotlinx.parcelize.Parcelize
import java.io.File
import java.util.Date
-@Entity(tableName = "contribution")
@Parcelize
data class Contribution constructor(
- @Embedded(prefix = "media_") val media: Media,
- @PrimaryKey val pageId: String = media.pageId,
+ val media: Media,
+ val pageId: String = media.pageId,
var state: Int = 0,
var transferred: Long = 0,
val decimalCoords: String? = null,
diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionDao.kt b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionDao.kt
index 50faa134086..3d638bfacef 100644
--- a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionDao.kt
+++ b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionDao.kt
@@ -16,10 +16,16 @@ import java.util.Calendar
@Dao
abstract class ContributionDao {
@Query("SELECT * FROM contribution order by media_dateUploaded DESC")
- abstract fun fetchContributions(): DataSource.Factory
+ protected abstract fun fetchContributionsInternal(): DataSource.Factory
+
+ fun fetchContributions(): DataSource.Factory =
+ fetchContributionsInternal().map { fromEntity(it) }
@Insert(onConflict = OnConflictStrategy.REPLACE)
- abstract fun saveSynchronous(contribution: Contribution)
+ protected abstract fun saveSynchronousInternal(contribution: ContributionRoomEntity)
+
+ fun saveSynchronous(contribution: Contribution) =
+ saveSynchronousInternal(toEntity(contribution))
fun save(contribution: Contribution): Completable {
return Completable
@@ -42,10 +48,16 @@ abstract class ContributionDao {
}
@Insert(onConflict = OnConflictStrategy.REPLACE)
- abstract fun save(contribution: List): Single>
+ protected abstract fun saveInternal(contribution: List): Single>
+
+ fun save(contribution: List): Single> =
+ saveInternal(contribution.map { toEntity(it) })
@Delete
- abstract fun deleteSynchronous(contribution: Contribution)
+ protected abstract fun deleteSynchronousInternal(contribution: ContributionRoomEntity)
+
+ fun deleteSynchronous(contribution: Contribution) =
+ deleteSynchronousInternal(toEntity(contribution))
/**
* Deletes contributions with specific states from the database.
@@ -74,35 +86,38 @@ abstract class ContributionDao {
}
@Query("SELECT * from contribution WHERE media_filename=:fileName")
- abstract fun getContributionWithTitle(fileName: String): List
+ protected abstract fun getContributionWithTitleInternal(fileName: String): List
+
+ fun getContributionWithTitle(fileName: String): List =
+ getContributionWithTitleInternal(fileName).map { fromEntity(it) }
@Query("SELECT * from contribution WHERE pageId=:pageId")
- abstract fun getContribution(pageId: String): Contribution
+ protected abstract fun getContributionInternal(pageId: String): ContributionRoomEntity
+
+ fun getContribution(pageId: String): Contribution =
+ fromEntity(getContributionInternal(pageId))
@Query("SELECT * from contribution WHERE state IN (:states) order by media_dateUploaded DESC")
- abstract fun getContribution(states: List): Single>
+ protected abstract fun getContributionInternal(states: List): Single>
+
+ fun getContribution(states: List): Single> =
+ getContributionInternal(states).map { entities -> entities.map { fromEntity(it) } }
- /**
- * Gets contributions with specific states in descending order by the date they were uploaded.
- *
- * @param states The states of the contributions to fetch.
- * @return A DataSource factory for paginated contributions with the specified states.
- */
@Query("SELECT * from contribution WHERE state IN (:states) order by media_dateUploaded DESC")
- abstract fun getContributions(
+ protected abstract fun getContributionsInternal(
states: List
- ): DataSource.Factory
+ ): DataSource.Factory
+
+ fun getContributions(states: List): DataSource.Factory =
+ getContributionsInternal(states).map { fromEntity(it) }
- /**
- * Gets contributions with specific states in ascending order by the date the upload started.
- *
- * @param states The states of the contributions to fetch.
- * @return A DataSource factory for paginated contributions with the specified states.
- */
@Query("SELECT * from contribution WHERE state IN (:states) order by dateUploadStarted ASC")
- abstract fun getContributionsSortedByDateUploadStarted(
+ protected abstract fun getContributionsSortedByDateUploadStartedInternal(
states: List
- ): DataSource.Factory
+ ): DataSource.Factory
+
+ fun getContributionsSortedByDateUploadStarted(states: List): DataSource.Factory =
+ getContributionsSortedByDateUploadStartedInternal(states).map { fromEntity(it) }
@Query("SELECT COUNT(*) from contribution WHERE state in (:toUpdateStates)")
abstract fun getPendingUploads(toUpdateStates: IntArray): Single
@@ -112,14 +127,11 @@ abstract class ContributionDao {
abstract fun deleteAll()
@Update
- abstract fun updateSynchronous(contribution: Contribution)
+ protected abstract fun updateSynchronousInternal(contribution: ContributionRoomEntity)
+
+ fun updateSynchronous(contribution: Contribution) =
+ updateSynchronousInternal(toEntity(contribution))
- /**
- * Updates the state of contributions with specific states.
- *
- * @param states The current states of the contributions to update.
- * @param newState The new state to set.
- */
@Query("UPDATE contribution SET state = :newState WHERE state IN (:states)")
abstract fun updateContributionsState(states: List, newState: Int)
@@ -130,19 +142,62 @@ abstract class ContributionDao {
}
}
-
-
- /**
- * Updates the state of contributions with specific states asynchronously.
- *
- * @param states The current states of the contributions to update.
- * @param newState The new state to set.
- * @return A Completable indicating the result of the operation.
- */
fun updateContributionsWithStates(states: List, newState: Int): Completable {
return Completable
.fromAction {
updateContributionsState(states, newState)
}
}
+
+ private fun toEntity(contribution: Contribution): ContributionRoomEntity =
+ ContributionRoomEntity(
+ media = contribution.media,
+ pageId = contribution.pageId,
+ state = contribution.state,
+ transferred = contribution.transferred,
+ decimalCoords = contribution.decimalCoords,
+ dateCreatedSource = contribution.dateCreatedSource,
+ wikidataPlace = contribution.wikidataPlace,
+ chunkInfo = contribution.chunkInfo,
+ errorInfo = contribution.errorInfo,
+ depictedItems = contribution.depictedItems,
+ mimeType = contribution.mimeType,
+ localUri = contribution.localUri,
+ dataLength = contribution.dataLength,
+ dateCreated = contribution.dateCreated,
+ dateCreatedString = contribution.dateCreatedString,
+ dateModified = contribution.dateModified,
+ dateUploadStarted = contribution.dateUploadStarted,
+ hasInvalidLocation = contribution.hasInvalidLocation,
+ contentUri = contribution.contentUri,
+ countryCode = contribution.countryCode,
+ imageSHA1 = contribution.imageSHA1,
+ retries = contribution.retries
+ )
+
+ private fun fromEntity(entity: ContributionRoomEntity): Contribution =
+ Contribution(
+ media = entity.media,
+ pageId = entity.pageId,
+ state = entity.state,
+ transferred = entity.transferred,
+ decimalCoords = entity.decimalCoords,
+ dateCreatedSource = entity.dateCreatedSource,
+ wikidataPlace = entity.wikidataPlace,
+ chunkInfo = entity.chunkInfo,
+ errorInfo = entity.errorInfo,
+ depictedItems = entity.depictedItems,
+ mimeType = entity.mimeType,
+ localUri = entity.localUri,
+ dataLength = entity.dataLength,
+ dateCreated = entity.dateCreated,
+ dateCreatedString = entity.dateCreatedString,
+ dateModified = entity.dateModified,
+ dateUploadStarted = entity.dateUploadStarted,
+ hasInvalidLocation = entity.hasInvalidLocation,
+ contentUri = entity.contentUri,
+ countryCode = entity.countryCode,
+ imageSHA1 = entity.imageSHA1,
+ retries = entity.retries
+ )
}
diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionRoomEntity.kt b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionRoomEntity.kt
new file mode 100644
index 00000000000..5808e352047
--- /dev/null
+++ b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionRoomEntity.kt
@@ -0,0 +1,39 @@
+package fr.free.nrw.commons.contributions
+
+import android.net.Uri
+import androidx.room.Embedded
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+import fr.free.nrw.commons.Media
+import fr.free.nrw.commons.upload.WikidataPlace
+import fr.free.nrw.commons.upload.structure.depictions.DepictedItem
+import java.util.Date
+
+/**
+ * Room entity for the contribution table.
+ */
+@Entity(tableName = "contribution")
+data class ContributionRoomEntity(
+ @Embedded(prefix = "media_") val media: Media,
+ @PrimaryKey val pageId: String,
+ val state: Int,
+ val transferred: Long,
+ val decimalCoords: String?,
+ val dateCreatedSource: String?,
+ val wikidataPlace: WikidataPlace?,
+ val chunkInfo: ChunkInfo?,
+ val errorInfo: String?,
+ val depictedItems: List,
+ val mimeType: String?,
+ val localUri: Uri?,
+ val dataLength: Long,
+ val dateCreated: Date?,
+ val dateCreatedString: String?,
+ val dateModified: Date?,
+ val dateUploadStarted: Date?,
+ val hasInvalidLocation: Int,
+ val contentUri: Uri?,
+ val countryCode: String?,
+ val imageSHA1: String?,
+ val retries: Int
+)
diff --git a/app/src/main/java/fr/free/nrw/commons/customselector/database/NotForUploadStatus.kt b/app/src/main/java/fr/free/nrw/commons/customselector/database/NotForUploadStatus.kt
index b3ef36318d9..27bf70bc929 100644
--- a/app/src/main/java/fr/free/nrw/commons/customselector/database/NotForUploadStatus.kt
+++ b/app/src/main/java/fr/free/nrw/commons/customselector/database/NotForUploadStatus.kt
@@ -1,16 +1,11 @@
package fr.free.nrw.commons.customselector.database
-import androidx.room.Entity
-import androidx.room.PrimaryKey
-
/**
* Entity class for Not For Upload status.
*/
-@Entity(tableName = "images_not_for_upload_table")
data class NotForUploadStatus(
/**
* Original image sha1.
*/
- @PrimaryKey
val imageSHA1: String,
)
diff --git a/app/src/main/java/fr/free/nrw/commons/customselector/database/NotForUploadStatusDao.kt b/app/src/main/java/fr/free/nrw/commons/customselector/database/NotForUploadStatusDao.kt
index b75a6e1d4f6..b26a72f4a40 100644
--- a/app/src/main/java/fr/free/nrw/commons/customselector/database/NotForUploadStatusDao.kt
+++ b/app/src/main/java/fr/free/nrw/commons/customselector/database/NotForUploadStatusDao.kt
@@ -5,6 +5,7 @@ import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
+import fr.free.nrw.commons.customselector.database.NotForUploadStatusRoomEntity
/**
* Dao class for Not For Upload
@@ -15,19 +16,32 @@ abstract class NotForUploadStatusDao {
* Insert into Not For Upload status.
*/
@Insert(onConflict = OnConflictStrategy.REPLACE)
- abstract suspend fun insert(notForUploadStatus: NotForUploadStatus)
+ protected abstract fun insertInternal(notForUploadStatus: NotForUploadStatusRoomEntity)
+
+ suspend fun insert(notForUploadStatus: NotForUploadStatus) {
+ insertInternal(toEntity(notForUploadStatus))
+ }
/**
* Delete Not For Upload status entry.
*/
@Delete
- abstract suspend fun delete(notForUploadStatus: NotForUploadStatus)
+ protected abstract fun deleteInternal(notForUploadStatus: NotForUploadStatusRoomEntity)
+
+ suspend fun delete(notForUploadStatus: NotForUploadStatus) {
+ deleteInternal(toEntity(notForUploadStatus))
+ }
/**
* Query Not For Upload status with image sha1.
*/
@Query("SELECT * FROM images_not_for_upload_table WHERE imageSHA1 = (:imageSHA1) ")
- abstract suspend fun getFromImageSHA1(imageSHA1: String): NotForUploadStatus?
+ protected abstract fun getFromImageSHA1Internal(imageSHA1: String): NotForUploadStatusRoomEntity?
+
+ suspend fun getFromImageSHA1(imageSHA1: String): NotForUploadStatus? {
+ val entity = getFromImageSHA1Internal(imageSHA1)
+ return if (entity != null) fromEntity(entity) else null
+ }
/**
* Asynchronous image sha1 query.
@@ -50,4 +64,14 @@ abstract class NotForUploadStatusDao {
*/
@Query("SELECT COUNT() FROM images_not_for_upload_table WHERE imageSHA1 = (:imageSHA1) ")
abstract suspend fun find(imageSHA1: String): Int
+
+ private fun toEntity(notForUploadStatus: NotForUploadStatus): NotForUploadStatusRoomEntity =
+ NotForUploadStatusRoomEntity(
+ imageSHA1 = notForUploadStatus.imageSHA1
+ )
+
+ private fun fromEntity(entity: NotForUploadStatusRoomEntity): NotForUploadStatus =
+ NotForUploadStatus(
+ imageSHA1 = entity.imageSHA1
+ )
}
diff --git a/app/src/main/java/fr/free/nrw/commons/customselector/database/NotForUploadStatusRoomEntity.kt b/app/src/main/java/fr/free/nrw/commons/customselector/database/NotForUploadStatusRoomEntity.kt
new file mode 100644
index 00000000000..87322ef14ec
--- /dev/null
+++ b/app/src/main/java/fr/free/nrw/commons/customselector/database/NotForUploadStatusRoomEntity.kt
@@ -0,0 +1,13 @@
+package fr.free.nrw.commons.customselector.database
+
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+
+/**
+ * Room entity for the images_not_for_upload_table.
+ */
+@Entity(tableName = "images_not_for_upload_table")
+data class NotForUploadStatusRoomEntity(
+ @PrimaryKey
+ val imageSHA1: String
+)
diff --git a/app/src/main/java/fr/free/nrw/commons/customselector/database/UploadedStatus.kt b/app/src/main/java/fr/free/nrw/commons/customselector/database/UploadedStatus.kt
index 7f635ed954d..b3717796191 100644
--- a/app/src/main/java/fr/free/nrw/commons/customselector/database/UploadedStatus.kt
+++ b/app/src/main/java/fr/free/nrw/commons/customselector/database/UploadedStatus.kt
@@ -1,19 +1,14 @@
package fr.free.nrw.commons.customselector.database
-import androidx.room.Entity
-import androidx.room.Index
-import androidx.room.PrimaryKey
import java.util.Date
/**
* Entity class for Uploaded Status.
*/
-@Entity(tableName = "uploaded_table", indices = [Index(value = ["modifiedImageSHA1"], unique = true)])
data class UploadedStatus(
/**
* Original image sha1.
*/
- @PrimaryKey
val imageSHA1: String,
/**
* Modified image sha1 (after exif changes).
diff --git a/app/src/main/java/fr/free/nrw/commons/customselector/database/UploadedStatusDao.kt b/app/src/main/java/fr/free/nrw/commons/customselector/database/UploadedStatusDao.kt
index 378af5b8db7..0412e780d3a 100644
--- a/app/src/main/java/fr/free/nrw/commons/customselector/database/UploadedStatusDao.kt
+++ b/app/src/main/java/fr/free/nrw/commons/customselector/database/UploadedStatusDao.kt
@@ -7,6 +7,7 @@ import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Update
import java.util.Calendar
+import fr.free.nrw.commons.customselector.database.UploadedStatusRoomEntity
/**
* UploadedStatusDao for Custom Selector.
@@ -17,31 +18,53 @@ abstract class UploadedStatusDao {
* Insert into uploaded status.
*/
@Insert(onConflict = OnConflictStrategy.REPLACE)
- abstract suspend fun insert(uploadedStatus: UploadedStatus)
+ protected abstract fun insertInternal(uploadedStatus: UploadedStatusRoomEntity)
+
+ suspend fun insert(uploadedStatus: UploadedStatus) {
+ insertInternal(toEntity(uploadedStatus))
+ }
/**
* Update uploaded status entry.
*/
@Update
- abstract suspend fun update(uploadedStatus: UploadedStatus)
+ protected abstract fun updateInternal(uploadedStatus: UploadedStatusRoomEntity)
+
+ suspend fun update(uploadedStatus: UploadedStatus) {
+ updateInternal(toEntity(uploadedStatus))
+ }
/**
* Delete uploaded status entry.
*/
@Delete
- abstract suspend fun delete(uploadedStatus: UploadedStatus)
+ protected abstract fun deleteInternal(uploadedStatus: UploadedStatusRoomEntity)
+
+ suspend fun delete(uploadedStatus: UploadedStatus) {
+ deleteInternal(toEntity(uploadedStatus))
+ }
/**
* Query uploaded status with image sha1.
*/
@Query("SELECT * FROM uploaded_table WHERE imageSHA1 = (:imageSHA1) ")
- abstract suspend fun getFromImageSHA1(imageSHA1: String): UploadedStatus?
+ protected abstract fun getFromImageSHA1Internal(imageSHA1: String): UploadedStatusRoomEntity?
+
+ suspend fun getFromImageSHA1(imageSHA1: String): UploadedStatus? {
+ val entity = getFromImageSHA1Internal(imageSHA1)
+ return if (entity != null) fromEntity(entity) else null
+ }
/**
* Query uploaded status with modified image sha1.
*/
@Query("SELECT * FROM uploaded_table WHERE modifiedImageSHA1 = (:modifiedImageSHA1) ")
- abstract suspend fun getFromModifiedImageSHA1(modifiedImageSHA1: String): UploadedStatus?
+ protected abstract fun getFromModifiedImageSHA1Internal(modifiedImageSHA1: String): UploadedStatusRoomEntity?
+
+ suspend fun getFromModifiedImageSHA1(modifiedImageSHA1: String): UploadedStatus? {
+ val entity = getFromModifiedImageSHA1Internal(modifiedImageSHA1)
+ return if (entity != null) fromEntity(entity) else null
+ }
/**
* Asynchronous insert into uploaded status table.
@@ -75,4 +98,22 @@ abstract class UploadedStatusDao {
* Asynchronous image sha1 query.
*/
suspend fun getUploadedFromImageSHA1(imageSHA1: String): UploadedStatus? = getFromImageSHA1(imageSHA1)
+
+ private fun toEntity(uploadedStatus: UploadedStatus): UploadedStatusRoomEntity =
+ UploadedStatusRoomEntity(
+ imageSHA1 = uploadedStatus.imageSHA1,
+ modifiedImageSHA1 = uploadedStatus.modifiedImageSHA1,
+ imageResult = uploadedStatus.imageResult,
+ modifiedImageResult = uploadedStatus.modifiedImageResult,
+ lastUpdated = uploadedStatus.lastUpdated
+ )
+
+ private fun fromEntity(entity: UploadedStatusRoomEntity): UploadedStatus =
+ UploadedStatus(
+ imageSHA1 = entity.imageSHA1,
+ modifiedImageSHA1 = entity.modifiedImageSHA1,
+ imageResult = entity.imageResult,
+ modifiedImageResult = entity.modifiedImageResult,
+ lastUpdated = entity.lastUpdated
+ )
}
diff --git a/app/src/main/java/fr/free/nrw/commons/customselector/database/UploadedStatusRoomEntity.kt b/app/src/main/java/fr/free/nrw/commons/customselector/database/UploadedStatusRoomEntity.kt
new file mode 100644
index 00000000000..2267406fca7
--- /dev/null
+++ b/app/src/main/java/fr/free/nrw/commons/customselector/database/UploadedStatusRoomEntity.kt
@@ -0,0 +1,19 @@
+package fr.free.nrw.commons.customselector.database
+
+import androidx.room.Entity
+import androidx.room.Index
+import androidx.room.PrimaryKey
+import java.util.Date
+
+/**
+ * Room entity for the uploaded_table.
+ */
+@Entity(tableName = "uploaded_table", indices = [Index(value = ["modifiedImageSHA1"], unique = true)])
+data class UploadedStatusRoomEntity(
+ @PrimaryKey
+ val imageSHA1: String,
+ val modifiedImageSHA1: String,
+ var imageResult: Boolean,
+ var modifiedImageResult: Boolean,
+ var lastUpdated: Date? = null
+)
diff --git a/app/src/main/java/fr/free/nrw/commons/db/AppDatabase.kt b/app/src/main/java/fr/free/nrw/commons/db/AppDatabase.kt
index f354482f3b6..612fab17ce7 100644
--- a/app/src/main/java/fr/free/nrw/commons/db/AppDatabase.kt
+++ b/app/src/main/java/fr/free/nrw/commons/db/AppDatabase.kt
@@ -4,7 +4,7 @@ import androidx.room.Database
import androidx.room.RoomDatabase
import androidx.room.TypeConverters
import fr.free.nrw.commons.bookmarks.category.BookmarkCategoriesDao
-import fr.free.nrw.commons.bookmarks.category.BookmarksCategoryModal
+import fr.free.nrw.commons.bookmarks.category.BookmarkCategoryRoomEntity
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsRoomDao
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsRoomEntity
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao
@@ -13,21 +13,21 @@ import fr.free.nrw.commons.bookmarks.pictures.BookmarkPictureRoomEntity
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesRoomDao
import fr.free.nrw.commons.category.CategoryRoomDao
import fr.free.nrw.commons.category.CategoryRoomEntity
-import fr.free.nrw.commons.contributions.Contribution
+import fr.free.nrw.commons.contributions.ContributionRoomEntity
import fr.free.nrw.commons.contributions.ContributionDao
-import fr.free.nrw.commons.customselector.database.NotForUploadStatus
-import fr.free.nrw.commons.customselector.database.NotForUploadStatusDao
-import fr.free.nrw.commons.customselector.database.UploadedStatus
+import fr.free.nrw.commons.customselector.database.UploadedStatusRoomEntity
import fr.free.nrw.commons.customselector.database.UploadedStatusDao
+import fr.free.nrw.commons.customselector.database.NotForUploadStatusRoomEntity
+import fr.free.nrw.commons.customselector.database.NotForUploadStatusDao
import fr.free.nrw.commons.explore.recentsearches.RecentSearchRoomEntity
import fr.free.nrw.commons.explore.recentsearches.RecentSearchesRoomDao
-import fr.free.nrw.commons.nearby.Place
+import fr.free.nrw.commons.nearby.PlaceRoomEntity
import fr.free.nrw.commons.nearby.PlaceDao
import fr.free.nrw.commons.recentlanguages.RecentLanguageRoomEntity
import fr.free.nrw.commons.recentlanguages.RecentLanguagesRoomDao
+import fr.free.nrw.commons.review.ReviewRoomEntity
import fr.free.nrw.commons.review.ReviewDao
-import fr.free.nrw.commons.review.ReviewEntity
-import fr.free.nrw.commons.upload.depicts.Depicts
+import fr.free.nrw.commons.upload.depicts.DepictsRoomEntity
import fr.free.nrw.commons.upload.depicts.DepictsDao
/**
@@ -35,10 +35,10 @@ import fr.free.nrw.commons.upload.depicts.DepictsDao
*
*/
@Database(
- entities = [Contribution::class, Depicts::class,
- UploadedStatus::class, NotForUploadStatus::class,
- ReviewEntity::class, Place::class,
- BookmarksCategoryModal::class, BookmarksLocations::class,
+ entities = [ContributionRoomEntity::class, DepictsRoomEntity::class,
+ UploadedStatusRoomEntity::class, NotForUploadStatusRoomEntity::class,
+ ReviewRoomEntity::class, PlaceRoomEntity::class,
+ BookmarkCategoryRoomEntity::class, BookmarksLocations::class,
BookmarkPictureRoomEntity::class, BookmarkItemsRoomEntity::class,
CategoryRoomEntity::class, RecentLanguageRoomEntity::class, RecentSearchRoomEntity::class
],
diff --git a/app/src/main/java/fr/free/nrw/commons/description/DescriptionEditActivity.kt b/app/src/main/java/fr/free/nrw/commons/description/DescriptionEditActivity.kt
index b1f1b7f9b8d..25b270f115e 100644
--- a/app/src/main/java/fr/free/nrw/commons/description/DescriptionEditActivity.kt
+++ b/app/src/main/java/fr/free/nrw/commons/description/DescriptionEditActivity.kt
@@ -18,7 +18,7 @@ import fr.free.nrw.commons.auth.csrf.InvalidLoginTokenException
import fr.free.nrw.commons.databinding.ActivityDescriptionEditBinding
import fr.free.nrw.commons.description.EditDescriptionConstants.LIST_OF_DESCRIPTION_AND_CAPTION
import fr.free.nrw.commons.description.EditDescriptionConstants.WIKITEXT
-import fr.free.nrw.commons.recentlanguages.RecentLanguagesDao
+import fr.free.nrw.commons.recentlanguages.RecentLanguagesRoomDao
import fr.free.nrw.commons.settings.Prefs
import fr.free.nrw.commons.theme.BaseActivity
import fr.free.nrw.commons.utils.applyEdgeToEdgeBottomInsets
@@ -70,7 +70,7 @@ class DescriptionEditActivity :
private var progressDialog: ProgressDialog? = null
@Inject
- lateinit var recentLanguagesDao: RecentLanguagesDao
+ lateinit var recentLanguagesDao: RecentLanguagesRoomDao
private lateinit var binding: ActivityDescriptionEditBinding
diff --git a/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationComponent.kt b/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationComponent.kt
index 9e569982f7e..d95a5b9ee33 100644
--- a/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationComponent.kt
+++ b/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationComponent.kt
@@ -38,7 +38,6 @@ import javax.inject.Singleton
ActivityBuilderModule::class,
FragmentBuilderModule::class,
ServiceBuilderModule::class,
- ContentProviderBuilderModule::class,
UploadModule::class,
ContributionsModule::class,
ContributionsProvidesModule::class,
diff --git a/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationModule.kt b/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationModule.kt
index 346bb0ef1b9..d4a32f427e6 100644
--- a/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationModule.kt
+++ b/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationModule.kt
@@ -1,7 +1,6 @@
package fr.free.nrw.commons.di
import android.app.Activity
-import android.content.ContentProviderClient
import android.content.ContentResolver
import android.content.Context
import android.database.sqlite.SQLiteDatabase
@@ -13,12 +12,16 @@ import androidx.sqlite.db.SupportSQLiteDatabase
import com.google.gson.Gson
import dagger.Module
import dagger.Provides
-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.items.BookmarkItemsRoomDao
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao
+import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesRoomDao
+import fr.free.nrw.commons.category.CategoryRoomDao
import fr.free.nrw.commons.contributions.ContributionDao
+import fr.free.nrw.commons.explore.recentsearches.RecentSearchesRoomDao
+import fr.free.nrw.commons.recentlanguages.RecentLanguagesRoomDao
import fr.free.nrw.commons.customselector.database.NotForUploadStatusDao
import fr.free.nrw.commons.customselector.database.UploadedStatusDao
import fr.free.nrw.commons.customselector.ui.selector.ImageFileLoader
@@ -90,50 +93,6 @@ open class CommonsApplicationModule(private val applicationContext: Context) {
context.getString(R.string.license_name_cc_by_sa_four) to Prefs.Licenses.CC_BY_SA_4
)
- /**
- * Provides an instance of CategoryContentProviderClient i.e. the categories
- * that are there in local storage
- */
- @Provides
- @Named("category")
- open fun provideCategoryContentProviderClient(context: Context): ContentProviderClient? =
- context.contentResolver.acquireContentProviderClient(BuildConfig.CATEGORY_AUTHORITY)
-
- @Provides
- @Named("recentsearch")
- fun provideRecentSearchContentProviderClient(context: Context): ContentProviderClient? =
- context.contentResolver.acquireContentProviderClient(BuildConfig.RECENT_SEARCH_AUTHORITY)
-
- @Provides
- @Named("contribution")
- open fun provideContributionContentProviderClient(context: Context): ContentProviderClient? =
- context.contentResolver.acquireContentProviderClient(BuildConfig.CONTRIBUTION_AUTHORITY)
-
- @Provides
- @Named("modification")
- open fun provideModificationContentProviderClient(context: Context): ContentProviderClient? =
- context.contentResolver.acquireContentProviderClient(BuildConfig.MODIFICATION_AUTHORITY)
-
- @Provides
- @Named("bookmarks")
- fun provideBookmarkContentProviderClient(context: Context): ContentProviderClient? =
- context.contentResolver.acquireContentProviderClient(BuildConfig.BOOKMARK_AUTHORITY)
-
- @Provides
- @Named("bookmarksItem")
- fun provideBookmarkItemContentProviderClient(context: Context): ContentProviderClient? =
- context.contentResolver.acquireContentProviderClient(BuildConfig.BOOKMARK_ITEMS_AUTHORITY)
-
- /**
- * This method is used to provide instance of RecentLanguagesContentProvider
- * which provides content of recent used languages from database
- * @param context Context
- * @return returns RecentLanguagesContentProvider
- */
- @Provides
- @Named("recent_languages")
- fun provideRecentLanguagesContentProviderClient(context: Context): ContentProviderClient? =
- context.contentResolver.acquireContentProviderClient(BuildConfig.RECENT_LANGUAGE_AUTHORITY)
/**
* Provides a Json store instance(JsonKvStore) which keeps
@@ -157,6 +116,7 @@ open class CommonsApplicationModule(private val applicationContext: Context) {
open fun provideLocationServiceManager(context: Context): LocationServiceManager =
LocationServiceManager(context)
+
@Provides
@Singleton
open fun provideDBOpenHelper(context: Context): DBOpenHelper =
@@ -238,6 +198,26 @@ open class CommonsApplicationModule(private val applicationContext: Context) {
fun providesBookmarkCategoriesDao (appDatabase: AppDatabase): BookmarkCategoriesDao =
appDatabase.bookmarkCategoriesDao()
+ @Provides
+ fun providesCategoryRoomDao(appDatabase: AppDatabase): CategoryRoomDao =
+ appDatabase.categoryRoomDao()
+
+ @Provides
+ fun providesBookmarkPicturesRoomDao(appDatabase: AppDatabase): BookmarkPicturesRoomDao =
+ appDatabase.bookmarkPicturesRoomDao()
+
+ @Provides
+ fun providesBookmarkItemsRoomDao(appDatabase: AppDatabase): BookmarkItemsRoomDao =
+ appDatabase.bookmarkItemsRoomDao()
+
+ @Provides
+ fun providesRecentLanguagesRoomDao(appDatabase: AppDatabase): RecentLanguagesRoomDao =
+ appDatabase.recentLanguagesRoomDao()
+
+ @Provides
+ fun providesRecentSearchesRoomDao(appDatabase: AppDatabase): RecentSearchesRoomDao =
+ appDatabase.recentSearchesRoomDao()
+
@Provides
fun providesContentResolver(context: Context): ContentResolver =
context.contentResolver
diff --git a/app/src/main/java/fr/free/nrw/commons/explore/SearchActivity.kt b/app/src/main/java/fr/free/nrw/commons/explore/SearchActivity.kt
index 0d7dfd21803..16b4bc0f72a 100644
--- a/app/src/main/java/fr/free/nrw/commons/explore/SearchActivity.kt
+++ b/app/src/main/java/fr/free/nrw/commons/explore/SearchActivity.kt
@@ -15,7 +15,7 @@ import fr.free.nrw.commons.explore.categories.search.SearchCategoryFragment
import fr.free.nrw.commons.explore.depictions.search.SearchDepictionsFragment
import fr.free.nrw.commons.explore.media.SearchMediaFragment
import fr.free.nrw.commons.explore.models.RecentSearch
-import fr.free.nrw.commons.explore.recentsearches.RecentSearchesDao
+import fr.free.nrw.commons.explore.recentsearches.RecentSearchesRoomDao
import fr.free.nrw.commons.explore.recentsearches.RecentSearchesFragment
import fr.free.nrw.commons.media.MediaDetailPagerFragment
import fr.free.nrw.commons.media.MediaDetailProvider
@@ -35,7 +35,7 @@ import javax.inject.Inject
class SearchActivity : BaseActivity(), MediaDetailProvider, CategoryImagesCallback {
@JvmField
@Inject
- var recentSearchesDao: RecentSearchesDao? = null
+ var recentSearchesDao: RecentSearchesRoomDao? = null
private var searchMediaFragment: SearchMediaFragment? = null
private var searchCategoryFragment: SearchCategoryFragment? = null
@@ -130,14 +130,7 @@ class SearchActivity : BaseActivity(), MediaDetailProvider, CategoryImagesCallba
}
private fun saveRecentSearch(query: String) {
- val recentSearch = recentSearchesDao!!.find(query)
- // Newly searched query...
- if (recentSearch == null) {
- recentSearchesDao!!.save(RecentSearch(null, query, Date()))
- } else {
- recentSearch.lastSearched = Date()
- recentSearchesDao!!.save(recentSearch)
- }
+ recentSearchesDao!!.save(RecentSearch(query, Date())).blockingAwait()
}
override fun getMediaAtPosition(i: Int): Media? = searchMediaFragment!!.getMediaAtPosition(i)
diff --git a/app/src/main/java/fr/free/nrw/commons/explore/depictions/WikidataItemDetailsActivity.kt b/app/src/main/java/fr/free/nrw/commons/explore/depictions/WikidataItemDetailsActivity.kt
index d025fdfe102..38354bac9b6 100644
--- a/app/src/main/java/fr/free/nrw/commons/explore/depictions/WikidataItemDetailsActivity.kt
+++ b/app/src/main/java/fr/free/nrw/commons/explore/depictions/WikidataItemDetailsActivity.kt
@@ -13,7 +13,7 @@ import com.google.android.material.snackbar.Snackbar
import fr.free.nrw.commons.Media
import fr.free.nrw.commons.R
import fr.free.nrw.commons.ViewPagerAdapter
-import fr.free.nrw.commons.bookmarks.items.BookmarkItemsDao
+import fr.free.nrw.commons.bookmarks.items.BookmarkItemsRoomDao
import fr.free.nrw.commons.category.CategoryImagesCallback
import fr.free.nrw.commons.databinding.ActivityWikidataItemDetailsBinding
import fr.free.nrw.commons.explore.depictions.child.ChildDepictionsFragment
@@ -38,7 +38,7 @@ import javax.inject.Inject
class WikidataItemDetailsActivity : BaseActivity(), MediaDetailProvider, CategoryImagesCallback {
@JvmField
@Inject
- var bookmarkItemsDao: BookmarkItemsDao? = null
+ var bookmarkItemsDao: BookmarkItemsRoomDao? = null
@JvmField
@Inject
@@ -220,7 +220,7 @@ class WikidataItemDetailsActivity : BaseActivity(), MediaDetailProvider, Categor
.subscribe(Consumer> { depictedItems: List ->
val bookmarkExists = bookmarkItemsDao!!.updateBookmarkItem(
depictedItems[0]!!
- )
+ ).blockingGet()
val snackbar = if (bookmarkExists)
Snackbar.make(
findViewById(R.id.toolbar_layout),
@@ -238,7 +238,7 @@ class WikidataItemDetailsActivity : BaseActivity(), MediaDetailProvider, Categor
})
)
} else {
- val bookmarkExists = bookmarkItemsDao!!.updateBookmarkItem(wikidataItem!!)
+ val bookmarkExists = bookmarkItemsDao!!.updateBookmarkItem(wikidataItem!!).blockingGet()
val snackbar = if (bookmarkExists)
Snackbar.make(
findViewById(R.id.toolbar_layout),
@@ -267,9 +267,9 @@ class WikidataItemDetailsActivity : BaseActivity(), MediaDetailProvider, Categor
private fun updateBookmarkState(item: MenuItem) {
val isBookmarked: Boolean = if (intent.getStringExtra("fragment") != null) {
- bookmarkItemsDao!!.findBookmarkItem(intent.getStringExtra("entityId"))
+ bookmarkItemsDao!!.findBookmarkItem(intent.getStringExtra("entityId")).blockingGet()
} else {
- bookmarkItemsDao!!.findBookmarkItem(wikidataItem!!.id)
+ bookmarkItemsDao!!.findBookmarkItem(wikidataItem!!.id).blockingGet()
}
item.setIcon(if (isBookmarked) {
R.drawable.menu_ic_round_star_filled_24px
diff --git a/app/src/main/java/fr/free/nrw/commons/explore/models/RecentSearch.kt b/app/src/main/java/fr/free/nrw/commons/explore/models/RecentSearch.kt
index 0f72cac29c1..2c527ec3080 100644
--- a/app/src/main/java/fr/free/nrw/commons/explore/models/RecentSearch.kt
+++ b/app/src/main/java/fr/free/nrw/commons/explore/models/RecentSearch.kt
@@ -3,17 +3,13 @@ package fr.free.nrw.commons.explore.models
import android.net.Uri
import java.util.Date
-/**
- * Represents a recently searched query
- * Example - query = "butterfly"
- */
class RecentSearch(
/**
* The content URI that marks this query as already saved in the database.
- *
* @property contentUri the content URI
*/
- var contentUri: Uri?,
+// @Deprecated("Required for legacy ContentProvider DAO compatibility only")
+// var contentUri: Uri? = null,
/**
* Gets query name
* @return query name
diff --git a/app/src/main/java/fr/free/nrw/commons/explore/recentsearches/RecentSearchesDao.kt b/app/src/main/java/fr/free/nrw/commons/explore/recentsearches/RecentSearchesDao.kt
index d16d250dd7f..d6707db0bc2 100644
--- a/app/src/main/java/fr/free/nrw/commons/explore/recentsearches/RecentSearchesDao.kt
+++ b/app/src/main/java/fr/free/nrw/commons/explore/recentsearches/RecentSearchesDao.kt
@@ -1,188 +1,188 @@
-package fr.free.nrw.commons.explore.recentsearches
-
-import android.annotation.SuppressLint
-import android.content.ContentProviderClient
-import android.content.ContentValues
-import android.database.Cursor
-import android.os.RemoteException
-import androidx.core.content.contentValuesOf
-import fr.free.nrw.commons.explore.models.RecentSearch
-import fr.free.nrw.commons.explore.recentsearches.RecentSearchesContentProvider.Companion.BASE_URI
-import fr.free.nrw.commons.explore.recentsearches.RecentSearchesContentProvider.Companion.uriForId
-import fr.free.nrw.commons.explore.recentsearches.RecentSearchesTable.ALL_FIELDS
-import fr.free.nrw.commons.explore.recentsearches.RecentSearchesTable.COLUMN_ID
-import fr.free.nrw.commons.explore.recentsearches.RecentSearchesTable.COLUMN_LAST_USED
-import fr.free.nrw.commons.explore.recentsearches.RecentSearchesTable.COLUMN_NAME
-import fr.free.nrw.commons.utils.getInt
-import fr.free.nrw.commons.utils.getLong
-import fr.free.nrw.commons.utils.getString
-import java.util.Date
-import javax.inject.Inject
-import javax.inject.Named
-import javax.inject.Provider
-
-/**
- * This class doesn't execute queries in database directly instead it contains the logic behind
- * inserting, deleting, searching data from recent searches database.
- */
-class RecentSearchesDao @Inject constructor(
- @param:Named("recentsearch") private val clientProvider: Provider
-) {
- /**
- * This method is called on click of media/ categories for storing them in recent searches
- * @param recentSearch a recent searches object that is to be added in SqLite DB
- */
- fun save(recentSearch: RecentSearch) {
- val db = clientProvider.get()
- try {
- val contentValues = toContentValues(recentSearch)
- if (recentSearch.contentUri == null) {
- recentSearch.contentUri = db.insert(BASE_URI, contentValues)
- } else {
- db.update(recentSearch.contentUri!!, contentValues, null, null)
- }
- } catch (e: RemoteException) {
- throw RuntimeException(e)
- } finally {
- db.release()
- }
- }
-
- /**
- * This method is called on confirmation of delete recent searches.
- * It deletes all recent searches from the database
- */
- fun deleteAll() {
- var cursor: Cursor? = null
- val db = clientProvider.get()
- try {
- cursor = db.query(
- BASE_URI,
- ALL_FIELDS,
- null,
- arrayOf(),
- "$COLUMN_LAST_USED DESC"
- )
- while (cursor != null && cursor.moveToNext()) {
- try {
- val recentSearch = find(fromCursor(cursor).query)
- if (recentSearch!!.contentUri == null) {
- throw RuntimeException("tried to delete item with no content URI")
- } else {
- db.delete(recentSearch.contentUri!!, null, null)
- }
- } catch (e: RemoteException) {
- throw RuntimeException(e)
- } finally {
- db.release()
- }
- }
- } catch (e: RemoteException) {
- throw RuntimeException(e)
- } finally {
- cursor?.close()
- }
- }
-
- /**
- * Deletes a recent search from the database
- */
- fun delete(recentSearch: RecentSearch) {
- val db = clientProvider.get()
- try {
- if (recentSearch.contentUri == null) {
- throw RuntimeException("tried to delete item with no content URI")
- } else {
- db.delete(recentSearch.contentUri!!, null, null)
- }
- } catch (e: RemoteException) {
- throw RuntimeException(e)
- } finally {
- db.release()
- }
- }
-
-
- /**
- * Find persisted search query in database, based on its name.
- * @param name Search query Ex- "butterfly"
- * @return recently searched query from database, or null if not found
- */
- fun find(name: String): RecentSearch? {
- var cursor: Cursor? = null
- val db = clientProvider.get()
- try {
- cursor = db.query(
- BASE_URI,
- ALL_FIELDS,
- "$COLUMN_NAME=?",
- arrayOf(name),
- null
- )
- if (cursor != null && cursor.moveToFirst()) {
- return fromCursor(cursor)
- }
- } catch (e: RemoteException) {
- // This feels lazy, but to hell with checked exceptions. :)
- throw RuntimeException(e)
- } finally {
- cursor?.close()
- db.release()
- }
- return null
- }
-
- /**
- * Retrieve recently-searched queries, ordered by descending date.
- * @return a list containing recent searches
- */
- fun recentSearches(limit: Int): List {
- val items: MutableList = mutableListOf()
- var cursor: Cursor? = null
- val db = clientProvider.get()
- try {
- cursor = db.query(
- BASE_URI, ALL_FIELDS,
- null, arrayOf(), "$COLUMN_LAST_USED DESC"
- )
- // fixme add a limit on the original query instead of falling out of the loop?
- while (cursor != null && cursor.moveToNext() && cursor.position < limit) {
- items.add(fromCursor(cursor).query)
- }
- } catch (e: RemoteException) {
- throw RuntimeException(e)
- } finally {
- cursor?.close()
- db.release()
- }
- return items
- }
-
- /**
- * It creates an Recent Searches object from data stored in the SQLite DB by using cursor
- * @param cursor
- * @return RecentSearch object
- */
- fun fromCursor(cursor: Cursor): RecentSearch {
- var query = cursor.getString(COLUMN_NAME)
-
- if (query == null) {
- query = ""
- }
-
- return RecentSearch(
- uriForId(cursor.getInt(COLUMN_ID)),
- query,
- Date(cursor.getLong(COLUMN_LAST_USED))
- )
- }
-
- /**
- * This class contains the database table architechture for recent searches,
- * It also contains queries and logic necessary to the create, update, delete this table.
- */
- private fun toContentValues(recentSearch: RecentSearch): ContentValues = contentValuesOf(
- COLUMN_NAME to recentSearch.query,
- COLUMN_LAST_USED to recentSearch.lastSearched.time
- )
-}
+//package fr.free.nrw.commons.explore.recentsearches
+//
+//import android.annotation.SuppressLint
+//import android.content.ContentProviderClient
+//import android.content.ContentValues
+//import android.database.Cursor
+//import android.os.RemoteException
+//import androidx.core.content.contentValuesOf
+//import fr.free.nrw.commons.explore.models.RecentSearch
+//import fr.free.nrw.commons.explore.recentsearches.RecentSearchesContentProvider.Companion.BASE_URI
+//import fr.free.nrw.commons.explore.recentsearches.RecentSearchesContentProvider.Companion.uriForId
+//import fr.free.nrw.commons.explore.recentsearches.RecentSearchesTable.ALL_FIELDS
+//import fr.free.nrw.commons.explore.recentsearches.RecentSearchesTable.COLUMN_ID
+//import fr.free.nrw.commons.explore.recentsearches.RecentSearchesTable.COLUMN_LAST_USED
+//import fr.free.nrw.commons.explore.recentsearches.RecentSearchesTable.COLUMN_NAME
+//import fr.free.nrw.commons.utils.getInt
+//import fr.free.nrw.commons.utils.getLong
+//import fr.free.nrw.commons.utils.getString
+//import java.util.Date
+//import javax.inject.Inject
+//import javax.inject.Named
+//import javax.inject.Provider
+//
+///**
+// * This class doesn't execute queries in database directly instead it contains the logic behind
+// * inserting, deleting, searching data from recent searches database.
+// */
+//class RecentSearchesDao @Inject constructor(
+// @param:Named("recentsearch") private val clientProvider: Provider
+//) {
+// /**
+// * This method is called on click of media/ categories for storing them in recent searches
+// * @param recentSearch a recent searches object that is to be added in SqLite DB
+// */
+// fun save(recentSearch: RecentSearch) {
+// val db = clientProvider.get()
+// try {
+// val contentValues = toContentValues(recentSearch)
+// if (recentSearch.contentUri == null) {
+// recentSearch.contentUri = db.insert(BASE_URI, contentValues)
+// } else {
+// db.update(recentSearch.contentUri!!, contentValues, null, null)
+// }
+// } catch (e: RemoteException) {
+// throw RuntimeException(e)
+// } finally {
+// db.release()
+// }
+// }
+//
+// /**
+// * This method is called on confirmation of delete recent searches.
+// * It deletes all recent searches from the database
+// */
+// fun deleteAll() {
+// var cursor: Cursor? = null
+// val db = clientProvider.get()
+// try {
+// cursor = db.query(
+// BASE_URI,
+// ALL_FIELDS,
+// null,
+// arrayOf(),
+// "$COLUMN_LAST_USED DESC"
+// )
+// while (cursor != null && cursor.moveToNext()) {
+// try {
+// val recentSearch = find(fromCursor(cursor).query)
+// if (recentSearch!!.contentUri == null) {
+// throw RuntimeException("tried to delete item with no content URI")
+// } else {
+// db.delete(recentSearch.contentUri!!, null, null)
+// }
+// } catch (e: RemoteException) {
+// throw RuntimeException(e)
+// } finally {
+// db.release()
+// }
+// }
+// } catch (e: RemoteException) {
+// throw RuntimeException(e)
+// } finally {
+// cursor?.close()
+// }
+// }
+//
+// /**
+// * Deletes a recent search from the database
+// */
+// fun delete(recentSearch: RecentSearch) {
+// val db = clientProvider.get()
+// try {
+// if (recentSearch.contentUri == null) {
+// throw RuntimeException("tried to delete item with no content URI")
+// } else {
+// db.delete(recentSearch.contentUri!!, null, null)
+// }
+// } catch (e: RemoteException) {
+// throw RuntimeException(e)
+// } finally {
+// db.release()
+// }
+// }
+//
+//
+// /**
+// * Find persisted search query in database, based on its name.
+// * @param name Search query Ex- "butterfly"
+// * @return recently searched query from database, or null if not found
+// */
+// fun find(name: String): RecentSearch? {
+// var cursor: Cursor? = null
+// val db = clientProvider.get()
+// try {
+// cursor = db.query(
+// BASE_URI,
+// ALL_FIELDS,
+// "$COLUMN_NAME=?",
+// arrayOf(name),
+// null
+// )
+// if (cursor != null && cursor.moveToFirst()) {
+// return fromCursor(cursor)
+// }
+// } catch (e: RemoteException) {
+// // This feels lazy, but to hell with checked exceptions. :)
+// throw RuntimeException(e)
+// } finally {
+// cursor?.close()
+// db.release()
+// }
+// return null
+// }
+//
+// /**
+// * Retrieve recently-searched queries, ordered by descending date.
+// * @return a list containing recent searches
+// */
+// fun recentSearches(limit: Int): List {
+// val items: MutableList = mutableListOf()
+// var cursor: Cursor? = null
+// val db = clientProvider.get()
+// try {
+// cursor = db.query(
+// BASE_URI, ALL_FIELDS,
+// null, arrayOf(), "$COLUMN_LAST_USED DESC"
+// )
+// // fixme add a limit on the original query instead of falling out of the loop?
+// while (cursor != null && cursor.moveToNext() && cursor.position < limit) {
+// items.add(fromCursor(cursor).query)
+// }
+// } catch (e: RemoteException) {
+// throw RuntimeException(e)
+// } finally {
+// cursor?.close()
+// db.release()
+// }
+// return items
+// }
+//
+// /**
+// * It creates an Recent Searches object from data stored in the SQLite DB by using cursor
+// * @param cursor
+// * @return RecentSearch object
+// */
+// fun fromCursor(cursor: Cursor): RecentSearch {
+// var query = cursor.getString(COLUMN_NAME)
+//
+// if (query == null) {
+// query = ""
+// }
+//
+// return RecentSearch(
+// uriForId(cursor.getInt(COLUMN_ID)),
+// query,
+// Date(cursor.getLong(COLUMN_LAST_USED))
+// )
+// }
+//
+// /**
+// * This class contains the database table architechture for recent searches,
+// * It also contains queries and logic necessary to the create, update, delete this table.
+// */
+// private fun toContentValues(recentSearch: RecentSearch): ContentValues = contentValuesOf(
+// COLUMN_NAME to recentSearch.query,
+// COLUMN_LAST_USED to recentSearch.lastSearched.time
+// )
+//}
diff --git a/app/src/main/java/fr/free/nrw/commons/explore/recentsearches/RecentSearchesFragment.kt b/app/src/main/java/fr/free/nrw/commons/explore/recentsearches/RecentSearchesFragment.kt
index e7903c9ed7b..89f5d0f7ca2 100644
--- a/app/src/main/java/fr/free/nrw/commons/explore/recentsearches/RecentSearchesFragment.kt
+++ b/app/src/main/java/fr/free/nrw/commons/explore/recentsearches/RecentSearchesFragment.kt
@@ -25,7 +25,7 @@ import javax.inject.Inject
class RecentSearchesFragment : CommonsDaggerSupportFragment() {
@JvmField
@Inject
- var recentSearchesDao: RecentSearchesDao? = null
+ var recentSearchesDao: RecentSearchesRoomDao? = null
private var recentSearches: List = emptyList()
private lateinit var adapter: ArrayAdapter
@@ -37,7 +37,7 @@ class RecentSearchesFragment : CommonsDaggerSupportFragment() {
): View {
binding = FragmentSearchHistoryBinding.inflate(inflater, container, false)
- recentSearches = recentSearchesDao!!.recentSearches(10)
+ recentSearches = recentSearchesDao!!.recentSearches(10).blockingGet()
if (recentSearches.isEmpty()) {
binding!!.recentSearchesDeleteButton.visibility = View.GONE
@@ -77,7 +77,7 @@ class RecentSearchesFragment : CommonsDaggerSupportFragment() {
}
private fun setDeleteRecentPositiveButton(context: Context, dialog: DialogInterface) {
- recentSearchesDao!!.deleteAll()
+ recentSearchesDao!!.deleteAll().blockingAwait()
if (binding != null) {
binding!!.recentSearchesDeleteButton.visibility = View.GONE
binding!!.recentSearchesTextView.setText(R.string.no_recent_searches)
@@ -85,7 +85,7 @@ class RecentSearchesFragment : CommonsDaggerSupportFragment() {
getContext(), getString(R.string.search_history_deleted),
Toast.LENGTH_SHORT
).show()
- recentSearches = recentSearchesDao!!.recentSearches(10)
+ recentSearches = recentSearchesDao!!.recentSearches(10).blockingGet()
adapter = ArrayAdapter(context, R.layout.item_recent_searches, recentSearches)
binding!!.recentSearchesList.adapter = adapter
adapter.notifyDataSetChanged()
@@ -109,8 +109,8 @@ class RecentSearchesFragment : CommonsDaggerSupportFragment() {
}
private fun setDeletePositiveButton(context: Context, dialog: DialogInterface, position: Int) {
- recentSearchesDao!!.delete(recentSearchesDao!!.find(recentSearches[position])!!)
- recentSearches = recentSearchesDao!!.recentSearches(10)
+ recentSearchesDao!!.delete(recentSearchesDao!!.find(recentSearches[position]).blockingGet()!!).blockingAwait()
+ recentSearches = recentSearchesDao!!.recentSearches(10).blockingGet()
adapter = ArrayAdapter(
context, R.layout.item_recent_searches,
recentSearches
@@ -135,7 +135,7 @@ class RecentSearchesFragment : CommonsDaggerSupportFragment() {
* This method is called when search query is null to update Recent Searches
*/
fun updateRecentSearches() {
- recentSearches = recentSearchesDao!!.recentSearches(10)
+ recentSearches = recentSearchesDao!!.recentSearches(10).blockingGet()
adapter.notifyDataSetChanged()
if (recentSearches.isNotEmpty()) {
diff --git a/app/src/main/java/fr/free/nrw/commons/explore/recentsearches/RecentSearchesRoomDao.kt b/app/src/main/java/fr/free/nrw/commons/explore/recentsearches/RecentSearchesRoomDao.kt
index 8a11bc50668..b1e2a92bb7f 100644
--- a/app/src/main/java/fr/free/nrw/commons/explore/recentsearches/RecentSearchesRoomDao.kt
+++ b/app/src/main/java/fr/free/nrw/commons/explore/recentsearches/RecentSearchesRoomDao.kt
@@ -1,24 +1,77 @@
package fr.free.nrw.commons.explore.recentsearches
-import androidx.room.Dao
-import androidx.room.Insert
-import androidx.room.OnConflictStrategy
-import androidx.room.Query
+import androidx.room.*
+import fr.free.nrw.commons.explore.models.RecentSearch
import io.reactivex.Completable
import io.reactivex.Single
+import java.util.*
@Dao
-interface RecentSearchesRoomDao {
+abstract class RecentSearchesRoomDao {
@Query("SELECT * FROM recent_searches ORDER BY last_used DESC LIMIT :limit")
- fun getAll(limit: Int): Single>
+ abstract fun getAll(limit: Int): Single>
@Insert(onConflict = OnConflictStrategy.REPLACE)
- fun insert(recentSearch: RecentSearchRoomEntity)
+ abstract fun insert(recentSearch: RecentSearchRoomEntity): Single
+
+ @Update
+ abstract fun update(recentSearch: RecentSearchRoomEntity): Completable
@Query("SELECT * FROM recent_searches WHERE name = :query")
- fun findEntity(query: String): RecentSearchRoomEntity?
+ abstract fun findEntity(query: String): Single>
@Query("DELETE FROM recent_searches")
- fun deleteTable(): Completable
+ abstract fun deleteTable(): Completable
+
+ @Query("DELETE FROM recent_searches WHERE name = :name")
+ abstract fun deleteByName(name: String): Completable
+
+ fun recentSearches(limit: Int): Single> {
+ return getAll(limit).map { entities ->
+ entities.map { it.query }
+ }
+ }
+
+ fun find(query: String): io.reactivex.Maybe {
+ return findEntity(query).flatMapMaybe { entities ->
+ val entity = entities.firstOrNull()
+ if (entity != null) io.reactivex.Maybe.just(fromEntity(entity))
+ else io.reactivex.Maybe.empty()
+ }
+ }
+
+ fun delete(recentSearch: RecentSearch): Completable {
+ return deleteByName(recentSearch.query)
+ }
+
+ fun deleteAll(): Completable {
+ return deleteTable()
+ }
+
+ fun save(recentSearch: RecentSearch): Completable {
+ return findEntity(recentSearch.query).flatMapCompletable { entities ->
+ if (entities.isNotEmpty()) {
+ update(toEntity(recentSearch, entities[0].id))
+ } else {
+ insert(toEntity(recentSearch)).ignoreElement()
+ }
+ }
+ }
+
+ private fun toEntity(
+ recentSearch: RecentSearch,
+ id: Long = 0
+ ): RecentSearchRoomEntity = RecentSearchRoomEntity(
+ id = id,
+ query = recentSearch.query,
+ lastSearched = recentSearch.lastSearched
+ )
+
+ private fun fromEntity(
+ entity: RecentSearchRoomEntity
+ ): RecentSearch = RecentSearch(
+ query = entity.query,
+ lastSearched = entity.lastSearched
+ )
}
diff --git a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.kt b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.kt
index d1e1d2aad10..7f0337eb6a6 100644
--- a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.kt
+++ b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.kt
@@ -27,8 +27,8 @@ import fr.free.nrw.commons.Media
import fr.free.nrw.commons.R
import fr.free.nrw.commons.auth.SessionManager
import fr.free.nrw.commons.bookmarks.models.Bookmark
-import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesContentProvider
-import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesDao
+//import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesContentProvider
+import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesRoomDao
import fr.free.nrw.commons.contributions.Contribution
import fr.free.nrw.commons.contributions.MainActivity
import fr.free.nrw.commons.databinding.FragmentMediaDetailPagerBinding
@@ -58,7 +58,7 @@ class MediaDetailPagerFragment : CommonsDaggerSupportFragment(), OnPageChangeLis
MediaDetailFragment.Callback {
@JvmField
@Inject
- var bookmarkDao: BookmarkPicturesDao? = null
+ var bookmarkDao: BookmarkPicturesRoomDao? = null
@JvmField
@Inject
@@ -174,7 +174,7 @@ class MediaDetailPagerFragment : CommonsDaggerSupportFragment(), OnPageChangeLis
val mediaDetailFragment = adapter!!.currentMediaDetailFragment
when (item.itemId) {
R.id.menu_bookmark_current_image -> {
- val bookmarkExists = bookmarkDao!!.updateBookmark(bookmark!!)
+ val bookmarkExists = bookmarkDao!!.updateBookmark(bookmark!!).blockingGet()
val snackbar = if (bookmarkExists) Snackbar.make(
requireView(),
R.string.add_bookmark,
@@ -444,7 +444,6 @@ ${m.pageTitle.canonicalUri}"""
bookmark = Bookmark(
m.filename,
m.getAuthorOrUser(),
- BookmarkPicturesContentProvider.uriForName(m.filename!!)
)
updateBookmarkState(menu.findItem(R.id.menu_bookmark_current_image))
val contributionState = provider.getContributionStateAt(position)
@@ -512,7 +511,7 @@ ${m.pageTitle.canonicalUri}"""
}
private fun updateBookmarkState(item: MenuItem) {
- val isBookmarked = bookmarkDao!!.findBookmark(bookmark)
+ val isBookmarked = bookmarkDao!!.findBookmark(bookmark).blockingGet()
if (isBookmarked) {
if (removedItems.contains(binding!!.mediaDetailsPager.currentItem)) {
removedItems.remove(binding!!.mediaDetailsPager.currentItem)
diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/Place.java b/app/src/main/java/fr/free/nrw/commons/nearby/Place.java
index 4950074482d..8dfcb2fa2ff 100644
--- a/app/src/main/java/fr/free/nrw/commons/nearby/Place.java
+++ b/app/src/main/java/fr/free/nrw/commons/nearby/Place.java
@@ -5,9 +5,6 @@
import android.os.Parcelable;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.room.Embedded;
-import androidx.room.Entity;
-import androidx.room.PrimaryKey;
import fr.free.nrw.commons.location.LatLng;
import fr.free.nrw.commons.nearby.model.NearbyResultItem;
import fr.free.nrw.commons.utils.LocationUtils;
@@ -18,23 +15,16 @@
/**
* A single geolocated Wikidata item
*/
-@Entity(tableName = "place")
public class Place implements Parcelable {
-
public String language;
public String name;
private Label label;
private String longDescription;
- @Embedded
public LatLng location;
- @PrimaryKey @NonNull
public String entityID;
private String category;
public String pic;
- // exists boolean will tell whether the place exists or not,
- // For a place to be existing both destroyed and endTime property should be null but it is also not necessary for a non-existing place to have both properties either one property is enough (in such case that not given property will be considered as null).
public Boolean exists;
-
public String distance;
public Sitelinks siteLinks;
private boolean isMonument;
diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/PlaceDao.java b/app/src/main/java/fr/free/nrw/commons/nearby/PlaceDao.java
index 269384ffab7..45c83ef462d 100644
--- a/app/src/main/java/fr/free/nrw/commons/nearby/PlaceDao.java
+++ b/app/src/main/java/fr/free/nrw/commons/nearby/PlaceDao.java
@@ -22,7 +22,14 @@ public abstract class PlaceDao {
* @param place The Place object to be inserted.
*/
@Insert(onConflict = OnConflictStrategy.REPLACE)
- public abstract void saveSynchronous(Place place);
+ public abstract void saveSynchronous(PlaceRoomEntity place);
+
+ void saveSynchronous(final Place place) {
+ saveSynchronous(new PlaceRoomEntity(place.getLanguage(), place.getName(), place.getLabel(),
+ place.getLongDescription(), place.getLocation(), place.entityID, place.getCategory(),
+ place.pic, place.exists, place.distance, place.siteLinks,
+ place.isMonument(), place.getThumb()));
+ }
/**
* Retrieves a Place object from the database based on the provided entity ID.
diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/PlaceRoomEntity.kt b/app/src/main/java/fr/free/nrw/commons/nearby/PlaceRoomEntity.kt
new file mode 100644
index 00000000000..5ff248fd356
--- /dev/null
+++ b/app/src/main/java/fr/free/nrw/commons/nearby/PlaceRoomEntity.kt
@@ -0,0 +1,28 @@
+package fr.free.nrw.commons.nearby
+
+import androidx.room.Embedded
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+import fr.free.nrw.commons.location.LatLng
+
+/**
+ * Room entity for the place table.
+ */
+@Entity(tableName = "place")
+data class PlaceRoomEntity(
+ val language: String?,
+ val name: String?,
+ val label: Label?,
+ val longDescription: String?,
+ @Embedded
+ val location: LatLng?,
+ @PrimaryKey
+ val entityID: String,
+ val category: String?,
+ val pic: String?,
+ val exists: Boolean?,
+ val distance: String?,
+ val siteLinks: Sitelinks?,
+ val isMonument: Boolean,
+ val thumb: String?
+)
diff --git a/app/src/main/java/fr/free/nrw/commons/recentlanguages/RecentLanguagesRoomDao.kt b/app/src/main/java/fr/free/nrw/commons/recentlanguages/RecentLanguagesRoomDao.kt
index 71243c66484..3b157280155 100644
--- a/app/src/main/java/fr/free/nrw/commons/recentlanguages/RecentLanguagesRoomDao.kt
+++ b/app/src/main/java/fr/free/nrw/commons/recentlanguages/RecentLanguagesRoomDao.kt
@@ -1,23 +1,39 @@
package fr.free.nrw.commons.recentlanguages
-import androidx.room.Dao
-import androidx.room.Insert
-import androidx.room.OnConflictStrategy
-import androidx.room.Query
+import androidx.room.*
+import io.reactivex.Completable
import io.reactivex.Single
@Dao
-interface RecentLanguagesRoomDao {
+abstract class RecentLanguagesRoomDao {
@Query("SELECT * FROM recent_languages ORDER BY rowid DESC")
- fun getAll(): Single>
+ abstract fun getAll(): Single>
@Insert(onConflict = OnConflictStrategy.REPLACE)
- fun insert(language: RecentLanguageRoomEntity)
+ abstract fun insert(language: RecentLanguageRoomEntity): Completable
@Query("DELETE FROM recent_languages WHERE language_code = :languageCode")
- fun deleteRecentLanguage(languageCode: String)
+ abstract fun deleteRecentLanguage(languageCode: String): Completable
@Query("SELECT EXISTS (SELECT 1 FROM recent_languages WHERE language_code = :languageCode)")
- fun findRecentLanguage(languageCode: String): Boolean
+ abstract fun findRecentLanguage(languageCode: String): Single
+
+ fun getRecentLanguages(): Single> {
+ return getAll().map { entities ->
+ entities.map { fromEntity(it) }
+ }
+ }
+
+ fun addRecentLanguage(language: Language): Completable {
+ return insert(toEntity(language))
+ }
+
+ private fun toEntity(language: Language): RecentLanguageRoomEntity {
+ return RecentLanguageRoomEntity(language.languageName, language.languageCode)
+ }
+
+ private fun fromEntity(entity: RecentLanguageRoomEntity): Language {
+ return Language(entity.languageName, entity.languageCode)
+ }
}
diff --git a/app/src/main/java/fr/free/nrw/commons/review/ReviewDao.kt b/app/src/main/java/fr/free/nrw/commons/review/ReviewDao.kt
index 1dc9b6ae8b5..2a87395d0bf 100644
--- a/app/src/main/java/fr/free/nrw/commons/review/ReviewDao.kt
+++ b/app/src/main/java/fr/free/nrw/commons/review/ReviewDao.kt
@@ -1,23 +1,27 @@
package fr.free.nrw.commons.review
-import androidx.room.Dao
-import androidx.room.Insert
-import androidx.room.OnConflictStrategy
-import androidx.room.Query
+import androidx.room.*
/**
* Dao interface for reviewed images database
*/
@Dao
-interface ReviewDao {
+abstract class ReviewDao {
/**
- * Inserts reviewed/skipped image identifier into the database
+ * Inserts reviewed/skipped image identifier into the database internally
*
- * @param reviewEntity
+ * @param reviewRoomEntity
*/
@Insert(onConflict = OnConflictStrategy.IGNORE)
- fun insert(reviewEntity: ReviewEntity)
+ protected abstract fun insertInternal(reviewRoomEntity: ReviewRoomEntity)
+
+ /**
+ * Public method to insert using domain model
+ */
+ fun insert(reviewImage: ReviewImage) {
+ insertInternal(toEntity(reviewImage))
+ }
/**
* Checks if the image has already been reviewed/skipped by the user
@@ -27,5 +31,8 @@ interface ReviewDao {
* @return
*/
@Query("SELECT EXISTS (SELECT * from `reviewed-images` where imageId = (:imageId))")
- fun isReviewedAlready(imageId: String): Boolean
+ abstract fun isReviewedAlready(imageId: String): Boolean
+
+ private fun toEntity(reviewImage: ReviewImage): ReviewRoomEntity =
+ ReviewRoomEntity(imageId = reviewImage.imageId)
}
diff --git a/app/src/main/java/fr/free/nrw/commons/review/ReviewHelper.kt b/app/src/main/java/fr/free/nrw/commons/review/ReviewHelper.kt
index 3ad15d8bfcb..72dfc906cc1 100644
--- a/app/src/main/java/fr/free/nrw/commons/review/ReviewHelper.kt
+++ b/app/src/main/java/fr/free/nrw/commons/review/ReviewHelper.kt
@@ -132,7 +132,7 @@ class ReviewHelper
*/
fun addViewedImagesToDB(imageId: String?) {
Completable
- .fromAction { imageId?.let { ReviewEntity(it) }?.let { dao!!.insert(it) } }
+ .fromAction { imageId?.let { ReviewImage(it) }?.let { dao!!.insert(it) } }
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
diff --git a/app/src/main/java/fr/free/nrw/commons/review/ReviewImage.kt b/app/src/main/java/fr/free/nrw/commons/review/ReviewImage.kt
new file mode 100644
index 00000000000..2ef83b34bf0
--- /dev/null
+++ b/app/src/main/java/fr/free/nrw/commons/review/ReviewImage.kt
@@ -0,0 +1,8 @@
+package fr.free.nrw.commons.review
+
+/**
+ * Domain model to store reviewed/skipped images identifier
+ */
+data class ReviewImage(
+ val imageId: String
+)
diff --git a/app/src/main/java/fr/free/nrw/commons/review/ReviewRoomEntity.kt b/app/src/main/java/fr/free/nrw/commons/review/ReviewRoomEntity.kt
new file mode 100644
index 00000000000..87e6707c57d
--- /dev/null
+++ b/app/src/main/java/fr/free/nrw/commons/review/ReviewRoomEntity.kt
@@ -0,0 +1,13 @@
+package fr.free.nrw.commons.review
+
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+
+/**
+ * Room entity for the reviewed-images table.
+ */
+@Entity(tableName = "reviewed-images")
+data class ReviewRoomEntity(
+ @PrimaryKey
+ val imageId: String
+)
diff --git a/app/src/main/java/fr/free/nrw/commons/settings/SettingsFragment.kt b/app/src/main/java/fr/free/nrw/commons/settings/SettingsFragment.kt
index c38ed1ecb8c..9711bcb42dc 100644
--- a/app/src/main/java/fr/free/nrw/commons/settings/SettingsFragment.kt
+++ b/app/src/main/java/fr/free/nrw/commons/settings/SettingsFragment.kt
@@ -46,7 +46,7 @@ import fr.free.nrw.commons.location.LocationServiceManager
import fr.free.nrw.commons.logging.CommonsLogSender
import fr.free.nrw.commons.recentlanguages.Language
import fr.free.nrw.commons.recentlanguages.RecentLanguagesAdapter
-import fr.free.nrw.commons.recentlanguages.RecentLanguagesDao
+import fr.free.nrw.commons.recentlanguages.RecentLanguagesRoomDao
import fr.free.nrw.commons.upload.LanguagesAdapter
import fr.free.nrw.commons.utils.DialogUtil
import fr.free.nrw.commons.utils.PermissionUtils
@@ -67,7 +67,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
lateinit var commonsLogSender: CommonsLogSender
@Inject
- lateinit var recentLanguagesDao: RecentLanguagesDao
+ lateinit var recentLanguagesDao: RecentLanguagesRoomDao
@Inject
lateinit var contributionController: ContributionController
@@ -342,7 +342,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
private fun prepareAppLanguages(keyListPreference: String) {
// Gets current language code from shared preferences
val languageCode = getCurrentLanguageCode(keyListPreference)
- val recentLanguages = recentLanguagesDao.getRecentLanguages()
+ val recentLanguages = recentLanguagesDao.getRecentLanguages().blockingGet()
val selectedLanguages = hashMapOf()
if (keyListPreference == "appUiDefaultLanguagePref") {
@@ -402,11 +402,11 @@ class SettingsFragment : PreferenceFragmentCompat() {
listView.setOnItemClickListener { adapterView, _, position, _ ->
val lCode = (adapterView.adapter as LanguagesAdapter).getLanguageCode(position)
val languageName = (adapterView.adapter as LanguagesAdapter).getLanguageName(position)
- val isExists = recentLanguagesDao.findRecentLanguage(lCode)
+ val isExists = recentLanguagesDao.findRecentLanguage(lCode).blockingGet()
if (isExists) {
- recentLanguagesDao.deleteRecentLanguage(lCode)
+ recentLanguagesDao.deleteRecentLanguage(lCode).blockingAwait()
}
- recentLanguagesDao.addRecentLanguage(Language(languageName, lCode))
+ recentLanguagesDao.addRecentLanguage(Language(languageName, lCode)).blockingAwait()
saveLanguageValue(lCode, keyListPreference)
val defLocale = createLocale(lCode)
if (keyListPreference == "appUiDefaultLanguagePref") {
@@ -451,7 +451,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
separator?.visibility = View.VISIBLE
val recentLanguagesAdapter = RecentLanguagesAdapter(
requireActivity(),
- recentLanguagesDao.getRecentLanguages(),
+ recentLanguagesDao.getRecentLanguages().blockingGet(),
selectedLanguages
)
languageHistoryListView?.adapter = recentLanguagesAdapter
@@ -469,11 +469,11 @@ class SettingsFragment : PreferenceFragmentCompat() {
) {
val recentLanguageCode = (adapterView.adapter as RecentLanguagesAdapter).getLanguageCode(position)
val recentLanguageName = (adapterView.adapter as RecentLanguagesAdapter).getLanguageName(position)
- val isExists = recentLanguagesDao.findRecentLanguage(recentLanguageCode)
+ val isExists = recentLanguagesDao.findRecentLanguage(recentLanguageCode).blockingGet()
if (isExists) {
- recentLanguagesDao.deleteRecentLanguage(recentLanguageCode)
+ recentLanguagesDao.deleteRecentLanguage(recentLanguageCode).blockingAwait()
}
- recentLanguagesDao.addRecentLanguage(Language(recentLanguageName, recentLanguageCode))
+ recentLanguagesDao.addRecentLanguage(Language(recentLanguageName, recentLanguageCode)).blockingAwait()
saveLanguageValue(recentLanguageCode, keyListPreference)
val defLocale = createLocale(recentLanguageCode)
if (keyListPreference == "appUiDefaultLanguagePref") {
diff --git a/app/src/main/java/fr/free/nrw/commons/upload/UploadMediaDetailAdapter.kt b/app/src/main/java/fr/free/nrw/commons/upload/UploadMediaDetailAdapter.kt
index b19da15e6b0..9c4f962b03c 100644
--- a/app/src/main/java/fr/free/nrw/commons/upload/UploadMediaDetailAdapter.kt
+++ b/app/src/main/java/fr/free/nrw/commons/upload/UploadMediaDetailAdapter.kt
@@ -32,7 +32,7 @@ import fr.free.nrw.commons.R
import fr.free.nrw.commons.databinding.RowItemDescriptionBinding
import fr.free.nrw.commons.recentlanguages.Language
import fr.free.nrw.commons.recentlanguages.RecentLanguagesAdapter
-import fr.free.nrw.commons.recentlanguages.RecentLanguagesDao
+import fr.free.nrw.commons.recentlanguages.RecentLanguagesRoomDao
import fr.free.nrw.commons.utils.AbstractTextWatcher
import timber.log.Timber
import java.util.Locale
@@ -50,7 +50,7 @@ class UploadMediaDetailAdapter : RecyclerView.Adapter
private var selectedVoiceIcon: SelectedVoiceIcon? = null
- var recentLanguagesDao: RecentLanguagesDao
+ var recentLanguagesDao: RecentLanguagesRoomDao
var callback: Callback? = null
var eventListener: EventListener? = null
var items: List
@@ -65,7 +65,7 @@ class UploadMediaDetailAdapter : RecyclerView.Adapter
) {
uploadMediaDetails = ArrayList()
@@ -80,7 +80,7 @@ class UploadMediaDetailAdapter : RecyclerView.Adapter,
- recentLanguagesDao: RecentLanguagesDao,
+ recentLanguagesDao: RecentLanguagesRoomDao,
voiceInputResultLauncher: ActivityResultLauncher
) {
this.uploadMediaDetails = uploadMediaDetails
@@ -298,7 +298,7 @@ class UploadMediaDetailAdapter : RecyclerView.Adapter
+ protected abstract fun getAllDepictsInternal(): List
+
+ fun getAllDepicts(): List =
+ getAllDepictsInternal().map { fromEntity(it) }
@Query("Select * From depicts_table order by lastUsed DESC LIMIT :n OFFSET 10")
- abstract suspend fun getDepictsForDeletion(n: Int): List
+ protected abstract fun getDepictsForDeletionInternal(n: Int): List
- @Delete
- abstract suspend fun delete(depicts: Depicts)
+ fun getDepictsForDeletion(n: Int): List =
+ getDepictsForDeletionInternal(n).map { fromEntity(it) }
/**
* Gets all Depicts objects from the database, ordered by lastUsed in descending order.
@@ -43,16 +51,6 @@ abstract class DepictsDao {
getAllDepicts()
}
- /**
- * Inserts a Depicts object into the database.
- *
- * @param depictedItem The Depicts object to insert.
- */
- fun insertDepict(depictedItem: Depicts) =
- CoroutineScope(Dispatchers.IO).launch {
- insert(depictedItem)
- }
-
/**
* Gets a list of Depicts objects that need to be deleted from the database.
*
@@ -64,16 +62,26 @@ abstract class DepictsDao {
getDepictsForDeletion(n)
}
- /**
- * Deletes a Depicts object from the database.
- *
- * @param depicts The Depicts object to delete.
- */
+ @Delete
+ protected abstract fun deleteInternal(depicts: DepictsRoomEntity)
+
fun deleteDepicts(depicts: Depicts) =
CoroutineScope(Dispatchers.IO).launch {
- delete(depicts)
+ deleteInternal(toEntity(depicts))
}
+ private fun toEntity(depicts: Depicts): DepictsRoomEntity =
+ DepictsRoomEntity(
+ item = depicts.item,
+ lastUsed = depicts.lastUsed
+ )
+
+ private fun fromEntity(entity: DepictsRoomEntity): Depicts =
+ Depicts(
+ item = entity.item,
+ lastUsed = entity.lastUsed
+ )
+
/**
* Saves a list of DepictedItems in the DepictsRoomDataBase.
*/
diff --git a/app/src/main/java/fr/free/nrw/commons/upload/depicts/DepictsRoomEntity.kt b/app/src/main/java/fr/free/nrw/commons/upload/depicts/DepictsRoomEntity.kt
new file mode 100644
index 00000000000..55535c47d46
--- /dev/null
+++ b/app/src/main/java/fr/free/nrw/commons/upload/depicts/DepictsRoomEntity.kt
@@ -0,0 +1,15 @@
+package fr.free.nrw.commons.upload.depicts
+
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+import fr.free.nrw.commons.upload.structure.depictions.DepictedItem
+import java.util.Date
+
+/**
+ * Room entity for the depicts_table.
+ */
+@Entity(tableName = "depicts_table")
+data class DepictsRoomEntity(
+ @PrimaryKey val item: DepictedItem,
+ val lastUsed: Date
+)
diff --git a/app/src/main/java/fr/free/nrw/commons/upload/mediaDetails/UploadMediaDetailFragment.kt b/app/src/main/java/fr/free/nrw/commons/upload/mediaDetails/UploadMediaDetailFragment.kt
index 8c2faff3433..8fc056526c3 100644
--- a/app/src/main/java/fr/free/nrw/commons/upload/mediaDetails/UploadMediaDetailFragment.kt
+++ b/app/src/main/java/fr/free/nrw/commons/upload/mediaDetails/UploadMediaDetailFragment.kt
@@ -34,7 +34,7 @@ import fr.free.nrw.commons.location.LatLng
import fr.free.nrw.commons.locationpicker.LocationPicker
import fr.free.nrw.commons.locationpicker.LocationPicker.getCameraPosition
import fr.free.nrw.commons.nearby.Place
-import fr.free.nrw.commons.recentlanguages.RecentLanguagesDao
+import fr.free.nrw.commons.recentlanguages.RecentLanguagesRoomDao
import fr.free.nrw.commons.settings.Prefs
import fr.free.nrw.commons.upload.ImageCoordinates
import fr.free.nrw.commons.upload.SimilarImageDialogFragment
@@ -75,7 +75,7 @@ class UploadMediaDetailFragment : UploadBaseFragment(), UploadMediaDetailsContra
lateinit var defaultKvStore: JsonKvStore
@Inject
- lateinit var recentLanguagesDao: RecentLanguagesDao
+ lateinit var recentLanguagesDao: RecentLanguagesRoomDao
/**
* True when user removes location from the current image
diff --git a/app/src/main/java/fr/free/nrw/commons/upload/structure/depictions/DepictedItem.kt b/app/src/main/java/fr/free/nrw/commons/upload/structure/depictions/DepictedItem.kt
index 4ae366535f6..0bc41eef89d 100644
--- a/app/src/main/java/fr/free/nrw/commons/upload/structure/depictions/DepictedItem.kt
+++ b/app/src/main/java/fr/free/nrw/commons/upload/structure/depictions/DepictedItem.kt
@@ -1,8 +1,6 @@
package fr.free.nrw.commons.upload.structure.depictions
import android.os.Parcelable
-import androidx.room.Entity
-import androidx.room.PrimaryKey
import fr.free.nrw.commons.category.CategoryItem
import fr.free.nrw.commons.nearby.Place
import fr.free.nrw.commons.upload.WikidataItem
@@ -25,7 +23,6 @@ const val THUMB_IMAGE_SIZE = "70px"
* Model class for Depicted Item in Upload and Explore
*/
@Parcelize
-@Entity
data class DepictedItem constructor(
override val name: String,
val description: String?,
@@ -33,7 +30,7 @@ data class DepictedItem constructor(
val instanceOfs: List,
val commonsCategories: List,
var isSelected: Boolean,
- @PrimaryKey override val id: String,
+ override val id: String,
) : WikidataItem,
Parcelable {
constructor(entity: Entities.Entity) : this(
diff --git a/app/src/test/kotlin/fr/free/nrw/commons/TestCommonsApplication.kt b/app/src/test/kotlin/fr/free/nrw/commons/TestCommonsApplication.kt
index c0e3bda0831..c338da96414 100644
--- a/app/src/test/kotlin/fr/free/nrw/commons/TestCommonsApplication.kt
+++ b/app/src/test/kotlin/fr/free/nrw/commons/TestCommonsApplication.kt
@@ -48,13 +48,6 @@ class MockCommonsApplicationModule(appContext: Context) : CommonsApplicationModu
val contributionClient: ContentProviderClient = mock()
val modificationClient: ContentProviderClient = mock()
val uploadPrefs: JsonKvStore = mock()
-
- override fun provideCategoryContentProviderClient(context: Context): ContentProviderClient = categoryClient
-
- override fun provideContributionContentProviderClient(context: Context): ContentProviderClient = contributionClient
-
- override fun provideModificationContentProviderClient(context: Context): ContentProviderClient = modificationClient
-
override fun providesDefaultKvStore(context: Context, gson: Gson): JsonKvStore = defaultSharedPreferences
override fun provideLocationServiceManager(context: Context): LocationServiceManager = locationServiceManager
diff --git a/app/src/test/kotlin/fr/free/nrw/commons/bookmarks/items/BookmarkItemsControllerTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/bookmarks/items/BookmarkItemsControllerTest.kt
index 38bf6b2678e..c413e7ae69f 100644
--- a/app/src/test/kotlin/fr/free/nrw/commons/bookmarks/items/BookmarkItemsControllerTest.kt
+++ b/app/src/test/kotlin/fr/free/nrw/commons/bookmarks/items/BookmarkItemsControllerTest.kt
@@ -9,11 +9,12 @@ import org.junit.Test
import org.mockito.InjectMocks
import org.mockito.Mock
import org.mockito.MockitoAnnotations
+import io.reactivex.Single
import java.util.ArrayList
class BookmarkItemsControllerTest {
@Mock
- var bookmarkDao: BookmarkItemsDao? = null
+ var bookmarkDao: BookmarkItemsRoomDao? = null
@InjectMocks
lateinit var bookmarkItemsController: BookmarkItemsController
@@ -22,7 +23,7 @@ class BookmarkItemsControllerTest {
fun setup() {
MockitoAnnotations.openMocks(this)
whenever(bookmarkDao!!.getAllBookmarksItems())
- .thenReturn(mockBookmarkList)
+ .thenReturn(Single.just(mockBookmarkList))
}
/**
diff --git a/app/src/test/kotlin/fr/free/nrw/commons/bookmarks/items/BookmarkItemsDaoTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/bookmarks/items/BookmarkItemsDaoTest.kt
index 4754e82affc..a8491392119 100644
--- a/app/src/test/kotlin/fr/free/nrw/commons/bookmarks/items/BookmarkItemsDaoTest.kt
+++ b/app/src/test/kotlin/fr/free/nrw/commons/bookmarks/items/BookmarkItemsDaoTest.kt
@@ -1,74 +1,39 @@
package fr.free.nrw.commons.bookmarks.items
-import android.content.ContentProviderClient
-import android.content.ContentValues
-import android.database.Cursor
-import android.database.MatrixCursor
-import android.net.Uri
-import android.os.RemoteException
-import androidx.sqlite.db.SupportSQLiteDatabase
-import com.nhaarman.mockitokotlin2.any
-import com.nhaarman.mockitokotlin2.anyOrNull
-import com.nhaarman.mockitokotlin2.argumentCaptor
-import com.nhaarman.mockitokotlin2.eq
-import com.nhaarman.mockitokotlin2.inOrder
-import com.nhaarman.mockitokotlin2.isA
-import com.nhaarman.mockitokotlin2.isNull
-import com.nhaarman.mockitokotlin2.mock
-import com.nhaarman.mockitokotlin2.verify
-import com.nhaarman.mockitokotlin2.whenever
+import androidx.room.Room.inMemoryDatabaseBuilder
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
import fr.free.nrw.commons.TestCommonsApplication
-import fr.free.nrw.commons.bookmarks.items.BookmarkItemsTable.COLUMN_CATEGORIES_DESCRIPTION_LIST
-import fr.free.nrw.commons.bookmarks.items.BookmarkItemsTable.COLUMN_CATEGORIES_NAME_LIST
-import fr.free.nrw.commons.bookmarks.items.BookmarkItemsTable.COLUMN_CATEGORIES_THUMBNAIL_LIST
-import fr.free.nrw.commons.bookmarks.items.BookmarkItemsTable.COLUMN_DESCRIPTION
-import fr.free.nrw.commons.bookmarks.items.BookmarkItemsTable.COLUMN_ID
-import fr.free.nrw.commons.bookmarks.items.BookmarkItemsTable.COLUMN_IMAGE
-import fr.free.nrw.commons.bookmarks.items.BookmarkItemsTable.COLUMN_INSTANCE_LIST
-import fr.free.nrw.commons.bookmarks.items.BookmarkItemsTable.COLUMN_IS_SELECTED
-import fr.free.nrw.commons.bookmarks.items.BookmarkItemsTable.COLUMN_NAME
-import fr.free.nrw.commons.bookmarks.items.BookmarkItemsTable.CREATE_TABLE_STATEMENT
-import fr.free.nrw.commons.bookmarks.items.BookmarkItemsTable.DROP_TABLE_STATEMENT
-import fr.free.nrw.commons.bookmarks.items.BookmarkItemsTable.onCreate
-import fr.free.nrw.commons.bookmarks.items.BookmarkItemsTable.onDelete
-import fr.free.nrw.commons.bookmarks.items.BookmarkItemsTable.onUpdate
import fr.free.nrw.commons.category.CategoryItem
+import fr.free.nrw.commons.db.AppDatabase
import fr.free.nrw.commons.upload.structure.depictions.DepictedItem
-import org.junit.Assert
+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.Mockito.verifyNoInteractions
-import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
+import org.robolectric.annotation.LooperMode
-@RunWith(RobolectricTestRunner::class)
+@RunWith(AndroidJUnit4::class)
@Config(sdk = [21], application = TestCommonsApplication::class)
+@LooperMode(LooperMode.Mode.PAUSED)
class BookmarkItemsDaoTest {
- private val columns =
- arrayOf(
- COLUMN_NAME,
- COLUMN_DESCRIPTION,
- COLUMN_IMAGE,
- COLUMN_INSTANCE_LIST,
- COLUMN_CATEGORIES_NAME_LIST,
- COLUMN_CATEGORIES_DESCRIPTION_LIST,
- COLUMN_CATEGORIES_THUMBNAIL_LIST,
- COLUMN_IS_SELECTED,
- COLUMN_ID,
- )
- private val client: ContentProviderClient = mock()
- private val database: SupportSQLiteDatabase = mock()
- private val captor = argumentCaptor()
-
- private lateinit var testObject: BookmarkItemsDao
+ private lateinit var bookmarkItemsRoomDao: BookmarkItemsRoomDao
+ private lateinit var database: AppDatabase
private lateinit var exampleItemBookmark: DepictedItem
- /**
- * Set up Test DepictedItem and BookmarkItemsDao
- */
@Before
- fun setUp() {
+ fun createDb() {
+ database =
+ inMemoryDatabaseBuilder(
+ context = ApplicationProvider.getApplicationContext(),
+ klass = AppDatabase::class.java,
+ ).allowMainThreadQueries().build()
+ bookmarkItemsRoomDao = database.bookmarkItemsRoomDao()
+
exampleItemBookmark =
DepictedItem(
"itemName",
@@ -86,330 +51,49 @@ class BookmarkItemsDaoTest {
false,
"itemID",
)
- testObject = BookmarkItemsDao { client }
- }
-
- @Test
- fun createTable() {
- onCreate(database)
- verify(database).execSQL(CREATE_TABLE_STATEMENT)
- }
-
- @Test
- fun deleteTable() {
- onDelete(database)
- inOrder(database) {
- verify(database).execSQL(DROP_TABLE_STATEMENT)
- verify(database).execSQL(CREATE_TABLE_STATEMENT)
- }
}
- @Test
- fun createFromCursor() {
- createCursor(1).let { cursor ->
- cursor.moveToFirst()
- testObject.fromCursor(cursor).let {
- Assert.assertEquals("itemName", it.name)
- Assert.assertEquals("itemDescription", it.description)
- Assert.assertEquals("itemImageUrl", it.imageUrl)
- Assert.assertEquals(listOf("instance"), it.instanceOfs)
- Assert.assertEquals(
- listOf(
- CategoryItem(
- "category name",
- "category description",
- "category thumbnail",
- false,
- ),
- ),
- it.commonsCategories,
- )
- Assert.assertEquals(false, it.isSelected)
- Assert.assertEquals("itemID", it.id)
- }
- }
+ @After
+ fun closeDb() {
+ database.close()
}
@Test
fun getAllItemsBookmarks() {
- whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull()))
- .thenReturn(createCursor(14))
-
- val result = testObject.getAllBookmarksItems()
-
- Assert.assertEquals(14, (result.size))
- }
-
- @Test(expected = RuntimeException::class)
- fun getAllItemsBookmarksTranslatesExceptions() {
- whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull())).thenThrow(
- RemoteException(""),
- )
- testObject.getAllBookmarksItems()
- }
-
- @Test
- fun getAllItemsBookmarksReturnsEmptyList_emptyCursor() {
- whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull()))
- .thenReturn(createCursor(0))
- Assert.assertTrue(testObject.getAllBookmarksItems().isEmpty())
- }
-
- @Test
- fun getAllItemsBookmarksReturnsEmptyList_nullCursor() {
- whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull())).thenReturn(null)
- Assert.assertTrue(testObject.getAllBookmarksItems().isEmpty())
- }
-
- @Test
- fun cursorsAreClosedAfterGetAllItemsBookmarksQuery() {
- val mockCursor: Cursor = mock()
- whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull())).thenReturn(mockCursor)
- whenever(mockCursor.moveToFirst()).thenReturn(false)
-
- testObject.getAllBookmarksItems()
+ for (i in 1..5) {
+ val item = exampleItemBookmark.copy(id = "item$i")
+ bookmarkItemsRoomDao.updateBookmarkItem(item).blockingGet()
+ }
- verify(mockCursor).close()
+ val result = bookmarkItemsRoomDao.getAllBookmarksItems().blockingGet()
+ assertEquals(5, result.size)
}
@Test
fun updateNewItemBookmark() {
- whenever(client.insert(any(), any())).thenReturn(Uri.EMPTY)
- whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(null)
-
- Assert.assertTrue(testObject.updateBookmarkItem(exampleItemBookmark))
- verify(client).insert(eq(BookmarkItemsContentProvider.BASE_URI), captor.capture())
- captor.firstValue.let { cv ->
- Assert.assertEquals(9, cv.size())
- Assert.assertEquals(
- exampleItemBookmark.name,
- cv.getAsString(COLUMN_NAME),
- )
- Assert.assertEquals(
- exampleItemBookmark.description,
- cv.getAsString(COLUMN_DESCRIPTION),
- )
- Assert.assertEquals(
- exampleItemBookmark.imageUrl,
- cv.getAsString(COLUMN_IMAGE),
- )
- Assert.assertEquals(
- exampleItemBookmark.instanceOfs[0],
- cv.getAsString(COLUMN_INSTANCE_LIST),
- )
- Assert.assertEquals(
- exampleItemBookmark.commonsCategories[0].name,
- cv.getAsString(COLUMN_CATEGORIES_NAME_LIST),
- )
- Assert.assertEquals(
- exampleItemBookmark.commonsCategories[0].description,
- cv.getAsString(COLUMN_CATEGORIES_DESCRIPTION_LIST),
- )
- Assert.assertEquals(
- exampleItemBookmark.commonsCategories[0].thumbnail,
- cv.getAsString(COLUMN_CATEGORIES_THUMBNAIL_LIST),
- )
- Assert.assertEquals(
- exampleItemBookmark.isSelected,
- cv.getAsBoolean(COLUMN_IS_SELECTED),
- )
- Assert.assertEquals(
- exampleItemBookmark.id,
- cv.getAsString(COLUMN_ID),
- )
- }
+ assertTrue(bookmarkItemsRoomDao.updateBookmarkItem(exampleItemBookmark).blockingGet())
+ assertTrue(bookmarkItemsRoomDao.findBookmarkItem(exampleItemBookmark.id).blockingGet())
}
@Test
fun updateExistingItemBookmark() {
- whenever(client.delete(isA(), isNull(), isNull())).thenReturn(1)
- whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(createCursor(1))
+ // First insert
+ bookmarkItemsRoomDao.updateBookmarkItem(exampleItemBookmark).blockingGet()
+ assertTrue(bookmarkItemsRoomDao.findBookmarkItem(exampleItemBookmark.id).blockingGet())
- Assert.assertFalse(testObject.updateBookmarkItem(exampleItemBookmark))
- verify(client).delete(
- eq(BookmarkItemsContentProvider.uriForName(exampleItemBookmark.id)),
- isNull(),
- isNull(),
- )
+ // Second update should remove it (toggle behavior)
+ assertFalse(bookmarkItemsRoomDao.updateBookmarkItem(exampleItemBookmark).blockingGet())
+ assertFalse(bookmarkItemsRoomDao.findBookmarkItem(exampleItemBookmark.id).blockingGet())
}
@Test
fun findExistingItemBookmark() {
- whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(createCursor(1))
- Assert.assertTrue(testObject.findBookmarkItem(exampleItemBookmark.id))
- }
-
- @Test(expected = RuntimeException::class)
- fun findItemBookmarkTranslatesExceptions() {
- whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull())).thenThrow(
- RemoteException(""),
- )
- testObject.findBookmarkItem(exampleItemBookmark.id)
+ bookmarkItemsRoomDao.updateBookmarkItem(exampleItemBookmark).blockingGet()
+ assertTrue(bookmarkItemsRoomDao.findBookmarkItem(exampleItemBookmark.id).blockingGet())
}
@Test
- fun findNotExistingItemBookmarkReturnsNull_emptyCursor() {
- whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(createCursor(0))
- Assert.assertFalse(testObject.findBookmarkItem(exampleItemBookmark.id))
+ fun findNotExistingItemBookmark() {
+ assertFalse(bookmarkItemsRoomDao.findBookmarkItem(exampleItemBookmark.id).blockingGet())
}
-
- @Test
- fun findNotExistingItemBookmarkReturnsNull_nullCursor() {
- whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(null)
- Assert.assertFalse(testObject.findBookmarkItem(exampleItemBookmark.id))
- }
-
- @Test
- fun cursorsAreClosedAfterFindItemBookmarkQuery() {
- val mockCursor: Cursor = mock()
- whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(mockCursor)
- whenever(mockCursor.moveToFirst()).thenReturn(false)
-
- testObject.findBookmarkItem(exampleItemBookmark.id)
-
- verify(mockCursor).close()
- }
-
- @Test
- fun migrateTableVersionFrom_v1_to_v2() {
- onUpdate(database, 1, 2)
- // Table didn't exist before v5
- 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 didn't exist before v5
- verifyNoInteractions(database)
- }
-
- @Test
- fun migrateTableVersionFrom_v4_to_v5() {
- onUpdate(database, 4, 5)
- // Table didn't change in version 5
- verifyNoInteractions(database)
- }
-
- @Test
- fun migrateTableVersionFrom_v5_to_v6() {
- onUpdate(database, 5, 6)
- // Table didn't change in version 6
- verifyNoInteractions(database)
- }
-
- @Test
- fun migrateTableVersionFrom_v6_to_v7() {
- onUpdate(database, 6, 7)
- // Table didn't change in version 7
- verifyNoInteractions(database)
- }
-
- @Test
- fun migrateTableVersionFrom_v7_to_v8() {
- onUpdate(database, 7, 8)
- // Table didn't change in version 8
- verifyNoInteractions(database)
- }
-
- @Test
- fun migrateTableVersionFrom_v8_to_v9() {
- onUpdate(database, 8, 9)
- // Table didn't change in version 9
- verifyNoInteractions(database)
- }
-
- @Test
- fun migrateTableVersionFrom_v9_to_v10() {
- onUpdate(database, 9, 10)
- // Table didn't change in version 10
- verifyNoInteractions(database)
- }
-
- @Test
- fun migrateTableVersionFrom_v10_to_v11() {
- onUpdate(database, 10, 11)
- // Table didn't change in version 11
- verifyNoInteractions(database)
- }
-
- @Test
- fun migrateTableVersionFrom_v11_to_v12() {
- onUpdate(database, 11, 12)
- // Table didn't change in version 12
- verifyNoInteractions(database)
- }
-
- @Test
- fun migrateTableVersionFrom_v12_to_v13() {
- onUpdate(database, 12, 13)
- // Table didn't change in version 13
- verifyNoInteractions(database)
- }
-
- @Test
- fun migrateTableVersionFrom_v13_to_v14() {
- onUpdate(database, 13, 14)
- // Table didn't change in version 14
- verifyNoInteractions(database)
- }
-
- @Test
- fun migrateTableVersionFrom_v14_to_v15() {
- onUpdate(database, 14, 15)
- // Table didn't change in version 15
- verifyNoInteractions(database)
- }
-
- @Test
- fun migrateTableVersionFrom_v15_to_v16() {
- onUpdate(database, 15, 16)
- // Table didn't change in version 16
- verifyNoInteractions(database)
- }
-
- @Test
- fun migrateTableVersionFrom_v16_to_v17() {
- onUpdate(database, 16, 17)
- // Table didn't change in version 17
- verifyNoInteractions(database)
- }
-
- @Test
- fun migrateTableVersionFrom_v18_to_v19() {
- onUpdate(database, 18, 19)
- verify(database).execSQL(CREATE_TABLE_STATEMENT)
- }
-
- @Test
- fun migrateTableVersionFrom_v19_to_v19() {
- onUpdate(database, 19, 19)
- verifyNoInteractions(database)
- }
-
- private fun createCursor(rowCount: Int) =
- MatrixCursor(columns, rowCount).apply {
- for (i in 0 until rowCount) {
- addRow(
- listOf(
- "itemName",
- "itemDescription",
- "itemImageUrl",
- "instance",
- "category name",
- "category description",
- "category thumbnail",
- false,
- "itemID",
- ),
- )
- }
- }
}
diff --git a/app/src/test/kotlin/fr/free/nrw/commons/bookmarks/locations/BookMarkLocationDaoTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/bookmarks/locations/BookMarkLocationDaoTest.kt
index 71e7bdd682c..32d922e70cf 100644
--- a/app/src/test/kotlin/fr/free/nrw/commons/bookmarks/locations/BookMarkLocationDaoTest.kt
+++ b/app/src/test/kotlin/fr/free/nrw/commons/bookmarks/locations/BookMarkLocationDaoTest.kt
@@ -1,23 +1,7 @@
package fr.free.nrw.commons.bookmarks.locations
-import android.content.ContentProviderClient
-import android.content.ContentValues
-import android.database.Cursor
-import android.database.MatrixCursor
-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
-import com.nhaarman.mockitokotlin2.eq
-import com.nhaarman.mockitokotlin2.inOrder
-import com.nhaarman.mockitokotlin2.isA
-import com.nhaarman.mockitokotlin2.isNull
-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.db.AppDatabase
import fr.free.nrw.commons.location.LatLng
@@ -32,8 +16,6 @@ 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
@@ -47,14 +29,12 @@ class BookMarkLocationDaoTest {
private lateinit var examplePlaceBookmark: Place
private lateinit var exampleLabel: Label
- private lateinit var exampleUri: Uri
private lateinit var exampleLocation: LatLng
private lateinit var builder: Sitelinks.Builder
@Before
fun setUp() {
exampleLabel = Label.FOREST
- exampleUri = Uri.parse("wikimedia/uri")
exampleLocation = LatLng(40.0, 51.4, 1f)
database = Room.inMemoryDatabaseBuilder(
@@ -91,7 +71,7 @@ class BookMarkLocationDaoTest {
@Test
fun testForAddAndGetAllBookmarkLocations() = runBlocking {
- bookmarkLocationsDao.addBookmarkLocation(examplePlaceBookmark.toBookmarksLocations())
+ bookmarkLocationsDao.addBookmarkLocation(bookmarkLocationsDao.toEntity(examplePlaceBookmark))
val bookmarks = bookmarkLocationsDao.getAllBookmarksLocations()
@@ -103,7 +83,7 @@ class BookMarkLocationDaoTest {
@Test
fun testFindBookmarkByNameForTrue() = runBlocking {
- bookmarkLocationsDao.addBookmarkLocation(examplePlaceBookmark.toBookmarksLocations())
+ bookmarkLocationsDao.addBookmarkLocation(bookmarkLocationsDao.toEntity(examplePlaceBookmark))
val exists = bookmarkLocationsDao.findBookmarkLocation(examplePlaceBookmark.name)
assertTrue(exists)
@@ -111,7 +91,7 @@ class BookMarkLocationDaoTest {
@Test
fun testFindBookmarkByNameForFalse() = runBlocking {
- bookmarkLocationsDao.addBookmarkLocation(examplePlaceBookmark.toBookmarksLocations())
+ bookmarkLocationsDao.addBookmarkLocation(bookmarkLocationsDao.toEntity(examplePlaceBookmark))
val exists = bookmarkLocationsDao.findBookmarkLocation("xyz")
assertFalse(exists)
@@ -119,7 +99,7 @@ class BookMarkLocationDaoTest {
@Test
fun testDeleteBookmark() = runBlocking {
- val bookmarkLocation = examplePlaceBookmark.toBookmarksLocations()
+ val bookmarkLocation = bookmarkLocationsDao.toEntity(examplePlaceBookmark)
bookmarkLocationsDao.addBookmarkLocation(bookmarkLocation)
bookmarkLocationsDao.deleteBookmarkLocation(bookmarkLocation)
@@ -137,7 +117,7 @@ class BookMarkLocationDaoTest {
@Test
fun testUpdateBookmarkForFalse() = runBlocking {
- val newBookmark = examplePlaceBookmark.toBookmarksLocations()
+ val newBookmark = bookmarkLocationsDao.toEntity(examplePlaceBookmark)
bookmarkLocationsDao.addBookmarkLocation(newBookmark)
val exists = bookmarkLocationsDao.updateBookmarkLocation(examplePlaceBookmark)
@@ -146,7 +126,7 @@ class BookMarkLocationDaoTest {
@Test
fun testGetAllBookmarksLocationsPlace() = runBlocking {
- val bookmarkLocation = examplePlaceBookmark.toBookmarksLocations()
+ val bookmarkLocation = bookmarkLocationsDao.toEntity(examplePlaceBookmark)
bookmarkLocationsDao.addBookmarkLocation(bookmarkLocation)
val bookmarks = bookmarkLocationsDao.getAllBookmarksLocationsPlace()
diff --git a/app/src/test/kotlin/fr/free/nrw/commons/bookmarks/pictures/BookmarkPictureDaoTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/bookmarks/pictures/BookmarkPictureDaoTest.kt
index 74d95908e2d..06712d1c8c6 100644
--- a/app/src/test/kotlin/fr/free/nrw/commons/bookmarks/pictures/BookmarkPictureDaoTest.kt
+++ b/app/src/test/kotlin/fr/free/nrw/commons/bookmarks/pictures/BookmarkPictureDaoTest.kt
@@ -1,233 +1,83 @@
package fr.free.nrw.commons.bookmarks.pictures
-import android.content.ContentProviderClient
-import android.content.ContentValues
-import android.database.Cursor
-import android.database.MatrixCursor
import android.net.Uri
-import android.os.RemoteException
-import androidx.sqlite.db.SupportSQLiteDatabase
-import com.nhaarman.mockitokotlin2.any
-import com.nhaarman.mockitokotlin2.anyOrNull
-import com.nhaarman.mockitokotlin2.argumentCaptor
-import com.nhaarman.mockitokotlin2.eq
-import com.nhaarman.mockitokotlin2.inOrder
-import com.nhaarman.mockitokotlin2.isA
-import com.nhaarman.mockitokotlin2.isNull
-import com.nhaarman.mockitokotlin2.mock
-import com.nhaarman.mockitokotlin2.verify
-import com.nhaarman.mockitokotlin2.whenever
+import androidx.room.Room.inMemoryDatabaseBuilder
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
import fr.free.nrw.commons.TestCommonsApplication
import fr.free.nrw.commons.bookmarks.models.Bookmark
-import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesContentProvider.Companion.BASE_URI
-import fr.free.nrw.commons.bookmarks.pictures.BookmarksTable.COLUMN_CREATOR
-import fr.free.nrw.commons.bookmarks.pictures.BookmarksTable.COLUMN_MEDIA_NAME
-import fr.free.nrw.commons.bookmarks.pictures.BookmarksTable.CREATE_TABLE_STATEMENT
-import fr.free.nrw.commons.bookmarks.pictures.BookmarksTable.DROP_TABLE_STATEMENT
-import fr.free.nrw.commons.bookmarks.pictures.BookmarksTable.onCreate
-import fr.free.nrw.commons.bookmarks.pictures.BookmarksTable.onDelete
-import fr.free.nrw.commons.bookmarks.pictures.BookmarksTable.onUpdate
+import fr.free.nrw.commons.db.AppDatabase
+import org.hamcrest.CoreMatchers
+import org.hamcrest.MatcherAssert
+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.Mockito.verifyNoInteractions
-import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
+import org.robolectric.annotation.LooperMode
-@RunWith(RobolectricTestRunner::class)
+@RunWith(AndroidJUnit4::class)
@Config(sdk = [21], application = TestCommonsApplication::class)
+@LooperMode(LooperMode.Mode.PAUSED)
class BookmarkPictureDaoTest {
- private val columns = arrayOf(COLUMN_MEDIA_NAME, COLUMN_CREATOR)
- private val client: ContentProviderClient = mock()
- private val database: SupportSQLiteDatabase = mock()
- private val captor = argumentCaptor()
-
- private lateinit var testObject: BookmarkPicturesDao
+ private lateinit var bookmarkPicturesRoomDao: BookmarkPicturesRoomDao
+ private lateinit var database: AppDatabase
private lateinit var exampleBookmark: Bookmark
@Before
- fun setUp() {
- exampleBookmark = Bookmark("mediaName", "creatorName", Uri.EMPTY)
- testObject = BookmarkPicturesDao { client }
- }
-
- @Test
- fun createTable() {
- onCreate(database)
- verify(database).execSQL(CREATE_TABLE_STATEMENT)
+ fun createDb() {
+ database =
+ inMemoryDatabaseBuilder(
+ context = ApplicationProvider.getApplicationContext(),
+ klass = AppDatabase::class.java,
+ ).allowMainThreadQueries().build()
+ bookmarkPicturesRoomDao = database.bookmarkPicturesRoomDao()
+ exampleBookmark = Bookmark("mediaName", "creatorName")
}
- @Test
- fun deleteTable() {
- onDelete(database)
- inOrder(database) {
- verify(database).execSQL(DROP_TABLE_STATEMENT)
- verify(database).execSQL(CREATE_TABLE_STATEMENT)
- }
- }
-
- @Test
- fun createFromCursor() {
- createCursor(1).let { cursor ->
- cursor.moveToFirst()
- testObject.fromCursor(cursor).let {
- assertEquals("mediaName", it.mediaName)
- assertEquals("creatorName", it.mediaCreator)
- }
- }
+ @After
+ fun closeDb() {
+ database.close()
}
@Test
fun getAllBookmarks() {
- whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull())).thenReturn(createCursor(14))
-
- var result = testObject.getAllBookmarks()
-
- assertEquals(14, (result.size))
- }
-
- @Test(expected = RuntimeException::class)
- fun getAllBookmarksTranslatesExceptions() {
- whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull())).thenThrow(RemoteException(""))
- testObject.getAllBookmarks()
- }
-
- @Test
- fun getAllBookmarksReturnsEmptyList_emptyCursor() {
- whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull())).thenReturn(createCursor(0))
- assertTrue(testObject.getAllBookmarks().isEmpty())
- }
-
- @Test
- fun getAllBookmarksReturnsEmptyList_nullCursor() {
- whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull())).thenReturn(null)
- assertTrue(testObject.getAllBookmarks().isEmpty())
- }
-
- @Test
- fun cursorsAreClosedAfterGetAllBookmarksQuery() {
- val mockCursor: Cursor = mock()
- whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull())).thenReturn(mockCursor)
- whenever(mockCursor.moveToFirst()).thenReturn(false)
-
- testObject.getAllBookmarks()
+ for (i in 1..5) {
+ bookmarkPicturesRoomDao.updateBookmark(Bookmark("media $i", "creator")).blockingGet()
+ }
- verify(mockCursor).close()
+ val result = bookmarkPicturesRoomDao.getAllBookmarks().blockingGet()
+ assertEquals(5, result.size)
}
@Test
fun updateNewBookmark() {
- whenever(client.insert(any(), any())).thenReturn(exampleBookmark.contentUri)
- whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(null)
-
- assertTrue(testObject.updateBookmark(exampleBookmark))
- verify(client).insert(eq(BASE_URI), captor.capture())
- captor.firstValue.let { cv ->
- assertEquals(2, cv.size())
- assertEquals(exampleBookmark.mediaName, cv.getAsString(COLUMN_MEDIA_NAME))
- assertEquals(exampleBookmark.mediaCreator, cv.getAsString(COLUMN_CREATOR))
- }
+ assertTrue(bookmarkPicturesRoomDao.updateBookmark(exampleBookmark).blockingGet())
+ assertTrue(bookmarkPicturesRoomDao.findBookmark(exampleBookmark).blockingGet())
}
@Test
fun updateExistingBookmark() {
- whenever(client.delete(isA(), isNull(), isNull())).thenReturn(1)
- whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(createCursor(1))
+ // First insert
+ bookmarkPicturesRoomDao.updateBookmark(exampleBookmark).blockingGet()
+ assertTrue(bookmarkPicturesRoomDao.findBookmark(exampleBookmark).blockingGet())
- assertFalse(testObject.updateBookmark(exampleBookmark))
- verify(client).delete(eq(exampleBookmark.contentUri!!), isNull(), isNull())
+ // Second update should remove it (matches legacy behavior)
+ assertFalse(bookmarkPicturesRoomDao.updateBookmark(exampleBookmark).blockingGet())
+ assertFalse(bookmarkPicturesRoomDao.findBookmark(exampleBookmark).blockingGet())
}
@Test
fun findExistingBookmark() {
- whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(createCursor(1))
- assertTrue(testObject.findBookmark(exampleBookmark))
- }
-
- @Test(expected = RuntimeException::class)
- fun findBookmarkTranslatesExceptions() {
- whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull())).thenThrow(RemoteException(""))
- testObject.findBookmark(exampleBookmark)
- }
-
- @Test
- fun findNotExistingBookmarkReturnsNull_emptyCursor() {
- whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(createCursor(0))
- assertFalse(testObject.findBookmark(exampleBookmark))
- }
-
- @Test
- fun findNotExistingBookmarkReturnsNull_nullCursor() {
- whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(null)
- assertFalse(testObject.findBookmark(exampleBookmark))
- }
-
- @Test
- fun cursorsAreClosedAfterFindBookmarkQuery() {
- val mockCursor: Cursor = mock()
- whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(mockCursor)
- whenever(mockCursor.moveToFirst()).thenReturn(false)
-
- testObject.findBookmark(exampleBookmark)
-
- 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 didn't exist before v5
- verifyNoInteractions(database)
+ bookmarkPicturesRoomDao.updateBookmark(exampleBookmark).blockingGet()
+ assertTrue(bookmarkPicturesRoomDao.findBookmark(exampleBookmark).blockingGet())
}
@Test
- fun migrateTableVersionFrom_v4_to_v5() {
- onUpdate(database, 4, 5)
- // Table didn't change in version 5
- verifyNoInteractions(database)
+ fun findNotExistingBookmark() {
+ assertFalse(bookmarkPicturesRoomDao.findBookmark(exampleBookmark).blockingGet())
}
-
- @Test
- fun migrateTableVersionFrom_v5_to_v6() {
- onUpdate(database, 5, 6)
- // Table didn't change in version 6
- verifyNoInteractions(database)
- }
-
- @Test
- fun migrateTableVersionFrom_v6_to_v7() {
- onUpdate(database, 6, 7)
- // Table didn't change in version 7
- verifyNoInteractions(database)
- }
-
- @Test
- fun migrateTableVersionFrom_v7_to_v8() {
- onUpdate(database, 7, 8)
- verify(database).execSQL(CREATE_TABLE_STATEMENT)
- }
-
- private fun createCursor(rowCount: Int) =
- MatrixCursor(columns, rowCount).apply {
- for (i in 0 until rowCount) {
- addRow(listOf("mediaName", "creatorName"))
- }
- }
}
diff --git a/app/src/test/kotlin/fr/free/nrw/commons/bookmarks/pictures/BookmarkPicturesControllerTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/bookmarks/pictures/BookmarkPicturesControllerTest.kt
index 154a5a9b3da..6f32fc05bc7 100644
--- a/app/src/test/kotlin/fr/free/nrw/commons/bookmarks/pictures/BookmarkPicturesControllerTest.kt
+++ b/app/src/test/kotlin/fr/free/nrw/commons/bookmarks/pictures/BookmarkPicturesControllerTest.kt
@@ -23,7 +23,7 @@ class BookmarkPicturesControllerTest {
var mediaClient: MediaClient? = null
@Mock
- var bookmarkDao: BookmarkPicturesDao? = null
+ var bookmarkDao: BookmarkPicturesRoomDao? = null
@InjectMocks
var bookmarkPicturesController: BookmarkPicturesController? = null
@@ -36,7 +36,7 @@ class BookmarkPicturesControllerTest {
MockitoAnnotations.initMocks(this)
val mockMedia = mockMedia
whenever(bookmarkDao!!.getAllBookmarks())
- .thenReturn(mockBookmarkList)
+ .thenReturn(Single.just(mockBookmarkList))
whenever(
mediaClient!!.getMedia(
ArgumentMatchers.anyString(),
@@ -51,8 +51,8 @@ class BookmarkPicturesControllerTest {
private val mockBookmarkList: List
private get() {
val list = ArrayList()
- list.add(Bookmark("File:Test1.jpg", "Maskaravivek", Uri.EMPTY))
- list.add(Bookmark("File:Test2.jpg", "Maskaravivek", Uri.EMPTY))
+ list.add(Bookmark("File:Test1.jpg", "Maskaravivek"))
+ list.add(Bookmark("File:Test2.jpg", "Maskaravivek"))
return list
}
diff --git a/app/src/test/kotlin/fr/free/nrw/commons/bookmarks/pictures/BookmarkPicturesFragmentUnitTests.kt b/app/src/test/kotlin/fr/free/nrw/commons/bookmarks/pictures/BookmarkPicturesFragmentUnitTests.kt
index b1dae0fab79..dd67333fae5 100644
--- a/app/src/test/kotlin/fr/free/nrw/commons/bookmarks/pictures/BookmarkPicturesFragmentUnitTests.kt
+++ b/app/src/test/kotlin/fr/free/nrw/commons/bookmarks/pictures/BookmarkPicturesFragmentUnitTests.kt
@@ -23,6 +23,7 @@ import fr.free.nrw.commons.TestCommonsApplication
import fr.free.nrw.commons.category.GridViewAdapter
import fr.free.nrw.commons.createTestClient
import fr.free.nrw.commons.databinding.FragmentBookmarksPicturesBinding
+import fr.free.nrw.commons.db.InMemoryDatabaseTest
import fr.free.nrw.commons.media.MediaClient
import fr.free.nrw.commons.profile.ProfileActivity
import media
@@ -43,7 +44,7 @@ import java.lang.reflect.Method
@RunWith(RobolectricTestRunner::class)
@Config(sdk = [21], application = TestCommonsApplication::class)
@LooperMode(LooperMode.Mode.PAUSED)
-class BookmarkPicturesFragmentUnitTests {
+class BookmarkPicturesFragmentUnitTests : InMemoryDatabaseTest() {
private lateinit var fragment: BookmarkPicturesFragment
private lateinit var binding: FragmentBookmarksPicturesBinding
@@ -96,7 +97,7 @@ class BookmarkPicturesFragmentUnitTests {
binding = FragmentBookmarksPicturesBinding.inflate(LayoutInflater.from(activity))
- val bookmarkDao = BookmarkPicturesDao { client }
+ val bookmarkDao = roomDatabase.bookmarkPicturesRoomDao()
controller = BookmarkPicturesController(mediaClient, bookmarkDao)
diff --git a/app/src/test/kotlin/fr/free/nrw/commons/category/CategoriesModelTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/category/CategoriesModelTest.kt
index 21fdba2f575..f4041b8f9b0 100644
--- a/app/src/test/kotlin/fr/free/nrw/commons/category/CategoriesModelTest.kt
+++ b/app/src/test/kotlin/fr/free/nrw/commons/category/CategoriesModelTest.kt
@@ -21,7 +21,7 @@ import org.mockito.MockitoAnnotations
// class for testing CategoriesModel class
class CategoriesModelTest {
@Mock
- internal lateinit var categoryDao: CategoryDao
+ internal lateinit var categoryDao: CategoryRoomDao
@Mock
internal lateinit var categoryClient: CategoryClient
@@ -35,6 +35,8 @@ class CategoriesModelTest {
@Throws(Exception::class)
fun setUp() {
MockitoAnnotations.openMocks(this)
+ // Default mock returns for Room DAO reactive methods
+ whenever(categoryDao.save(any())).thenReturn(io.reactivex.Completable.complete())
categoriesModel = CategoriesModel(categoryClient, categoryDao, gpsCategoryModel)
}
@@ -139,14 +141,11 @@ class CategoriesModelTest {
),
)
whenever(categoryDao.recentCategories(25)).thenReturn(
- listOf(
- CategoryItem(
- "recentCategories",
- "",
- "",
- false,
- ),
- ),
+ Single.just(
+ listOf(
+ CategoryItem("recentCategories", "", "", false)
+ )
+ )
)
whenever(
categoryClient.getCategoriesByName(
diff --git a/app/src/test/kotlin/fr/free/nrw/commons/category/CategoryDaoTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/category/CategoryDaoTest.kt
index 53d82dabf7a..fab26471b56 100644
--- a/app/src/test/kotlin/fr/free/nrw/commons/category/CategoryDaoTest.kt
+++ b/app/src/test/kotlin/fr/free/nrw/commons/category/CategoryDaoTest.kt
@@ -1,319 +1,94 @@
package fr.free.nrw.commons.category
-import android.content.ContentProviderClient
-import android.content.ContentValues
-import android.database.Cursor
-import android.database.MatrixCursor
-import android.os.RemoteException
-import androidx.sqlite.db.SupportSQLiteDatabase
-import com.nhaarman.mockitokotlin2.any
-import com.nhaarman.mockitokotlin2.anyOrNull
-import com.nhaarman.mockitokotlin2.argumentCaptor
-import com.nhaarman.mockitokotlin2.eq
-import com.nhaarman.mockitokotlin2.inOrder
-import com.nhaarman.mockitokotlin2.isA
-import com.nhaarman.mockitokotlin2.isNull
-import com.nhaarman.mockitokotlin2.mock
-import com.nhaarman.mockitokotlin2.verify
-import com.nhaarman.mockitokotlin2.whenever
+import androidx.room.Room.inMemoryDatabaseBuilder
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
import fr.free.nrw.commons.TestCommonsApplication
-import fr.free.nrw.commons.category.CategoryTable.ALL_FIELDS
-import fr.free.nrw.commons.category.CategoryTable.COLUMN_DESCRIPTION
-import fr.free.nrw.commons.category.CategoryTable.COLUMN_ID
-import fr.free.nrw.commons.category.CategoryTable.COLUMN_LAST_USED
-import fr.free.nrw.commons.category.CategoryTable.COLUMN_NAME
-import fr.free.nrw.commons.category.CategoryTable.COLUMN_THUMBNAIL
-import fr.free.nrw.commons.category.CategoryTable.COLUMN_TIMES_USED
-import fr.free.nrw.commons.category.CategoryTable.CREATE_TABLE_STATEMENT
-import fr.free.nrw.commons.category.CategoryTable.DROP_TABLE_STATEMENT
-import fr.free.nrw.commons.category.CategoryTable.onCreate
-import fr.free.nrw.commons.category.CategoryTable.onDelete
-import fr.free.nrw.commons.category.CategoryTable.onUpdate
-import fr.free.nrw.commons.explore.recentsearches.RecentSearchesContentProvider.Companion.uriForId
+import fr.free.nrw.commons.db.AppDatabase
+import org.hamcrest.CoreMatchers
+import org.hamcrest.MatcherAssert
+import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
-import org.junit.Assert.assertNull
-import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.Mockito.verifyNoInteractions
-import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
+import org.robolectric.annotation.LooperMode
import java.util.Date
-@RunWith(RobolectricTestRunner::class)
+@RunWith(AndroidJUnit4::class)
@Config(sdk = [21], application = TestCommonsApplication::class)
+@LooperMode(LooperMode.Mode.PAUSED)
class CategoryDaoTest {
- private val columns =
- arrayOf(
- COLUMN_ID,
- COLUMN_NAME,
- COLUMN_DESCRIPTION,
- COLUMN_THUMBNAIL,
- COLUMN_LAST_USED,
- COLUMN_TIMES_USED,
- )
- private val client: ContentProviderClient = mock()
- private val database: SupportSQLiteDatabase = mock()
- private val captor = argumentCaptor()
- private val queryCaptor = argumentCaptor>()
-
- private lateinit var testObject: CategoryDao
+ private lateinit var categoryRoomDao: CategoryRoomDao
+ private lateinit var database: AppDatabase
@Before
- fun setUp() {
- testObject = CategoryDao { client }
- }
-
- @Test
- fun createTable() {
- onCreate(database)
- verify(database).execSQL(CREATE_TABLE_STATEMENT)
- }
-
- @Test
- fun deleteTable() {
- onDelete(database)
- inOrder(database) {
- verify(database).execSQL(DROP_TABLE_STATEMENT)
- verify(database).execSQL(CREATE_TABLE_STATEMENT)
- }
+ fun createDb() {
+ database =
+ inMemoryDatabaseBuilder(
+ context = ApplicationProvider.getApplicationContext(),
+ klass = AppDatabase::class.java,
+ ).allowMainThreadQueries().build()
+ categoryRoomDao = database.categoryRoomDao()
}
- @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 didn't exist before v5
- verifyNoInteractions(database)
- }
-
- @Test
- fun migrateTableVersionFrom_v4_to_v5() {
- onUpdate(database, 4, 5)
- verify(database).execSQL(CREATE_TABLE_STATEMENT)
- }
-
- @Test
- fun migrateTableVersionFrom_v5_to_v6() {
- onUpdate(database, 5, 6)
- // Table didn't change in version 6
- verifyNoInteractions(database)
- }
-
- @Test
- fun migrateTableVersionFrom_v6_to_v7() {
- onUpdate(database, 6, 7)
- // Table didn't change in version 7
- verifyNoInteractions(database)
- }
-
- @Test
- fun migrateTableVersionFrom_v7_to_v8() {
- onUpdate(database, 7, 8)
- // Table didn't change in version 8
- verifyNoInteractions(database)
- }
-
- @Test
- fun createFromCursor() {
- createCursor(1).let { cursor ->
- cursor.moveToFirst()
- testObject.fromCursor(cursor).let {
- assertEquals(CategoryContentProvider.uriForId(1), it.contentUri)
- assertEquals("showImageWithItem", it.name)
- assertEquals(123L, it.lastUsed?.time)
- assertEquals(2, it.timesUsed)
- }
- }
+ @After
+ fun closeDb() {
+ database.close()
}
@Test
fun saveExistingCategory() {
- createCursor(1).let {
- val category = testObject.fromCursor(it.apply { moveToFirst() })
-
- testObject.save(category)
-
- verify(client).update(
- eq(category.contentUri)!!,
- captor.capture(),
- isNull(),
- isNull()
- )
- captor.firstValue.let { cv ->
- assertEquals(5, cv.size())
- assertEquals(category.name, cv.getAsString(COLUMN_NAME))
- assertEquals(category.description, cv.getAsString(COLUMN_DESCRIPTION))
- assertEquals(category.thumbnail, cv.getAsString(COLUMN_THUMBNAIL))
- assertEquals(category.lastUsed?.time, cv.getAsLong(COLUMN_LAST_USED))
- assertEquals(category.timesUsed, cv.getAsInteger(COLUMN_TIMES_USED))
- }
- }
- }
-
- @Test
- fun saveNewCategory() {
- val contentUri = uriForId(111)
- whenever(client.insert(isA(), isA())).thenReturn(contentUri)
- val category =
- Category(
- null,
- "showImageWithItem",
- "description",
- "image",
- Date(234L),
- 1,
- )
-
- testObject.save(category)
-
- verify(client).insert(eq(CategoryContentProvider.BASE_URI), captor.capture())
- captor.firstValue.let { cv ->
- assertEquals(5, cv.size())
- assertEquals(category.name, cv.getAsString(COLUMN_NAME))
- assertEquals(category.description, cv.getAsString(COLUMN_DESCRIPTION))
- assertEquals(category.thumbnail, cv.getAsString(COLUMN_THUMBNAIL))
- assertEquals(category.lastUsed?.time, cv.getAsLong(COLUMN_LAST_USED))
- assertEquals(category.timesUsed, cv.getAsInteger(COLUMN_TIMES_USED))
- assertEquals(contentUri, category.contentUri)
- }
- }
+ // First insert
+ val category = Category("Test Category", "desc", "thumb", Date(1234), 1)
+ categoryRoomDao.save(category).blockingAwait()
- @Test(expected = RuntimeException::class)
- fun testSaveTranslatesRemoteExceptions() {
- whenever(client.insert(isA(), isA())).thenThrow(RemoteException(""))
- testObject.save(Category())
- }
+ val foundBefore = categoryRoomDao.findCategory("Test Category").blockingGet()
+ MatcherAssert.assertThat(foundBefore, CoreMatchers.equalTo(true))
- @Test
- fun whenTheresNoDataFindReturnsNull_nullCursor() {
- whenever(client.query(any(), any(), any(), any(), any())).thenReturn(null)
- assertNull(testObject.find("showImageWithItem"))
- }
+ // Update it
+ category.timesUsed = 5
+ categoryRoomDao.save(category).blockingAwait()
- @Test
- fun whenTheresNoDataFindReturnsNull_emptyCursor() {
- whenever(client.query(any(), any(), any(), any(), any())).thenReturn(createCursor(0))
- assertNull(testObject.find("showImageWithItem"))
+ // Verify update via entity
+ val entities = categoryRoomDao.findEntity("Test Category").blockingGet()
+ assertEquals(5, entities[0].timesUsed)
}
@Test
- fun cursorsAreClosedAfterUse() {
- val mockCursor: Cursor = mock()
- whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(mockCursor)
- whenever(mockCursor.moveToFirst()).thenReturn(false)
-
- testObject.find("showImageWithItem")
+ fun saveNewCategory() {
+ val category = Category("New Category", "desc", "thumb", Date(1234), 1)
+ categoryRoomDao.save(category).blockingAwait()
- verify(mockCursor).close()
+ val items = categoryRoomDao.recentCategories(1).blockingGet()
+ assertEquals(1, items.size)
+ assertEquals("New Category", items[0].name)
}
@Test
fun findCategory() {
- whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(createCursor(1))
-
- val category = testObject.find("showImageWithItem")
- assertNotNull(category)
+ val category = Category("Category to Find", "desc", "thumb", Date(1234), 1)
+ categoryRoomDao.save(category).blockingAwait()
- assertEquals(CategoryContentProvider.uriForId(1), category?.contentUri)
- assertEquals("showImageWithItem", category?.name)
- assertEquals("description", category?.description)
- assertEquals("image", category?.thumbnail)
- assertEquals(123L, category?.lastUsed?.time)
- assertEquals(2, category?.timesUsed)
+ val isFound = categoryRoomDao.findCategory("Category to Find").blockingGet()
+ MatcherAssert.assertThat(isFound, CoreMatchers.equalTo(true))
- verify(client).query(
- eq(CategoryContentProvider.BASE_URI),
- eq(ALL_FIELDS),
- eq("$COLUMN_NAME=?"),
- queryCaptor.capture(),
- isNull(),
- )
- assertEquals("showImageWithItem", queryCaptor.firstValue[0])
- }
-
- @Test(expected = RuntimeException::class)
- fun findCategoryTranslatesExceptions() {
- whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenThrow(RemoteException(""))
- testObject.find("showImageWithItem")
- }
-
- @Test(expected = RuntimeException::class)
- fun recentCategoriesTranslatesExceptions() {
- whenever(client.query(any(), any(), anyOrNull(), any(), any())).thenThrow(RemoteException(""))
- testObject.recentCategories(1)
- }
-
- @Test
- fun recentCategoriesReturnsEmptyList_nullCursor() {
- whenever(client.query(any(), any(), anyOrNull(), any(), any())).thenReturn(null)
- assertTrue(testObject.recentCategories(1).isEmpty())
- }
-
- @Test
- fun recentCategoriesReturnsEmptyList_emptyCursor() {
- whenever(client.query(any(), any(), any(), any(), any())).thenReturn(createCursor(0))
- assertTrue(testObject.recentCategories(1).isEmpty())
- }
-
- @Test
- fun cursorsAreClosedAfterRecentCategoriesQuery() {
- val mockCursor: Cursor = mock()
- whenever(client.query(any(), any(), anyOrNull(), any(), any())).thenReturn(mockCursor)
- whenever(mockCursor.moveToFirst()).thenReturn(false)
-
- testObject.recentCategories(1)
-
- verify(mockCursor).close()
- }
-
- @Test
- fun recentCategoriesReturnsLessThanLimit() {
- whenever(client.query(any(), any(), anyOrNull(), any(), any())).thenReturn(createCursor(1))
-
- val result = testObject.recentCategories(10)
-
- assertEquals(1, result.size)
- assertEquals("showImageWithItem", result[0].name)
-
- verify(client).query(
- eq(CategoryContentProvider.BASE_URI),
- eq(ALL_FIELDS),
- isNull(),
- queryCaptor.capture(),
- eq("$COLUMN_LAST_USED DESC"),
- )
- assertEquals(0, queryCaptor.firstValue.size)
+ val isNotFound = categoryRoomDao.findCategory("Non existent").blockingGet()
+ MatcherAssert.assertThat(isNotFound, CoreMatchers.equalTo(false))
}
@Test
fun recentCategoriesHonorsLimit() {
- whenever(client.query(any(), any(), anyOrNull(), any(), any())).thenReturn(createCursor(10))
-
- val result = testObject.recentCategories(5)
+ for (i in 1..10) {
+ val category = Category("Category $i", "desc", "thumb", Date(i * 1000L), 1)
+ categoryRoomDao.save(category).blockingAwait()
+ }
- assertEquals(5, result.size)
+ val items = categoryRoomDao.recentCategories(5).blockingGet()
+ assertEquals(5, items.size)
+ // Check ordering (LIFO by lastUsed)
+ assertEquals("Category 10", items[0].name)
}
-
- private fun createCursor(rowCount: Int) =
- MatrixCursor(columns, rowCount).apply {
- for (i in 0 until rowCount) {
- addRow(listOf("1", "showImageWithItem", "description", "image", "123", "2"))
- }
- }
}
diff --git a/app/src/test/kotlin/fr/free/nrw/commons/db/BookmarkItemsTableTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/db/BookmarkItemsTableTest.kt
index e67bcf701f8..01d553eae5a 100644
--- a/app/src/test/kotlin/fr/free/nrw/commons/db/BookmarkItemsTableTest.kt
+++ b/app/src/test/kotlin/fr/free/nrw/commons/db/BookmarkItemsTableTest.kt
@@ -28,7 +28,7 @@ class BookmarkItemsTableTest : InMemoryDatabaseTest() {
isSelected = true,
id = "Q12345"
)
- dao.insert(item)
+ dao.insert(item).blockingAwait()
val allItems = dao.getAll().blockingGet()
assertEquals(1, allItems.size)
@@ -49,7 +49,7 @@ class BookmarkItemsTableTest : InMemoryDatabaseTest() {
VALUES ('Legacy Item', 'Q6789', 'Instance', 'Cat', 'Desc', 'Thumb', 1);
""".trimIndent())
- val exists = dao.findBookmarkItem("Q6789")
+ val exists = dao.findBookmarkItem("Q6789").blockingGet()
assertTrue(exists)
val allItems = dao.getAll().blockingGet()
assertEquals(1, allItems.size)
@@ -72,18 +72,18 @@ class BookmarkItemsTableTest : InMemoryDatabaseTest() {
isSelected = false,
id = "QToDelete"
)
- dao.insert(item)
+ dao.insert(item).blockingAwait()
assertRowCount(BookmarkItemsTable.TABLE_NAME, 1)
- dao.delete(item)
+ dao.delete(item).blockingAwait()
assertRowCount(BookmarkItemsTable.TABLE_NAME, 0)
}
@Test
fun testClearAllTables() {
val dao = roomDatabase.bookmarkItemsRoomDao()
- dao.insert(BookmarkItemsRoomEntity("Item 1", null, null, "", "", "", "", false, "Q1"))
- dao.insert(BookmarkItemsRoomEntity("Item 2", null, null, "", "", "", "", false, "Q2"))
+ dao.insert(BookmarkItemsRoomEntity("Item 1", null, null, "", "", "", "", false, "Q1")).blockingAwait()
+ dao.insert(BookmarkItemsRoomEntity("Item 2", null, null, "", "", "", "", false, "Q2")).blockingAwait()
assertRowCount(BookmarkItemsTable.TABLE_NAME, 2)
clearAllTables()
diff --git a/app/src/test/kotlin/fr/free/nrw/commons/db/BookmarkPictureTableTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/db/BookmarkPictureTableTest.kt
index 27535892b44..5ca13e08b70 100644
--- a/app/src/test/kotlin/fr/free/nrw/commons/db/BookmarkPictureTableTest.kt
+++ b/app/src/test/kotlin/fr/free/nrw/commons/db/BookmarkPictureTableTest.kt
@@ -21,7 +21,7 @@ class BookmarkPictureTableTest : InMemoryDatabaseTest() {
mediaName = "Test Image",
mediaCreator = "Test Creator"
)
- dao.insert(bookmark)
+ dao.insert(bookmark).blockingAwait()
val allBookmarks = dao.getAll().blockingGet()
assertEquals(1, allBookmarks.size)
@@ -38,7 +38,7 @@ class BookmarkPictureTableTest : InMemoryDatabaseTest() {
// Insert with legacy SQL
db.execSQL("INSERT INTO bookmarks (media_name, media_creator) VALUES ('Legacy Image', 'Legacy Creator');")
- val exists = dao.findBookmarkByName("Legacy Image")
+ val exists: Boolean = dao.findBookmarkByName("Legacy Image").blockingGet()
assertTrue(exists)
val allBookmarks = dao.getAll().blockingGet()
assertEquals(1, allBookmarks.size)
@@ -50,18 +50,18 @@ class BookmarkPictureTableTest : InMemoryDatabaseTest() {
fun testDeleteBookmark() {
val dao = roomDatabase.bookmarkPicturesRoomDao()
val bookmark = BookmarkPictureRoomEntity("Image to delete", "Creator")
- dao.insert(bookmark)
+ dao.insert(bookmark).blockingAwait()
assertRowCount(BookmarksTable.TABLE_NAME, 1)
- dao.delete(bookmark)
+ dao.delete(bookmark).blockingAwait()
assertRowCount(BookmarksTable.TABLE_NAME, 0)
}
@Test
fun testClearAllTables() {
val dao = roomDatabase.bookmarkPicturesRoomDao()
- dao.insert(BookmarkPictureRoomEntity("Image 1", "Creator 1"))
- dao.insert(BookmarkPictureRoomEntity("Image 2", "Creator 2"))
+ dao.insert(BookmarkPictureRoomEntity("Image 1", "Creator 1")).blockingAwait()
+ dao.insert(BookmarkPictureRoomEntity("Image 2", "Creator 2")).blockingAwait()
assertRowCount(BookmarksTable.TABLE_NAME, 2)
clearAllTables()
diff --git a/app/src/test/kotlin/fr/free/nrw/commons/db/CategoryTableTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/db/CategoryTableTest.kt
index 14e9a14d2df..a541f17f06d 100644
--- a/app/src/test/kotlin/fr/free/nrw/commons/db/CategoryTableTest.kt
+++ b/app/src/test/kotlin/fr/free/nrw/commons/db/CategoryTableTest.kt
@@ -24,9 +24,9 @@ class CategoryTableTest : InMemoryDatabaseTest() {
thumbnail = "http://test.com/thumb.jpg",
timesUsed = 5
)
- categoryDao.insert(category)
+ categoryDao.insert(category).blockingGet()
- val retrieved = categoryDao.findEntity("Test Category")
+ val retrieved = categoryDao.findEntity("Test Category").blockingGet().firstOrNull()
assertNotNull(retrieved)
assertEquals("Test Category", retrieved?.name)
assertEquals("Test Description", retrieved?.description)
@@ -43,7 +43,7 @@ class CategoryTableTest : InMemoryDatabaseTest() {
// Insert with legacy SQL
db.execSQL("INSERT INTO categories (name, description, times_used) VALUES ('Nature', 'Nature category', 10);")
- val entity = categoryDao.findEntity("Nature")
+ val entity = categoryDao.findEntity("Nature").blockingGet().firstOrNull()
assertNotNull(entity)
assertEquals("Nature", entity?.name)
assertEquals("Nature category", entity?.description)
@@ -55,13 +55,13 @@ class CategoryTableTest : InMemoryDatabaseTest() {
fun testUpdateCategory() {
val categoryDao = roomDatabase.categoryRoomDao()
val category = CategoryRoomEntity(name = "Original Name", timesUsed = 1)
- categoryDao.insert(category)
+ categoryDao.insert(category).blockingGet()
- val savedCategory = categoryDao.findEntity("Original Name")!!
- val updatedCategory = savedCategory.copy(timesUsed = 2)
- categoryDao.insert(updatedCategory)
+ val savedCategory = categoryDao.findEntity("Original Name").blockingGet().firstOrNull()
+ val updatedCategory = savedCategory?.copy(timesUsed = 2)
+ categoryDao.insert(updatedCategory!!).blockingGet()
- val retrieved = categoryDao.findEntity("Original Name")
+ val retrieved = categoryDao.findEntity("Original Name").blockingGet().firstOrNull()
assertEquals(2, retrieved?.timesUsed)
assertRowCount(CategoryTable.TABLE_NAME, 1)
}
@@ -69,8 +69,8 @@ class CategoryTableTest : InMemoryDatabaseTest() {
@Test
fun testClearAllTables() {
val categoryDao = roomDatabase.categoryRoomDao()
- categoryDao.insert(CategoryRoomEntity(name = "Cat 1"))
- categoryDao.insert(CategoryRoomEntity(name = "Cat 2"))
+ categoryDao.insert(CategoryRoomEntity(name = "Cat 1")).blockingGet()
+ categoryDao.insert(CategoryRoomEntity(name = "Cat 2")).blockingGet()
assertRowCount(CategoryTable.TABLE_NAME, 2)
clearAllTables()
@@ -80,9 +80,9 @@ class CategoryTableTest : InMemoryDatabaseTest() {
@Test
fun testFindCategory() {
val categoryDao = roomDatabase.categoryRoomDao()
- categoryDao.insert(CategoryRoomEntity(name = "Exist"))
+ categoryDao.insert(CategoryRoomEntity(name = "Exist")).blockingGet()
- assertTrue(categoryDao.findCategory("Exist"))
- assertTrue(!categoryDao.findCategory("NotExist"))
+ assertTrue(categoryDao.findCategory("Exist").blockingGet())
+ assertTrue(!categoryDao.findCategory("NotExist").blockingGet())
}
}
\ No newline at end of file
diff --git a/app/src/test/kotlin/fr/free/nrw/commons/db/RecentLanguagesTableTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/db/RecentLanguagesTableTest.kt
index 6757b35630c..e225d99a632 100644
--- a/app/src/test/kotlin/fr/free/nrw/commons/db/RecentLanguagesTableTest.kt
+++ b/app/src/test/kotlin/fr/free/nrw/commons/db/RecentLanguagesTableTest.kt
@@ -21,7 +21,7 @@ class RecentLanguagesTableTest : InMemoryDatabaseTest() {
languageName = "English",
languageCode = "en"
)
- dao.insert(language)
+ dao.insert(language).blockingAwait()
val allLanguages = dao.getAll().blockingGet()
assertEquals(1, allLanguages.size)
@@ -38,7 +38,7 @@ class RecentLanguagesTableTest : InMemoryDatabaseTest() {
// Insert with legacy SQL
db.execSQL("INSERT INTO recent_languages (language_name, language_code) VALUES ('French', 'fr');")
- val exists = dao.findRecentLanguage("fr")
+ val exists = dao.findRecentLanguage("fr").blockingGet()
assertTrue(exists)
val allLanguages = dao.getAll().blockingGet()
assertEquals(1, allLanguages.size)
@@ -49,18 +49,18 @@ class RecentLanguagesTableTest : InMemoryDatabaseTest() {
@Test
fun testDeleteRecentLanguage() {
val dao = roomDatabase.recentLanguagesRoomDao()
- dao.insert(RecentLanguageRoomEntity("Spanish", "es"))
+ dao.insert(RecentLanguageRoomEntity("Spanish", "es")).blockingAwait()
assertRowCount(RecentLanguagesTable.TABLE_NAME, 1)
- dao.deleteRecentLanguage("es")
+ dao.deleteRecentLanguage("es").blockingAwait()
assertRowCount(RecentLanguagesTable.TABLE_NAME, 0)
}
@Test
fun testClearAllTables() {
val dao = roomDatabase.recentLanguagesRoomDao()
- dao.insert(RecentLanguageRoomEntity("Language 1", "l1"))
- dao.insert(RecentLanguageRoomEntity("Language 2", "l2"))
+ dao.insert(RecentLanguageRoomEntity("Language 1", "l1")).blockingAwait()
+ dao.insert(RecentLanguageRoomEntity("Language 2", "l2")).blockingAwait()
assertRowCount(RecentLanguagesTable.TABLE_NAME, 2)
clearAllTables()
diff --git a/app/src/test/kotlin/fr/free/nrw/commons/db/RecentSearchesTableTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/db/RecentSearchesTableTest.kt
index b70cca65721..70669936280 100644
--- a/app/src/test/kotlin/fr/free/nrw/commons/db/RecentSearchesTableTest.kt
+++ b/app/src/test/kotlin/fr/free/nrw/commons/db/RecentSearchesTableTest.kt
@@ -23,9 +23,9 @@ class RecentSearchesTableTest : InMemoryDatabaseTest() {
query = "Test Search",
lastSearched = date
)
- dao.insert(search)
+ dao.insert(search).blockingGet()
- val retrieved = dao.findEntity("Test Search")
+ val retrieved = dao.findEntity("Test Search").blockingGet().firstOrNull()
assertNotNull(retrieved)
assertEquals("Test Search", retrieved?.query)
// Date might lose some precision in DB, but should be close
@@ -42,7 +42,7 @@ class RecentSearchesTableTest : InMemoryDatabaseTest() {
val now = System.currentTimeMillis()
db.execSQL("INSERT INTO recent_searches (name, last_used) VALUES ('Legacy Search', $now);")
- val entity = dao.findEntity("Legacy Search")
+ val entity = dao.findEntity("Legacy Search").blockingGet().firstOrNull()
assertNotNull(entity)
assertEquals("Legacy Search", entity?.query)
assertEquals(now, entity?.lastSearched?.time)
@@ -52,8 +52,8 @@ class RecentSearchesTableTest : InMemoryDatabaseTest() {
@Test
fun testDeleteTable() {
val dao = roomDatabase.recentSearchesRoomDao()
- dao.insert(RecentSearchRoomEntity(query = "Search 1", lastSearched = Date()))
- dao.insert(RecentSearchRoomEntity(query = "Search 2", lastSearched = Date()))
+ dao.insert(RecentSearchRoomEntity(query = "Search 1", lastSearched = Date())).blockingGet()
+ dao.insert(RecentSearchRoomEntity(query = "Search 2", lastSearched = Date())).blockingGet()
assertRowCount(RecentSearchesTable.TABLE_NAME, 2)
dao.deleteTable().blockingAwait()
@@ -63,7 +63,7 @@ class RecentSearchesTableTest : InMemoryDatabaseTest() {
@Test
fun testClearAllTables() {
val dao = roomDatabase.recentSearchesRoomDao()
- dao.insert(RecentSearchRoomEntity(query = "Search 1", lastSearched = Date()))
+ dao.insert(RecentSearchRoomEntity(query = "Search 1", lastSearched = Date())).blockingGet()
assertRowCount(RecentSearchesTable.TABLE_NAME, 1)
clearAllTables()
diff --git a/app/src/test/kotlin/fr/free/nrw/commons/explore/recentsearches/RecentSearchesDaoTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/explore/recentsearches/RecentSearchesDaoTest.kt
index f5e338e8572..7451e55f6c8 100644
--- a/app/src/test/kotlin/fr/free/nrw/commons/explore/recentsearches/RecentSearchesDaoTest.kt
+++ b/app/src/test/kotlin/fr/free/nrw/commons/explore/recentsearches/RecentSearchesDaoTest.kt
@@ -1,326 +1,93 @@
package fr.free.nrw.commons.explore.recentsearches
-import android.content.ContentProviderClient
-import android.content.ContentValues
-import android.database.Cursor
-import android.database.MatrixCursor
-import android.os.RemoteException
-import androidx.sqlite.db.SupportSQLiteDatabase
-import com.nhaarman.mockitokotlin2.any
-import com.nhaarman.mockitokotlin2.anyOrNull
-import com.nhaarman.mockitokotlin2.argumentCaptor
-import com.nhaarman.mockitokotlin2.eq
-import com.nhaarman.mockitokotlin2.inOrder
-import com.nhaarman.mockitokotlin2.isA
-import com.nhaarman.mockitokotlin2.isNull
-import com.nhaarman.mockitokotlin2.mock
-import com.nhaarman.mockitokotlin2.verify
-import com.nhaarman.mockitokotlin2.whenever
+import androidx.room.Room.inMemoryDatabaseBuilder
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
import fr.free.nrw.commons.TestCommonsApplication
+import fr.free.nrw.commons.db.AppDatabase
import fr.free.nrw.commons.explore.models.RecentSearch
-import fr.free.nrw.commons.explore.recentsearches.RecentSearchesContentProvider.Companion.BASE_URI
-import fr.free.nrw.commons.explore.recentsearches.RecentSearchesContentProvider.Companion.uriForId
-import fr.free.nrw.commons.explore.recentsearches.RecentSearchesTable.ALL_FIELDS
-import fr.free.nrw.commons.explore.recentsearches.RecentSearchesTable.COLUMN_ID
-import fr.free.nrw.commons.explore.recentsearches.RecentSearchesTable.COLUMN_LAST_USED
-import fr.free.nrw.commons.explore.recentsearches.RecentSearchesTable.COLUMN_NAME
-import fr.free.nrw.commons.explore.recentsearches.RecentSearchesTable.CREATE_TABLE_STATEMENT
-import fr.free.nrw.commons.explore.recentsearches.RecentSearchesTable.DROP_TABLE_STATEMENT
-import fr.free.nrw.commons.explore.recentsearches.RecentSearchesTable.onCreate
-import fr.free.nrw.commons.explore.recentsearches.RecentSearchesTable.onDelete
-import fr.free.nrw.commons.explore.recentsearches.RecentSearchesTable.onUpdate
+import org.hamcrest.CoreMatchers
+import org.hamcrest.MatcherAssert
+import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.Mockito.verifyNoInteractions
-import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
+import org.robolectric.annotation.LooperMode
import java.util.Date
-@RunWith(RobolectricTestRunner::class)
+@RunWith(AndroidJUnit4::class)
@Config(sdk = [21], application = TestCommonsApplication::class)
+@LooperMode(LooperMode.Mode.PAUSED)
class RecentSearchesDaoTest {
- private val columns = arrayOf(COLUMN_ID, COLUMN_NAME, COLUMN_LAST_USED)
- private val client: ContentProviderClient = mock()
- private val database: SupportSQLiteDatabase = mock()
- private val captor = argumentCaptor()
- private val queryCaptor = argumentCaptor>()
-
- private lateinit var testObject: RecentSearchesDao
+ private lateinit var recentSearchesRoomDao: RecentSearchesRoomDao
+ private lateinit var database: AppDatabase
@Before
- fun setUp() {
- testObject = RecentSearchesDao { client }
- }
-
- /**
- * Unit Test for creating a table for recent Searches
- */
- @Test
- fun createTable() {
- onCreate(database)
- verify(database).execSQL(CREATE_TABLE_STATEMENT)
- }
-
- /**
- * Unit Test for deleting table for recent Searches
- */
- @Test
- fun deleteTable() {
- onDelete(database)
- inOrder(database) {
- verify(database).execSQL(DROP_TABLE_STATEMENT)
- verify(database).execSQL(CREATE_TABLE_STATEMENT)
- }
- }
-
- /**
- * Unit Test for migrating from database version 1 to 2 for recent Searches Table
- */
- @Test
- fun migrateTableVersionFrom_v1_to_v2() {
- onUpdate(database, 1, 2)
- // Table didnt exist before v7
- verifyNoInteractions(database)
- }
-
- /**
- * Unit Test for migrating from database version 2 to 3 for recent Searches Table
- */
- @Test
- fun migrateTableVersionFrom_v2_to_v3() {
- onUpdate(database, 2, 3)
- // Table didnt exist before v7
- verifyNoInteractions(database)
- }
-
- /**
- * Unit Test for migrating from database version 3 to 4 for recent Searches Table
- */
- @Test
- fun migrateTableVersionFrom_v3_to_v4() {
- onUpdate(database, 3, 4)
- // Table didnt exist before v7
- verifyNoInteractions(database)
- }
-
- /**
- * Unit Test for migrating from database version 4 to 5 for recent Searches Table
- */
- @Test
- fun migrateTableVersionFrom_v4_to_v5() {
- onUpdate(database, 4, 5)
- // Table didnt exist before v7
- verifyNoInteractions(database)
- }
-
- /**
- * Unit Test for migrating from database version 5 to 6 for recent Searches Table
- */
- @Test
- fun migrateTableVersionFrom_v5_to_v6() {
- onUpdate(database, 5, 6)
- // Table didnt exist before v7
- verifyNoInteractions(database)
- }
-
- /**
- * Unit Test for migrating from database version 6 to 7 for recent Searches Table
- */
- @Test
- fun migrateTableVersionFrom_v6_to_v7() {
- onUpdate(database, 6, 7)
- verify(database).execSQL(CREATE_TABLE_STATEMENT)
- }
-
- /**
- * Unit Test for migrating from database version 7 to 8 for recent Searches Table
- */
- @Test
- fun migrateTableVersionFrom_v7_to_v8() {
- onUpdate(database, 7, 8)
- // Table didnt change in version 8
- verifyNoInteractions(database)
+ fun createDb() {
+ database =
+ inMemoryDatabaseBuilder(
+ context = ApplicationProvider.getApplicationContext(),
+ klass = AppDatabase::class.java,
+ ).allowMainThreadQueries().build()
+ recentSearchesRoomDao = database.recentSearchesRoomDao()
}
- /**
- * Unit Test for migrating from creating a row without using ID in recent Searches Table
- */
- @Test
- fun createFromCursor() {
- createCursor(1).let { cursor ->
- cursor.moveToFirst()
- testObject.fromCursor(cursor).let {
- assertEquals(uriForId(1), it.contentUri)
- assertEquals("butterfly", it.query)
- assertEquals(123, it.lastSearched.time)
- }
- }
+ @After
+ fun closeDb() {
+ database.close()
}
- /**
- * Unit Test for migrating from updating a row using contentUri in recent Searches Table
- */
@Test
fun saveExistingQuery() {
- createCursor(1).let {
- val recentSearch = testObject.fromCursor(it.apply { moveToFirst() })
+ // First insert
+ val recentSearch = RecentSearch("butterfly", Date(123L))
+ recentSearchesRoomDao.save(recentSearch).blockingAwait()
- testObject.save(recentSearch)
+ // Update it
+ val updatedSearch = RecentSearch("butterfly", Date(456L))
+ recentSearchesRoomDao.save(updatedSearch).blockingAwait()
- verify(client).update(eq(recentSearch.contentUri!!), captor.capture(), isNull(), isNull())
- captor.firstValue.let { cv ->
- assertEquals(2, cv.size())
- assertEquals(recentSearch.query, cv.getAsString(COLUMN_NAME))
- assertEquals(recentSearch.lastSearched.time, cv.getAsLong(COLUMN_LAST_USED))
- }
- }
+ // Verify update
+ val found = recentSearchesRoomDao.find("butterfly").blockingGet()
+ assertNotNull(found)
+ assertEquals(456L, found?.lastSearched?.time)
}
- /**
- * Unit Test for migrating from creating a row using ID in recent Searches Table
- */
@Test
fun saveNewQuery() {
- val contentUri = RecentSearchesContentProvider.uriForId(111)
- whenever(client.insert(isA(), isA())).thenReturn(contentUri)
- val recentSearch = RecentSearch(null, "butterfly", Date(234L))
+ val recentSearch = RecentSearch("butterfly", Date(123L))
+ recentSearchesRoomDao.save(recentSearch).blockingAwait()
- testObject.save(recentSearch)
-
- verify(client).insert(eq(BASE_URI), captor.capture())
- captor.firstValue.let { cv ->
- assertEquals(2, cv.size())
- assertEquals(recentSearch.query, cv.getAsString(COLUMN_NAME))
- assertEquals(recentSearch.lastSearched.time, cv.getAsLong(COLUMN_LAST_USED))
- assertEquals(contentUri, recentSearch.contentUri)
- }
- }
-
- /**
- * Unit Test for checking translation exceptions in searching a row from DB using recent search query
- */
- @Test(expected = RuntimeException::class)
- fun findRecentSearchTranslatesExceptions() {
- whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenThrow(RemoteException(""))
- testObject.find("butterfly")
- }
-
- /**
- * Unit Test for checking data if it's not present in searching a row from DB using recent search query
- */
- @Test
- fun whenTheresNoDataFindReturnsNull_nullCursor() {
- whenever(client.query(any(), any(), any(), any(), any())).thenReturn(null)
- assertNull(testObject.find("butterfly"))
- }
-
- /**
- * Unit Test for checking data if it's not present in searching a row from DB using recent search query
- */
- @Test
- fun whenTheresNoDataFindReturnsNull_emptyCursor() {
- whenever(client.query(any(), any(), any(), any(), any())).thenReturn(createCursor(0))
- assertNull(testObject.find("butterfly"))
- }
-
- /**
- * Unit Test for checking if cursor's are closed after use or not
- */
- @Test
- fun cursorsAreClosedAfterUse() {
- val mockCursor: Cursor = mock()
- whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(mockCursor)
- whenever(mockCursor.moveToFirst()).thenReturn(false)
-
- testObject.find("butterfly")
-
- verify(mockCursor).close()
+ val found = recentSearchesRoomDao.find("butterfly").blockingGet()
+ assertNotNull(found)
+ assertEquals("butterfly", found?.query)
}
- /**
- * Unit Test for checking search results after searching a row from DB using recent search query
- */
@Test
fun findRecentSearchQuery() {
- whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(createCursor(1))
-
- val recentSearch = testObject.find("butterfly")
- assertNotNull(recentSearch)
+ val recentSearch = RecentSearch("butterfly", Date(123L))
+ recentSearchesRoomDao.save(recentSearch).blockingAwait()
- assertEquals(uriForId(1), recentSearch?.contentUri)
- assertEquals("butterfly", recentSearch?.query)
- assertEquals(123L, recentSearch?.lastSearched?.time)
+ val found = recentSearchesRoomDao.find("butterfly").blockingGet()
+ assertNotNull(found)
+ assertEquals("butterfly", found?.query)
- verify(client).query(
- eq(BASE_URI),
- eq(ALL_FIELDS),
- eq("$COLUMN_NAME=?"),
- queryCaptor.capture(),
- isNull(),
- )
- assertEquals("butterfly", queryCaptor.firstValue[0])
+ val notFound = recentSearchesRoomDao.find("non existent").blockingGet()
+ assertNull(notFound)
}
- /**
- * Unit Test for checking if cursor's are closed after recent search query or not
- */
- @Test
- fun cursorsAreClosedAfterRecentSearchQuery() {
- val mockCursor: Cursor = mock()
- whenever(client.query(any(), any(), anyOrNull(), any(), any())).thenReturn(mockCursor)
- whenever(mockCursor.moveToFirst()).thenReturn(false)
-
- testObject.recentSearches(1)
-
- verify(mockCursor).close()
- }
-
- /**
- * Unit Test for checking when recent searches returns less than the limit
- */
- @Test
- fun recentSearchesReturnsLessThanLimit() {
- whenever(client.query(any(), any(), anyOrNull(), any(), any())).thenReturn(createCursor(1))
-
- val result = testObject.recentSearches(10)
-
- assertEquals(1, result.size)
- assertEquals("butterfly", result[0])
-
- verify(client).query(
- eq(BASE_URI),
- eq(ALL_FIELDS),
- isNull(),
- queryCaptor.capture(),
- eq("$COLUMN_LAST_USED DESC"),
- )
- assertEquals(0, queryCaptor.firstValue.size)
- }
-
- /**
- * Unit Test for checking size or list recieved from recent searches
- */
@Test
fun recentSearchesHonorsLimit() {
- whenever(client.query(any(), any(), anyOrNull(), any(), any())).thenReturn(createCursor(10))
-
- val result = testObject.recentSearches(5)
+ for (i in 1..10) {
+ recentSearchesRoomDao.save(RecentSearch("query $i", Date(i * 1000L))).blockingAwait()
+ }
- assertEquals(5, result.size)
+ val results = recentSearchesRoomDao.recentSearches(5).blockingGet()
+ assertEquals(5, results.size)
+ assertEquals("query 10", results[0])
}
-
- /**
- * Unit Test for creating entries in recent searches database.
- * @param rowCount No of rows
- */
- private fun createCursor(rowCount: Int) =
- MatrixCursor(columns, rowCount).apply {
- for (i in 0 until rowCount) {
- addRow(listOf("1", "butterfly", "123"))
- }
- }
}
diff --git a/app/src/test/kotlin/fr/free/nrw/commons/explore/recentsearches/RecentSearchesFragmentUnitTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/explore/recentsearches/RecentSearchesFragmentUnitTest.kt
index cd1186fc810..393351f4c80 100644
--- a/app/src/test/kotlin/fr/free/nrw/commons/explore/recentsearches/RecentSearchesFragmentUnitTest.kt
+++ b/app/src/test/kotlin/fr/free/nrw/commons/explore/recentsearches/RecentSearchesFragmentUnitTest.kt
@@ -12,6 +12,9 @@ import fr.free.nrw.commons.OkHttpConnectionFactory
import fr.free.nrw.commons.TestCommonsApplication
import fr.free.nrw.commons.contributions.MainActivity
import fr.free.nrw.commons.createTestClient
+import fr.free.nrw.commons.db.InMemoryDatabaseTest
+import fr.free.nrw.commons.explore.SearchActivity
+import io.reactivex.Single
import org.junit.Assert
import org.junit.Before
import org.junit.Test
@@ -35,7 +38,7 @@ class RecentSearchesFragmentUnitTest {
private lateinit var layoutInflater: LayoutInflater
@Mock
- private lateinit var recentSearchesDao: RecentSearchesDao
+ private lateinit var recentSearchesDao: RecentSearchesRoomDao
@Mock
private lateinit var adapter: ArrayAdapter<*>
@@ -53,7 +56,7 @@ class RecentSearchesFragmentUnitTest {
OkHttpConnectionFactory.CLIENT = createTestClient()
- val activity = Robolectric.buildActivity(MainActivity::class.java).create().get()
+ val activity = Robolectric.buildActivity(SearchActivity::class.java).create().get()
fragment = RecentSearchesFragment()
fragmentManager = activity.supportFragmentManager
val fragmentTransaction: FragmentTransaction = fragmentManager.beginTransaction()
@@ -65,6 +68,11 @@ class RecentSearchesFragmentUnitTest {
Whitebox.setInternalState(fragment, "recentSearchesDao", recentSearchesDao)
Whitebox.setInternalState(fragment, "adapter", adapter)
Whitebox.setInternalState(fragment, "recentSearches", listOf("string"))
+
+ // Default mock returns for Room DAO reactive methods
+ whenever(recentSearchesDao.recentSearches(10)).thenReturn(Single.just(emptyList()))
+ whenever(recentSearchesDao.deleteTable()).thenReturn(io.reactivex.Completable.complete())
+ whenever(recentSearchesDao.deleteAll()).thenReturn(io.reactivex.Completable.complete())
}
@Test
@@ -82,7 +90,7 @@ class RecentSearchesFragmentUnitTest {
@Test
@Throws(Exception::class)
fun testOnResume() {
- whenever(recentSearchesDao.recentSearches(10)).thenReturn(mutableListOf("search1"))
+ whenever(recentSearchesDao.recentSearches(10)).thenReturn(Single.just(mutableListOf("search1")))
fragment.onResume()
}
diff --git a/app/src/test/kotlin/fr/free/nrw/commons/explore/search/SearchActivityUnitTests.kt b/app/src/test/kotlin/fr/free/nrw/commons/explore/search/SearchActivityUnitTests.kt
index 00b9c0fd91a..c52ba99bc26 100644
--- a/app/src/test/kotlin/fr/free/nrw/commons/explore/search/SearchActivityUnitTests.kt
+++ b/app/src/test/kotlin/fr/free/nrw/commons/explore/search/SearchActivityUnitTests.kt
@@ -3,6 +3,7 @@ package fr.free.nrw.commons.explore.search
import android.content.Context
import androidx.fragment.app.FragmentManager
import androidx.test.core.app.ApplicationProvider
+import com.nhaarman.mockitokotlin2.any
import com.nhaarman.mockitokotlin2.verify
import fr.free.nrw.commons.Media
import fr.free.nrw.commons.TestCommonsApplication
@@ -11,10 +12,10 @@ import fr.free.nrw.commons.explore.SearchActivity
import fr.free.nrw.commons.explore.categories.search.SearchCategoryFragment
import fr.free.nrw.commons.explore.depictions.search.SearchDepictionsFragment
import fr.free.nrw.commons.explore.media.SearchMediaFragment
-import fr.free.nrw.commons.explore.models.RecentSearch
-import fr.free.nrw.commons.explore.recentsearches.RecentSearchesDao
import fr.free.nrw.commons.explore.recentsearches.RecentSearchesFragment
+import fr.free.nrw.commons.explore.recentsearches.RecentSearchesRoomDao
import fr.free.nrw.commons.media.MediaDetailPagerFragment
+import io.reactivex.Completable
import io.reactivex.disposables.CompositeDisposable
import org.junit.Assert
import org.junit.Before
@@ -50,7 +51,7 @@ class SearchActivityUnitTests {
private lateinit var viewPagerAdapter: ViewPagerAdapter
@Mock
- private lateinit var recentSearchesDao: RecentSearchesDao
+ private lateinit var recentSearchesDao: RecentSearchesRoomDao
@Mock
private lateinit var searchMediaFragment: SearchMediaFragment
@@ -125,11 +126,12 @@ class SearchActivityUnitTests {
fun testSaveRecentSearchCaseNull() {
val query = "test"
Whitebox.setInternalState(activity, "recentSearchesDao", recentSearchesDao)
+ `when`(recentSearchesDao.save(any())).thenReturn(Completable.complete())
val method: Method =
SearchActivity::class.java.getDeclaredMethod("saveRecentSearch", String::class.java)
method.isAccessible = true
method.invoke(activity, query)
- verify(recentSearchesDao).find(query)
+ verify(recentSearchesDao).save(any())
}
@Test
@@ -137,12 +139,12 @@ class SearchActivityUnitTests {
fun testSaveRecentSearchCaseNonNull() {
val query = "test"
Whitebox.setInternalState(activity, "recentSearchesDao", recentSearchesDao)
- `when`(recentSearchesDao.find(query)).thenReturn(mock(RecentSearch::class.java))
+ `when`(recentSearchesDao.save(any())).thenReturn(Completable.complete())
val method: Method =
SearchActivity::class.java.getDeclaredMethod("saveRecentSearch", String::class.java)
method.isAccessible = true
method.invoke(activity, query)
- verify(recentSearchesDao).find(query)
+ verify(recentSearchesDao).save(any())
}
@Test
@@ -204,6 +206,8 @@ class SearchActivityUnitTests {
`when`(searchMediaFragment.isRemoving).thenReturn(false)
`when`(searchCategoryFragment.isRemoving).thenReturn(false)
+ `when`(recentSearchesDao.save(any())).thenReturn(Completable.complete())
+
val method: Method =
SearchActivity::class.java.getDeclaredMethod(
"handleSearch",
@@ -211,7 +215,6 @@ class SearchActivityUnitTests {
)
method.isAccessible = true
method.invoke(activity, query)
- verify(recentSearchesDao).find(query)
verify(searchDepictionsFragment).onQueryUpdated(query)
verify(searchMediaFragment).onQueryUpdated(query)
verify(searchCategoryFragment).onQueryUpdated(query)
diff --git a/app/src/test/kotlin/fr/free/nrw/commons/recentlanguages/RecentLanguagesDaoUnitTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/recentlanguages/RecentLanguagesDaoUnitTest.kt
index 4c9c9b96bc0..2c7d2c84e9b 100644
--- a/app/src/test/kotlin/fr/free/nrw/commons/recentlanguages/RecentLanguagesDaoUnitTest.kt
+++ b/app/src/test/kotlin/fr/free/nrw/commons/recentlanguages/RecentLanguagesDaoUnitTest.kt
@@ -1,323 +1,79 @@
package fr.free.nrw.commons.recentlanguages
-import android.content.ContentProviderClient
-import android.content.ContentValues
-import android.database.Cursor
-import android.database.MatrixCursor
-import android.os.RemoteException
-import androidx.sqlite.db.SupportSQLiteDatabase
-import com.nhaarman.mockitokotlin2.anyOrNull
-import com.nhaarman.mockitokotlin2.argumentCaptor
-import com.nhaarman.mockitokotlin2.inOrder
-import com.nhaarman.mockitokotlin2.mock
-import com.nhaarman.mockitokotlin2.whenever
+import androidx.room.Room.inMemoryDatabaseBuilder
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
import fr.free.nrw.commons.TestCommonsApplication
-import fr.free.nrw.commons.recentlanguages.RecentLanguagesTable.COLUMN_CODE
-import fr.free.nrw.commons.recentlanguages.RecentLanguagesTable.COLUMN_NAME
-import fr.free.nrw.commons.recentlanguages.RecentLanguagesTable.CREATE_TABLE_STATEMENT
-import fr.free.nrw.commons.recentlanguages.RecentLanguagesTable.DROP_TABLE_STATEMENT
-import fr.free.nrw.commons.recentlanguages.RecentLanguagesTable.onCreate
-import fr.free.nrw.commons.recentlanguages.RecentLanguagesTable.onDelete
-import fr.free.nrw.commons.recentlanguages.RecentLanguagesTable.onUpdate
-import org.junit.Assert
+import fr.free.nrw.commons.db.AppDatabase
+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.ArgumentMatchers.any
-import org.mockito.ArgumentMatchers.eq
-import org.mockito.Mockito.verify
-import org.mockito.Mockito.verifyNoInteractions
-import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
+import org.robolectric.annotation.LooperMode
-@RunWith(RobolectricTestRunner::class)
+@RunWith(AndroidJUnit4::class)
@Config(sdk = [21], application = TestCommonsApplication::class)
+@LooperMode(LooperMode.Mode.PAUSED)
class RecentLanguagesDaoUnitTest {
- private val columns =
- arrayOf(
- COLUMN_NAME,
- COLUMN_CODE,
- )
-
- private val client: ContentProviderClient = mock()
- private val database: SupportSQLiteDatabase = mock()
- private val captor = argumentCaptor()
-
- private lateinit var testObject: RecentLanguagesDao
+ private lateinit var recentLanguagesRoomDao: RecentLanguagesRoomDao
+ private lateinit var database: AppDatabase
private lateinit var exampleLanguage: Language
- /**
- * Set up Test Language and RecentLanguagesDao
- */
@Before
- fun setUp() {
+ fun createDb() {
+ database =
+ inMemoryDatabaseBuilder(
+ context = ApplicationProvider.getApplicationContext(),
+ klass = AppDatabase::class.java,
+ ).allowMainThreadQueries().build()
+ recentLanguagesRoomDao = database.recentLanguagesRoomDao()
exampleLanguage = Language("English", "en")
- testObject = RecentLanguagesDao { client }
}
- @Test
- fun createTable() {
- onCreate(database)
- verify(database).execSQL(CREATE_TABLE_STATEMENT)
- }
-
- @Test
- fun deleteTable() {
- onDelete(database)
- inOrder(database) {
- verify(database).execSQL(DROP_TABLE_STATEMENT)
- }
- }
-
- @Test
- fun createFromCursor() {
- createCursor(1).let { cursor ->
- cursor.moveToFirst()
- testObject.fromCursor(cursor).let {
- Assert.assertEquals("languageName", it.languageName)
- Assert.assertEquals("languageCode", it.languageCode)
- }
- }
+ @After
+ fun closeDb() {
+ database.close()
}
@Test
fun testGetRecentLanguages() {
- whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull()))
- .thenReturn(createCursor(14))
-
- val result = testObject.getRecentLanguages()
-
- Assert.assertEquals(14, (result.size))
- }
-
- @Test(expected = RuntimeException::class)
- fun getGetRecentLanguagesTranslatesExceptions() {
- whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull())).thenThrow(
- RemoteException(""),
- )
- testObject.getRecentLanguages()
- }
-
- @Test
- fun getGetRecentLanguagesReturnsEmptyList_emptyCursor() {
- whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull()))
- .thenReturn(createCursor(0))
- Assert.assertTrue(testObject.getRecentLanguages().isEmpty())
- }
-
- @Test
- fun getGetRecentLanguagesReturnsEmptyList_nullCursor() {
- whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull())).thenReturn(null)
- Assert.assertTrue(testObject.getRecentLanguages().isEmpty())
- }
-
- @Test
- fun cursorsAreClosedAfterGetRecentLanguages() {
- val mockCursor: Cursor = mock()
- whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull())).thenReturn(mockCursor)
- whenever(mockCursor.moveToFirst()).thenReturn(false)
-
- testObject.getRecentLanguages()
+ for (i in 1..5) {
+ recentLanguagesRoomDao.addRecentLanguage(Language("Lang$i", "code$i")).blockingAwait()
+ }
- verify(mockCursor).close()
+ val result = recentLanguagesRoomDao.getRecentLanguages().blockingGet()
+ assertEquals(5, result.size)
}
@Test
fun findExistingLanguage() {
- whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(createCursor(1))
- Assert.assertTrue(testObject.findRecentLanguage(exampleLanguage.languageCode))
- }
-
- @Test(expected = RuntimeException::class)
- fun findLanguageTranslatesExceptions() {
- whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull())).thenThrow(
- RemoteException(""),
- )
- testObject.findRecentLanguage(exampleLanguage.languageCode)
- }
-
- @Test
- fun findNotExistingLanguageReturnsNull_emptyCursor() {
- whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(createCursor(0))
- Assert.assertFalse(testObject.findRecentLanguage(exampleLanguage.languageCode))
- }
-
- @Test
- fun findNotExistingLanguageReturnsNull_nullCursor() {
- whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(null)
- Assert.assertFalse(testObject.findRecentLanguage(exampleLanguage.languageCode))
- }
-
- @Test
- fun cursorsAreClosedAfterFindLanguageQuery() {
- val mockCursor: Cursor = mock()
- whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(mockCursor)
- whenever(mockCursor.moveToFirst()).thenReturn(false)
-
- testObject.findRecentLanguage(exampleLanguage.languageCode)
-
- verify(mockCursor).close()
- }
-
- @Test
- fun migrateTableVersionFrom_v1_to_v2() {
- onUpdate(database, 1, 2)
- // Table didnt exist before v7
- verifyNoInteractions(database)
- }
-
- @Test
- fun migrateTableVersionFrom_v2_to_v3() {
- onUpdate(database, 2, 3)
- // Table didnt exist before v7
- verifyNoInteractions(database)
- }
-
- @Test
- fun migrateTableVersionFrom_v3_to_v4() {
- onUpdate(database, 3, 4)
- // Table didnt exist before v7
- verifyNoInteractions(database)
- }
-
- @Test
- fun migrateTableVersionFrom_v4_to_v5() {
- onUpdate(database, 4, 5)
- // Table didnt exist before v7
- verifyNoInteractions(database)
+ recentLanguagesRoomDao.addRecentLanguage(exampleLanguage).blockingAwait()
+ assertTrue(recentLanguagesRoomDao.findRecentLanguage(exampleLanguage.languageCode).blockingGet())
}
@Test
- fun migrateTableVersionFrom_v5_to_v6() {
- onUpdate(database, 5, 6)
- // Table didnt exist in version 6
- verifyNoInteractions(database)
- }
-
- @Test
- fun migrateTableVersionFrom_v6_to_v7() {
- onUpdate(database, 6, 7)
- // Table didnt exist in version 7
- verifyNoInteractions(database)
- }
-
- @Test
- fun migrateTableVersionFrom_v7_to_v8() {
- onUpdate(database, 7, 8)
- // Table didnt exist in version 8
- verifyNoInteractions(database)
- }
-
- @Test
- fun migrateTableVersionFrom_v8_to_v9() {
- onUpdate(database, 8, 9)
- // Table didnt exist in version 9
- verifyNoInteractions(database)
- }
-
- @Test
- fun migrateTableVersionFrom_v9_to_v10() {
- onUpdate(database, 9, 10)
- // Table didnt exist in version 10
- verifyNoInteractions(database)
- }
-
- @Test
- fun migrateTableVersionFrom_v10_to_v11() {
- onUpdate(database, 10, 11)
- // Table didnt exist in version 11
- verifyNoInteractions(database)
- }
-
- @Test
- fun migrateTableVersionFrom_v11_to_v12() {
- onUpdate(database, 11, 12)
- // Table didnt exist in version 12
- verifyNoInteractions(database)
- }
-
- @Test
- fun migrateTableVersionFrom_v12_to_v13() {
- onUpdate(database, 12, 13)
- // Table didnt exist in version 13
- verifyNoInteractions(database)
- }
-
- @Test
- fun migrateTableVersionFrom_v13_to_v14() {
- onUpdate(database, 13, 14)
- // Table didnt exist in version 14
- verifyNoInteractions(database)
- }
-
- @Test
- fun migrateTableVersionFrom_v14_to_v15() {
- onUpdate(database, 14, 15)
- // Table didnt exist in version 15
- verifyNoInteractions(database)
- }
-
- @Test
- fun migrateTableVersionFrom_v15_to_v16() {
- onUpdate(database, 15, 16)
- // Table didnt exist in version 16
- verifyNoInteractions(database)
- }
-
- @Test
- fun migrateTableVersionFrom_v16_to_v17() {
- onUpdate(database, 16, 17)
- // Table didnt exist in version 17
- verifyNoInteractions(database)
- }
-
- @Test
- fun migrateTableVersionFrom_v18_to_v19() {
- onUpdate(database, 18, 19)
- // Table didnt exist in version 18
- verifyNoInteractions(database)
- }
-
- @Test
- fun migrateTableVersionFrom_v19_to_v20() {
- onUpdate(database, 19, 20)
- verify(database).execSQL(CREATE_TABLE_STATEMENT)
- }
-
- @Test
- fun migrateTableVersionFrom_v20_to_v20() {
- onUpdate(database, 20, 20)
- verifyNoInteractions(database)
+ fun findNotExistingLanguage() {
+ assertFalse(recentLanguagesRoomDao.findRecentLanguage(exampleLanguage.languageCode).blockingGet())
}
@Test
fun testAddNewLanguage() {
- testObject.addRecentLanguage(exampleLanguage)
-
- verify(client).insert(eq(RecentLanguagesContentProvider.BASE_URI), captor.capture())
- captor.firstValue.let { cv ->
- Assert.assertEquals(2, cv.size())
- Assert.assertEquals(
- exampleLanguage.languageName,
- cv.getAsString(COLUMN_NAME),
- )
- Assert.assertEquals(
- exampleLanguage.languageCode,
- cv.getAsString(COLUMN_CODE),
- )
- }
+ recentLanguagesRoomDao.addRecentLanguage(exampleLanguage).blockingAwait()
+ val result = recentLanguagesRoomDao.getRecentLanguages().blockingGet()
+ assertEquals(1, result.size)
+ assertEquals(exampleLanguage.languageName, result[0].languageName)
}
@Test
fun testDeleteLanguage() {
- testObject.addRecentLanguage(exampleLanguage)
- testObject.deleteRecentLanguage(exampleLanguage.languageCode)
- }
+ recentLanguagesRoomDao.addRecentLanguage(exampleLanguage).blockingAwait()
+ assertTrue(recentLanguagesRoomDao.findRecentLanguage(exampleLanguage.languageCode).blockingGet())
- private fun createCursor(rowCount: Int) =
- MatrixCursor(columns, rowCount).apply {
- for (i in 0 until rowCount) {
- addRow(listOf("languageName", "languageCode"))
- }
- }
+ recentLanguagesRoomDao.deleteRecentLanguage(exampleLanguage.languageCode).blockingAwait()
+ assertFalse(recentLanguagesRoomDao.findRecentLanguage(exampleLanguage.languageCode).blockingGet())
+ }
}
diff --git a/app/src/test/kotlin/fr/free/nrw/commons/review/ReviewDaoTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/review/ReviewDaoTest.kt
index 96aacf6f848..7cf0bd2e6c5 100644
--- a/app/src/test/kotlin/fr/free/nrw/commons/review/ReviewDaoTest.kt
+++ b/app/src/test/kotlin/fr/free/nrw/commons/review/ReviewDaoTest.kt
@@ -51,8 +51,8 @@ class ReviewDaoTest {
fun insert() {
// Insert data
val imageId = "1234"
- val reviewEntity = ReviewEntity(imageId)
- reviewDao.insert(reviewEntity)
+ val reviewImage = ReviewImage(imageId)
+ reviewDao.insert(reviewImage)
// Check insertion
// Covers the case where the image exists in the database
diff --git a/app/src/test/kotlin/fr/free/nrw/commons/settings/SettingsFragmentUnitTests.kt b/app/src/test/kotlin/fr/free/nrw/commons/settings/SettingsFragmentUnitTests.kt
index acd56c5f4b0..bd64ded5f36 100644
--- a/app/src/test/kotlin/fr/free/nrw/commons/settings/SettingsFragmentUnitTests.kt
+++ b/app/src/test/kotlin/fr/free/nrw/commons/settings/SettingsFragmentUnitTests.kt
@@ -18,7 +18,7 @@ import com.nhaarman.mockitokotlin2.whenever
import fr.free.nrw.commons.TestCommonsApplication
import fr.free.nrw.commons.recentlanguages.Language
import fr.free.nrw.commons.recentlanguages.RecentLanguagesAdapter
-import fr.free.nrw.commons.recentlanguages.RecentLanguagesDao
+import fr.free.nrw.commons.recentlanguages.RecentLanguagesRoomDao
import fr.free.nrw.commons.settings.SettingsFragment.Companion.createLocale
import org.junit.Assert
import org.junit.Assert.assertEquals
@@ -47,7 +47,7 @@ class SettingsFragmentUnitTests {
private lateinit var context: Context
@Mock
- private lateinit var recentLanguagesDao: RecentLanguagesDao
+ private lateinit var recentLanguagesDao: RecentLanguagesRoomDao
@Mock
private lateinit var recentLanguagesTextView: TextView
@@ -87,6 +87,16 @@ class SettingsFragmentUnitTests {
"languageHistoryListView",
languageHistoryListView,
)
+
+ // Default mock returns for Room DAO reactive methods
+ whenever(recentLanguagesDao.getRecentLanguages())
+ .thenReturn(io.reactivex.Single.just(emptyList()))
+ whenever(recentLanguagesDao.findRecentLanguage(any()))
+ .thenReturn(io.reactivex.Single.just(false))
+ whenever(recentLanguagesDao.deleteRecentLanguage(any()))
+ .thenReturn(io.reactivex.Completable.complete())
+ whenever(recentLanguagesDao.addRecentLanguage(any()))
+ .thenReturn(io.reactivex.Completable.complete())
}
@Test
@@ -165,13 +175,15 @@ class SettingsFragmentUnitTests {
Shadows.shadowOf(Looper.getMainLooper()).idle()
whenever(recentLanguagesDao.getRecentLanguages())
.thenReturn(
- mutableListOf(
- Language("English", "en"),
- Language("English", "en"),
- Language("English", "en"),
- Language("English", "en"),
- Language("English", "en"),
- Language("English", "en"),
+ io.reactivex.Single.just(
+ mutableListOf(
+ Language("English", "en"),
+ Language("English", "en"),
+ Language("English", "en"),
+ Language("English", "en"),
+ Language("English", "en"),
+ Language("English", "en"),
+ )
),
)
val method: Method =
@@ -217,7 +229,7 @@ class SettingsFragmentUnitTests {
@Throws(Exception::class)
fun testOnRecentLanguageClicked() {
whenever(recentLanguagesDao.findRecentLanguage(any()))
- .thenReturn(true)
+ .thenReturn(io.reactivex.Single.just(true))
whenever(adapterView.adapter)
.thenReturn(
RecentLanguagesAdapter(
diff --git a/app/src/test/kotlin/fr/free/nrw/commons/upload/UploadMediaDetailAdapterUnitTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/upload/UploadMediaDetailAdapterUnitTest.kt
index 7cc59b78dd1..15e6af02059 100644
--- a/app/src/test/kotlin/fr/free/nrw/commons/upload/UploadMediaDetailAdapterUnitTest.kt
+++ b/app/src/test/kotlin/fr/free/nrw/commons/upload/UploadMediaDetailAdapterUnitTest.kt
@@ -17,8 +17,9 @@ import com.nhaarman.mockitokotlin2.whenever
import fr.free.nrw.commons.TestCommonsApplication
import fr.free.nrw.commons.recentlanguages.Language
import fr.free.nrw.commons.recentlanguages.RecentLanguagesAdapter
-import fr.free.nrw.commons.recentlanguages.RecentLanguagesDao
+import fr.free.nrw.commons.recentlanguages.RecentLanguagesRoomDao
import fr.free.nrw.commons.upload.mediaDetails.UploadMediaDetailFragment
+import io.reactivex.Single
import org.junit.Assert
import org.junit.Before
import org.junit.Test
@@ -52,7 +53,7 @@ class UploadMediaDetailAdapterUnitTest {
private lateinit var eventListener: UploadMediaDetailAdapter.EventListener
@Mock
- private lateinit var recentLanguagesDao: RecentLanguagesDao
+ private lateinit var recentLanguagesDao: RecentLanguagesRoomDao
@Mock
private lateinit var textView: TextView
@@ -78,6 +79,17 @@ class UploadMediaDetailAdapterUnitTest {
uploadMediaDetails = mutableListOf(uploadMediaDetail, uploadMediaDetail)
activity = Robolectric.buildActivity(UploadActivity::class.java).get()
fragment = mock(UploadMediaDetailFragment::class.java)
+
+ // Default mock returns for Room DAO reactive methods
+ whenever(recentLanguagesDao.getRecentLanguages())
+ .thenReturn(Single.just(emptyList()))
+ whenever(recentLanguagesDao.findRecentLanguage(com.nhaarman.mockitokotlin2.any()))
+ .thenReturn(Single.just(false))
+ whenever(recentLanguagesDao.deleteRecentLanguage(com.nhaarman.mockitokotlin2.any()))
+ .thenReturn(io.reactivex.Completable.complete())
+ whenever(recentLanguagesDao.addRecentLanguage(com.nhaarman.mockitokotlin2.any()))
+ .thenReturn(io.reactivex.Completable.complete())
+
adapter = UploadMediaDetailAdapter(fragment, "", recentLanguagesDao, mockResultLauncher)
context = ApplicationProvider.getApplicationContext()
Whitebox.setInternalState(adapter, "uploadMediaDetails", uploadMediaDetails)
@@ -240,7 +252,7 @@ class UploadMediaDetailAdapterUnitTest {
@Throws(Exception::class)
fun testOnRecentLanguageClicked() {
whenever(recentLanguagesDao.findRecentLanguage(any()))
- .thenReturn(true)
+ .thenReturn(Single.just(true))
whenever(adapterView.adapter)
.thenReturn(
RecentLanguagesAdapter(
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index f9ae80547be..9504a5b2dd3 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -70,6 +70,7 @@ soloader = "0.10.5"
timber = "4.7.1"
uiautomator = "2.2.0"
workManager = "2.8.1"
+roomKtx = "2.8.4"
[libraries]
# AndroidX Core Dependencies
@@ -202,6 +203,7 @@ coordinates2country-android = { module = "io.github.coordinates2country:coordina
osmdroid-android = { module = "org.osmdroid:osmdroid-android", version.ref = "osmdroidAndroid" }
kotlin-stdlib-jdk7 = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib-jdk7", version.ref = "kotlinStdlib" }
kotlin-stdlib-jdk8 = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib-jdk8", version.ref = "kotlinStdlib" }
+room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "roomKtx" }
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }