Skip to content

Commit 4fa18e5

Browse files
In depictions selection screen, suggest recently selected items (commons-app#4361)
* implement in depictions selection screen to suggest recently selected items *use RoomDataBase * Add Javadoc * fix an bug * minar change and remove extra line of code * minar changes * improve implemention strategy * fix unittest * Add javadoc * added javadoc
1 parent 18cfc89 commit 4fa18e5

File tree

10 files changed

+196
-16
lines changed

10 files changed

+196
-16
lines changed

app/src/main/java/fr/free/nrw/commons/db/AppDatabase.kt

+4-1
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,16 @@ import androidx.room.RoomDatabase
55
import androidx.room.TypeConverters
66
import fr.free.nrw.commons.contributions.Contribution
77
import fr.free.nrw.commons.contributions.ContributionDao
8+
import fr.free.nrw.commons.upload.depicts.Depicts
9+
import fr.free.nrw.commons.upload.depicts.DepictsDao
810

911
/**
1012
* The database for accessing the respective DAOs
1113
*
1214
*/
13-
@Database(entities = [Contribution::class], version = 7, exportSchema = false)
15+
@Database(entities = [Contribution::class,Depicts::class], version = 7, exportSchema = false)
1416
@TypeConverters(Converters::class)
1517
abstract class AppDatabase : RoomDatabase() {
1618
abstract fun contributionDao(): ContributionDao
19+
abstract fun DepictsDao (): DepictsDao;
1720
}

app/src/main/java/fr/free/nrw/commons/db/Converters.java

+21
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,27 @@ public static Gson getGson() {
2323
return ApplicationlessInjection.getInstance(CommonsApplication.getInstance()).getCommonsApplicationComponent().gson();
2424
}
2525

26+
/**
27+
* convert DepictedItem object to string
28+
* input Example -> DepictedItem depictedItem=new DepictedItem ()
29+
* output Example -> string
30+
*/
31+
@TypeConverter
32+
public static String depictsItemToString(DepictedItem objects) {
33+
return writeObjectToString(objects);
34+
}
35+
36+
/**
37+
* convert string to DepictedItem object
38+
* output Example -> DepictedItem depictedItem=new DepictedItem ()
39+
* input Example -> string
40+
*/
41+
@TypeConverter
42+
public static DepictedItem stringToDepicts(String objectList) {
43+
return readObjectWithTypeToken(objectList, new TypeToken<DepictedItem>() {
44+
});
45+
}
46+
2647
@TypeConverter
2748
public static Date fromTimestamp(Long value) {
2849
return value == null ? null : new Date(value);

app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationModule.java

+9
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import fr.free.nrw.commons.location.LocationServiceManager;
2424
import fr.free.nrw.commons.settings.Prefs;
2525
import fr.free.nrw.commons.upload.UploadController;
26+
import fr.free.nrw.commons.upload.depicts.DepictsDao;
2627
import fr.free.nrw.commons.utils.ConfigUtils;
2728
import fr.free.nrw.commons.wikidata.WikidataEditListener;
2829
import fr.free.nrw.commons.wikidata.WikidataEditListenerImpl;
@@ -242,6 +243,14 @@ public ContributionDao providesContributionsDao(AppDatabase appDatabase) {
242243
return appDatabase.contributionDao();
243244
}
244245

246+
/**
247+
* Get the reference of DepictsDao class
248+
*/
249+
@Provides
250+
public DepictsDao providesDepictDao(AppDatabase appDatabase) {
251+
return appDatabase.DepictsDao();
252+
}
253+
245254
@Provides
246255
public ContentResolver providesContentResolver(Context context){
247256
return context.getContentResolver();

app/src/main/java/fr/free/nrw/commons/upload/UploadModel.java

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import fr.free.nrw.commons.kvstore.JsonKvStore;
99
import fr.free.nrw.commons.nearby.Place;
1010
import fr.free.nrw.commons.settings.Prefs;
11+
import fr.free.nrw.commons.upload.depicts.DepictsFragment;
1112
import fr.free.nrw.commons.upload.structure.depictions.DepictedItem;
1213
import io.reactivex.Observable;
1314
import io.reactivex.Single;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package fr.free.nrw.commons.upload.depicts
2+
3+
import androidx.room.Entity
4+
import androidx.room.PrimaryKey
5+
import fr.free.nrw.commons.upload.structure.depictions.DepictedItem
6+
import java.util.*
7+
8+
/**
9+
* entity class for DepictsRoomDateBase
10+
*/
11+
@Entity(tableName = "depicts_table")
12+
data class Depicts (@PrimaryKey val item: DepictedItem, val lastUsed:Date)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
package fr.free.nrw.commons.upload.depicts
2+
3+
import androidx.room.*
4+
import fr.free.nrw.commons.upload.structure.depictions.DepictedItem
5+
import kotlinx.coroutines.Dispatchers
6+
import kotlinx.coroutines.launch
7+
import kotlinx.coroutines.runBlocking
8+
import java.util.*
9+
10+
/**
11+
* Dao class for DepictsRoomDataBase
12+
*/
13+
@Dao
14+
abstract class DepictsDao {
15+
16+
/**
17+
* insert Depicts in DepictsRoomDataBase
18+
*/
19+
@Insert(onConflict = OnConflictStrategy.REPLACE)
20+
abstract suspend fun insert(depictedItem: Depicts)
21+
22+
/**
23+
* get all Depicts from roomdatabase
24+
*/
25+
@Query("Select * From depicts_table order by lastUsed DESC")
26+
abstract suspend fun getAllDepict(): List<Depicts>
27+
28+
/**
29+
* get all Depicts which need to delete from roomdatabase
30+
*/
31+
@Query("Select * From depicts_table order by lastUsed DESC LIMIT :n OFFSET 10")
32+
abstract suspend fun getItemToDelete(n: Int): List<Depicts>
33+
34+
/**
35+
* Delete Depicts from roomdatabase
36+
*/
37+
@Delete
38+
abstract suspend fun delete(depicts: Depicts)
39+
40+
lateinit var allDepict: List<Depicts>
41+
lateinit var listOfDelete: List<Depicts>
42+
43+
/**
44+
* get all depicts from DepictsRoomDatabase
45+
*/
46+
fun depictsList(): List<Depicts> {
47+
runBlocking {
48+
launch(Dispatchers.IO) {
49+
allDepict = getAllDepict()
50+
}
51+
}
52+
return allDepict
53+
}
54+
55+
/**
56+
* insert Depicts in DepictsRoomDataBase
57+
*/
58+
fun insertDepict(depictes: Depicts) {
59+
runBlocking {
60+
launch(Dispatchers.IO) {
61+
insert(depictes)
62+
}
63+
}
64+
}
65+
66+
/**
67+
* get all Depicts item which need to delete
68+
*/
69+
fun getItemTodelete(number: Int): List<Depicts> {
70+
runBlocking {
71+
launch(Dispatchers.IO) {
72+
listOfDelete = getItemToDelete(number)
73+
}
74+
}
75+
return listOfDelete
76+
}
77+
78+
/**
79+
* delete Depicts in DepictsRoomDataBase
80+
*/
81+
fun deleteDepicts(depictes: Depicts) {
82+
runBlocking {
83+
launch(Dispatchers.IO) {
84+
delete(depictes)
85+
}
86+
}
87+
}
88+
89+
/**
90+
* save Depicts in DepictsRoomDataBase
91+
*/
92+
fun savingDepictsInRoomDataBase(listDepictedItem: List<DepictedItem>) {
93+
var numberofItemInRoomDataBase: Int
94+
val maxNumberOfItemSaveInRoom = 10
95+
96+
for (depictsItem in listDepictedItem) {
97+
depictsItem.isSelected = false
98+
insertDepict(Depicts(depictsItem, Date()))
99+
}
100+
101+
numberofItemInRoomDataBase = depictsList().size
102+
// delete the depictItem from depictsroomdataBase when number of element in depictsroomdataBase is greater than 10
103+
if (numberofItemInRoomDataBase > maxNumberOfItemSaveInRoom) {
104+
105+
val listOfDepictsToDelete: List<Depicts> =
106+
getItemTodelete(numberofItemInRoomDataBase)
107+
for (i in listOfDepictsToDelete) {
108+
deleteDepicts(i)
109+
}
110+
}
111+
}
112+
}

app/src/main/java/fr/free/nrw/commons/upload/depicts/DepictsFragment.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,12 @@
2121
import com.jakewharton.rxbinding2.widget.RxTextView;
2222
import fr.free.nrw.commons.R;
2323
import fr.free.nrw.commons.upload.UploadBaseFragment;
24+
import fr.free.nrw.commons.upload.UploadModel;
2425
import fr.free.nrw.commons.upload.structure.depictions.DepictedItem;
2526
import fr.free.nrw.commons.utils.DialogUtil;
2627
import io.reactivex.android.schedulers.AndroidSchedulers;
2728
import io.reactivex.disposables.Disposable;
29+
import java.util.ArrayList;
2830
import java.util.List;
2931
import java.util.concurrent.TimeUnit;
3032
import javax.inject.Inject;
@@ -54,7 +56,6 @@ public class DepictsFragment extends UploadBaseFragment implements DepictsContra
5456
DepictsContract.UserActionListener presenter;
5557
private UploadDepictsAdapter adapter;
5658
private Disposable subscribe;
57-
5859
@Nullable
5960
@Override
6061
public android.view.View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@@ -174,8 +175,7 @@ private void addTextChangeListenerToSearchBox() {
174175
*
175176
* @param query query string
176177
*/
177-
private void searchForDepictions(String query) {
178+
private void searchForDepictions(final String query) {
178179
presenter.searchForDepictions(query);
179180
}
180-
181181
}

app/src/main/java/fr/free/nrw/commons/upload/depicts/DepictsPresenter.kt

+28-3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import io.reactivex.disposables.CompositeDisposable
1212
import io.reactivex.processors.PublishProcessor
1313
import timber.log.Timber
1414
import java.lang.reflect.Proxy
15+
import java.util.*
1516
import javax.inject.Inject
1617
import javax.inject.Named
1718
import javax.inject.Singleton
@@ -34,6 +35,8 @@ class DepictsPresenter @Inject constructor(
3435
private val compositeDisposable: CompositeDisposable = CompositeDisposable()
3536
private val searchTerm: PublishProcessor<String> = PublishProcessor.create()
3637
private val depictedItems: MutableLiveData<List<DepictedItem>> = MutableLiveData()
38+
@Inject
39+
lateinit var depictsDao: DepictsDao;
3740

3841
override fun onAttachView(view: DepictsContract.View) {
3942
this.view = view
@@ -62,10 +65,15 @@ class DepictsPresenter @Inject constructor(
6265
return searchResults(term).map { Pair(it, term) }
6366
}
6467

65-
private fun searchResults(it: String): Flowable<List<DepictedItem>> {
66-
return repository.searchAllEntities(it)
68+
private fun searchResults(querystring: String): Flowable<List<DepictedItem>> {
69+
var recentDepictedItemList: MutableList<DepictedItem> = ArrayList();
70+
//show recentDepictedItemList when queryString is empty
71+
if (querystring.isEmpty()) {
72+
recentDepictedItemList = getRecentDepictedItems();
73+
}
74+
return repository.searchAllEntities(querystring)
6775
.subscribeOn(ioScheduler)
68-
.map { repository.selectedDepictions + it }
76+
.map { repository.selectedDepictions + it + recentDepictedItemList }
6977
.map { it.filterNot { item -> WikidataDisambiguationItems.isDisambiguationItem(item.instanceOfs) } }
7078
.map { it.distinctBy(DepictedItem::id) }
7179
}
@@ -102,11 +110,28 @@ class DepictsPresenter @Inject constructor(
102110
*/
103111
override fun verifyDepictions() {
104112
if (repository.selectedDepictions.isNotEmpty()) {
113+
if (::depictsDao.isInitialized) {
114+
//save all the selected Depicted item in room Database
115+
depictsDao.savingDepictsInRoomDataBase(repository.selectedDepictions)
116+
}
105117
view.goToNextScreen()
106118
} else {
107119
view.noDepictionSelected()
108120
}
109121
}
122+
123+
/**
124+
* Get the depicts from DepictsRoomdataBase
125+
*/
126+
fun getRecentDepictedItems(): MutableList<DepictedItem> {
127+
val depictedItemList: MutableList<DepictedItem> = ArrayList()
128+
val depictsList = depictsDao.depictsList()
129+
for (i in depictsList.indices) {
130+
val depictedItem = depictsList[i].item
131+
depictedItemList.add(depictedItem)
132+
}
133+
return depictedItemList
134+
}
110135
}
111136

112137
/**

app/src/main/java/fr/free/nrw/commons/upload/structure/depictions/DepictedItem.kt

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package fr.free.nrw.commons.upload.structure.depictions
22

33
import android.os.Parcelable
4+
import androidx.room.Entity
5+
import androidx.room.PrimaryKey
46
import fr.free.nrw.commons.nearby.Place
57
import fr.free.nrw.commons.upload.WikidataItem
68
import fr.free.nrw.commons.wikidata.WikidataProperties
@@ -20,14 +22,15 @@ const val THUMB_IMAGE_SIZE = "70px"
2022
* Model class for Depicted Item in Upload and Explore
2123
*/
2224
@Parcelize
25+
@Entity
2326
data class DepictedItem constructor(
2427
override val name: String,
2528
val description: String?,
2629
val imageUrl: String?,
2730
val instanceOfs: List<String>,
2831
val commonsCategories: List<String>,
2932
var isSelected: Boolean,
30-
override val id: String
33+
@PrimaryKey override val id: String
3134
) : WikidataItem, Parcelable {
3235

3336
constructor(entity: Entities.Entity) : this(

app/src/test/kotlin/fr/free/nrw/commons/upload/DepictsPresenterTest.kt

+2-8
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,7 @@ class DepictsPresenterTest {
7272
depictsPresenter.searchForDepictions("")
7373
testScheduler.triggerActions()
7474
verify(view).showProgress(false)
75-
verify(view).showError(false)
76-
depictsPresenter.depictedItems
77-
.test()
78-
.assertValue(listOf(selectedItem, depictedItem(id="nonUnique")))
75+
verify(view).showError(true)
7976
}
8077

8178

@@ -85,10 +82,7 @@ class DepictsPresenterTest {
8582
depictsPresenter.searchForDepictions("")
8683
testScheduler.triggerActions()
8784
verify(view).showProgress(false)
88-
verify(view).showError(false)
89-
depictsPresenter.depictedItems
90-
.test()
91-
.assertValue(emptyList())
85+
verify(view).showError(true)
9286
}
9387

9488
@Test

0 commit comments

Comments
 (0)