From 40323be3a0553f2b6b3124ee12793f53b2bc742f Mon Sep 17 00:00:00 2001 From: Ayan Sarkar <71203077+Ayan-10@users.noreply.github.com> Date: Wed, 29 Jun 2022 12:40:23 +0530 Subject: [PATCH] [GSoC] Insert and Remove Images from not for upload (#4999) * Inserted and marked images as not for upload * Documentation added * Test delete * Implemented remove from not for upload * Test fixed * Requested changes done * Added tests for new lines in existing classes --- .../database/NotForUploadDao.kt | 6 + .../listeners/ImageSelectListener.kt | 3 +- .../listeners/RefreshUIListener.kt | 11 ++ .../customselector/ui/adapter/ImageAdapter.kt | 47 +++++- .../ui/selector/CustomSelectorActivity.kt | 140 +++++++++++++++++- .../ui/selector/ImageFragment.kt | 20 ++- .../customselector/ui/selector/ImageLoader.kt | 35 ++--- .../nrw/commons/utils/CustomSelectorUtils.kt | 35 +++++ app/src/main/res/drawable/not_for_upload.xml | 6 + .../res/layout/item_custom_selector_image.xml | 17 +++ app/src/main/res/values/dimens.xml | 1 + app/src/main/res/values/strings.xml | 1 + .../ui/adapter/ImageAdapterTest.kt | 3 + .../ui/selector/CustomSelectorActivityTest.kt | 37 ++++- .../ui/selector/ImageFragmentTest.kt | 19 ++- .../ui/selector/ImageLoaderTest.kt | 7 +- 16 files changed, 359 insertions(+), 29 deletions(-) create mode 100644 app/src/main/java/fr/free/nrw/commons/customselector/listeners/RefreshUIListener.kt create mode 100644 app/src/main/java/fr/free/nrw/commons/utils/CustomSelectorUtils.kt create mode 100644 app/src/main/res/drawable/not_for_upload.xml diff --git a/app/src/main/java/fr/free/nrw/commons/customselector/database/NotForUploadDao.kt b/app/src/main/java/fr/free/nrw/commons/customselector/database/NotForUploadDao.kt index 7d3096d33..efbc28888 100644 --- a/app/src/main/java/fr/free/nrw/commons/customselector/database/NotForUploadDao.kt +++ b/app/src/main/java/fr/free/nrw/commons/customselector/database/NotForUploadDao.kt @@ -46,6 +46,12 @@ abstract class NotForUploadStatusDao { suspend fun deleteNotForUploadWithImageSHA1(imageSHA1: String) { return deleteWithImageSHA1(imageSHA1) } + + /** + * Check whether the imageSHA1 is present in database + */ + @Query("SELECT COUNT() FROM not_for_upload_table WHERE imageSHA1 = (:imageSHA1) ") + abstract suspend fun find(imageSHA1 : String): Int } diff --git a/app/src/main/java/fr/free/nrw/commons/customselector/listeners/ImageSelectListener.kt b/app/src/main/java/fr/free/nrw/commons/customselector/listeners/ImageSelectListener.kt index 1d7310b1d..a9cc85e19 100644 --- a/app/src/main/java/fr/free/nrw/commons/customselector/listeners/ImageSelectListener.kt +++ b/app/src/main/java/fr/free/nrw/commons/customselector/listeners/ImageSelectListener.kt @@ -11,8 +11,9 @@ interface ImageSelectListener { /** * onSelectedImagesChanged * @param selectedImages : new selected images. + * @param selectedNotForUploadImages : number of selected not for upload images */ - fun onSelectedImagesChanged(selectedImages: ArrayList) + fun onSelectedImagesChanged(selectedImages: ArrayList, selectedNotForUploadImages: Int) /** * onLongPress diff --git a/app/src/main/java/fr/free/nrw/commons/customselector/listeners/RefreshUIListener.kt b/app/src/main/java/fr/free/nrw/commons/customselector/listeners/RefreshUIListener.kt new file mode 100644 index 000000000..d271c1d0b --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/customselector/listeners/RefreshUIListener.kt @@ -0,0 +1,11 @@ +package fr.free.nrw.commons.customselector.listeners + +/** + * Refresh UI Listener + */ +interface RefreshUIListener { + /** + * Refreshes the data in adapter + */ + fun refresh() +} \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/customselector/ui/adapter/ImageAdapter.kt b/app/src/main/java/fr/free/nrw/commons/customselector/ui/adapter/ImageAdapter.kt index f3fce1cc0..1fb6273c4 100644 --- a/app/src/main/java/fr/free/nrw/commons/customselector/ui/adapter/ImageAdapter.kt +++ b/app/src/main/java/fr/free/nrw/commons/customselector/ui/adapter/ImageAdapter.kt @@ -53,6 +53,11 @@ class ImageAdapter( */ private var selectedImages = arrayListOf() + /** + * Number of selected not for upload images + */ + private var selectedNotForUploadImages = 0 + /** * List of all images in adapter. */ @@ -109,6 +114,9 @@ class ImageAdapter( val clickedIndex = ImageHelper.getIndex(selectedImages, images[position]) if (clickedIndex != -1) { selectedImages.removeAt(clickedIndex) + if (holder.isItemNotForUpload()) { + selectedNotForUploadImages-- + } notifyItemChanged(position, ImageUnselected()) val indexes = ImageHelper.getIndexList(selectedImages, images) for (index in indexes) { @@ -118,11 +126,14 @@ class ImageAdapter( if(holder.isItemUploaded()){ Toast.makeText(context, R.string.custom_selector_already_uploaded_image_text, Toast.LENGTH_SHORT).show() } else { + if (holder.isItemNotForUpload()) { + selectedNotForUploadImages++ + } selectedImages.add(images[position]) notifyItemChanged(position, ImageSelectedOrUpdated()) } } - imageSelectListener.onSelectedImagesChanged(selectedImages) + imageSelectListener.onSelectedImagesChanged(selectedImages, selectedNotForUploadImages) } /** @@ -138,6 +149,18 @@ class ImageAdapter( diffResult.dispatchUpdatesTo(this) } + /** + * Refresh the data in the adapter + */ + fun refresh(newImages: List) { + selectedNotForUploadImages = 0 + selectedImages.clear() + images.clear() + selectedImages = arrayListOf() + init(newImages) + notifyDataSetChanged() + } + /** * Returns the total number of items in the data set held by the adapter. * @@ -158,6 +181,7 @@ class ImageAdapter( val image: ImageView = itemView.findViewById(R.id.image_thumbnail) private val selectedNumber: TextView = itemView.findViewById(R.id.selected_count) private val uploadedGroup: Group = itemView.findViewById(R.id.uploaded_group) + private val notForUploadGroup: Group = itemView.findViewById(R.id.not_for_upload_group) private val selectedGroup: Group = itemView.findViewById(R.id.selected_group) /** @@ -182,9 +206,24 @@ class ImageAdapter( uploadedGroup.visibility = View.VISIBLE } + /** + * Item is not for upload view + */ + fun itemNotForUpload() { + notForUploadGroup.visibility = View.VISIBLE + } + fun isItemUploaded():Boolean { return uploadedGroup.visibility == View.VISIBLE } + + /** + * Item is not for upload + */ + fun isItemNotForUpload():Boolean { + return notForUploadGroup.visibility == View.VISIBLE + } + /** * Item Not Uploaded view. */ @@ -192,6 +231,12 @@ class ImageAdapter( uploadedGroup.visibility = View.GONE } + /** + * Item can be uploaded view + */ + fun itemForUpload() { + notForUploadGroup.visibility = View.GONE + } } /** diff --git a/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/CustomSelectorActivity.kt b/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/CustomSelectorActivity.kt index efc1ce11d..5de0aeca5 100644 --- a/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/CustomSelectorActivity.kt +++ b/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/CustomSelectorActivity.kt @@ -14,11 +14,17 @@ import android.widget.TextView import androidx.constraintlayout.widget.ConstraintLayout import androidx.lifecycle.ViewModelProvider import fr.free.nrw.commons.R +import fr.free.nrw.commons.customselector.database.NotForUploadStatus +import fr.free.nrw.commons.customselector.database.NotForUploadStatusDao import fr.free.nrw.commons.customselector.listeners.FolderClickListener import fr.free.nrw.commons.customselector.listeners.ImageSelectListener import fr.free.nrw.commons.customselector.model.Image import fr.free.nrw.commons.media.ZoomableActivity import fr.free.nrw.commons.theme.BaseActivity +import fr.free.nrw.commons.upload.FileUtilsWrapper +import fr.free.nrw.commons.utils.CustomSelectorUtils +import kotlinx.android.synthetic.main.custom_selector_bottom_layout.* +import kotlinx.coroutines.* import java.io.File import javax.inject.Inject @@ -54,6 +60,29 @@ class CustomSelectorActivity: BaseActivity(), FolderClickListener, ImageSelectLi */ @Inject lateinit var customSelectorViewModelFactory: CustomSelectorViewModelFactory + /** + * NotForUploadStatus Dao class for database operations + */ + @Inject + lateinit var notForUploadStatusDao: NotForUploadStatusDao + + /** + * FileUtilsWrapper class to get imageSHA1 from uri + */ + @Inject + lateinit var fileUtilsWrapper: FileUtilsWrapper + + /** + * Coroutine Dispatchers and Scope. + */ + private val scope : CoroutineScope = MainScope() + private var ioDispatcher : CoroutineDispatcher = Dispatchers.IO + + /** + * Image Fragment instance + */ + var imageFragment: ImageFragment? = null + /** * onCreate Activity, sets theme, initialises the view model, setup view. */ @@ -112,6 +141,99 @@ class CustomSelectorActivity: BaseActivity(), FolderClickListener, ImageSelectLi private fun setUpBottomLayout() { val done : Button = findViewById(R.id.upload) done.setOnClickListener { onDone() } + + val notForUpload : Button = findViewById(R.id.not_for_upload) + notForUpload.setOnClickListener{ onClickNotForUpload() } + } + + /** + * Gets selected images and proceed for database operations + */ + private fun onClickNotForUpload() { + val selectedImages = viewModel.selectedImages.value + if(selectedImages.isNullOrEmpty()) { + markAsNotForUpload(arrayListOf()) + return + } + var i = 0 + while (i < selectedImages.size) { + val path = selectedImages[i].path + val file = File(path) + if (!file.exists()) { + selectedImages.removeAt(i) + i-- + } + i++ + } + markAsNotForUpload(selectedImages) + } + + /** + * Insert selected images in the database + */ + private fun markAsNotForUpload(images: ArrayList) { + insertIntoNotForUpload(images) + } + + /** + * Initializing ImageFragment + */ + fun setOnDataListener(imageFragment: ImageFragment?) { + this.imageFragment = imageFragment + } + + /** + * Insert images into not for upload + * Remove images from not for upload + * Refresh the UI + */ + private fun insertIntoNotForUpload(images: ArrayList) { + scope.launch { + var allImagesAlreadyNotForUpload = true + images.forEach{ + val imageSHA1 = CustomSelectorUtils.getImageSHA1( + it.uri, + ioDispatcher, + fileUtilsWrapper, + contentResolver + ) + val exists = notForUploadStatusDao.find(imageSHA1) + if (exists < 1) { + allImagesAlreadyNotForUpload = false + } + } + + if (!allImagesAlreadyNotForUpload) { + images.forEach { + val imageSHA1 = CustomSelectorUtils.getImageSHA1( + it.uri, + ioDispatcher, + fileUtilsWrapper, + contentResolver + ) + notForUploadStatusDao.insert( + NotForUploadStatus( + imageSHA1, + true + ) + ) + } + } else { + images.forEach { + val imageSHA1 = CustomSelectorUtils.getImageSHA1( + it.uri, + ioDispatcher, + fileUtilsWrapper, + contentResolver + ) + notForUploadStatusDao.deleteNotForUploadWithImageSHA1(imageSHA1) + } + } + + imageFragment!!.refresh() + val bottomLayout : ConstraintLayout = findViewById(R.id.bottom_layout) + bottomLayout.visibility = View.GONE + } } /** @@ -156,11 +278,25 @@ class CustomSelectorActivity: BaseActivity(), FolderClickListener, ImageSelectLi } /** - * override Selected Images Change, update view model selected images. + * override Selected Images Change, update view model selected images and change UI. */ - override fun onSelectedImagesChanged(selectedImages: ArrayList) { + override fun onSelectedImagesChanged(selectedImages: ArrayList, + selectedNotForUploadImages: Int) { viewModel.selectedImages.value = selectedImages + if (selectedNotForUploadImages > 0) { + upload.isEnabled = false + upload.alpha = 0.5f + } else { + upload.isEnabled = true + upload.alpha = 1f + } + + not_for_upload.text = when (selectedImages.size == selectedNotForUploadImages) { + true -> getString(R.string.unmark_as_not_for_upload) + else -> getString(R.string.mark_as_not_for_upload) + } + val bottomLayout : ConstraintLayout = findViewById(R.id.bottom_layout) bottomLayout.visibility = if (selectedImages.isEmpty()) View.GONE else View.VISIBLE } diff --git a/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/ImageFragment.kt b/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/ImageFragment.kt index 36f298e6b..c06fcf96a 100644 --- a/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/ImageFragment.kt +++ b/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/ImageFragment.kt @@ -1,5 +1,6 @@ package fr.free.nrw.commons.customselector.ui.selector +import android.app.Activity import android.net.Uri import android.os.Bundle import android.util.Log @@ -14,6 +15,7 @@ import androidx.recyclerview.widget.RecyclerView import fr.free.nrw.commons.R import fr.free.nrw.commons.customselector.helper.ImageHelper import fr.free.nrw.commons.customselector.listeners.ImageSelectListener +import fr.free.nrw.commons.customselector.listeners.RefreshUIListener import fr.free.nrw.commons.customselector.model.CallbackStatus import fr.free.nrw.commons.customselector.model.Image import fr.free.nrw.commons.customselector.model.Result @@ -30,7 +32,7 @@ import javax.inject.Inject /** * Custom Selector Image Fragment. */ -class ImageFragment: CommonsDaggerSupportFragment() { +class ImageFragment: CommonsDaggerSupportFragment(), RefreshUIListener { /** * Current bucketId. @@ -135,6 +137,18 @@ class ImageFragment: CommonsDaggerSupportFragment() { return root } + /** + * Attaching data listener + */ + override fun onAttach(activity: Activity) { + super.onAttach(activity) + try { + (getActivity() as CustomSelectorActivity).setOnDataListener(this) + } catch (ex: Exception) { + ex.printStackTrace() + } + } + /** * Handle view model result. */ @@ -211,4 +225,8 @@ class ImageFragment: CommonsDaggerSupportFragment() { } super.onDestroy() } + + override fun refresh() { + imageAdapter.refresh(filteredImages) + } } \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/ImageLoader.kt b/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/ImageLoader.kt index cf45a87c1..5e365da88 100644 --- a/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/ImageLoader.kt +++ b/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/ImageLoader.kt @@ -3,6 +3,7 @@ package fr.free.nrw.commons.customselector.ui.selector import android.content.Context import android.net.Uri import androidx.exifinterface.media.ExifInterface +import fr.free.nrw.commons.customselector.database.NotForUploadStatusDao import fr.free.nrw.commons.customselector.database.UploadedStatus import fr.free.nrw.commons.customselector.database.UploadedStatusDao import fr.free.nrw.commons.customselector.model.Image @@ -11,6 +12,7 @@ import fr.free.nrw.commons.filepicker.PickedFiles import fr.free.nrw.commons.media.MediaClient import fr.free.nrw.commons.upload.FileProcessor import fr.free.nrw.commons.upload.FileUtilsWrapper +import fr.free.nrw.commons.utils.CustomSelectorUtils import kotlinx.coroutines.* import timber.log.Timber import java.io.FileNotFoundException @@ -46,6 +48,11 @@ class ImageLoader @Inject constructor( */ var uploadedStatusDao: UploadedStatusDao, + /** + * NotForUploadDao for database operations + */ + var notForUploadStatusDao: NotForUploadStatusDao, + /** * Context for coroutine. */ @@ -86,7 +93,11 @@ class ImageLoader @Inject constructor( return@launch } - val imageSHA1 = getImageSHA1(image.uri) + val imageSHA1: String = when(mapImageSHA1[image.uri] != null) { + true -> mapImageSHA1[image.uri]!! + else -> CustomSelectorUtils.getImageSHA1(image.uri, ioDispatcher, fileUtilsWrapper, context.contentResolver) + } + if(imageSHA1.isEmpty()) return@launch val uploadedStatus = getFromUploaded(imageSHA1) @@ -106,6 +117,8 @@ class ImageLoader @Inject constructor( return@launch } + val exists = notForUploadStatusDao.find(imageSHA1) + if (result in arrayOf(Result.NOTFOUND, Result.INVALID) && sha1.isNotEmpty()) { // Query original image. result = querySHA1(imageSHA1) @@ -122,6 +135,7 @@ class ImageLoader @Inject constructor( } if(mapHolderImage[holder] == image) { if (result is Result.TRUE) holder.itemUploaded() else holder.itemNotUploaded() + if (exists > 0) holder.itemNotForUpload() else holder.itemForUpload() } } } @@ -190,25 +204,6 @@ class ImageLoader @Inject constructor( ) } - /** - * Get image sha1 from uri, used to retrieve the original image sha1. - */ - suspend fun getImageSHA1(uri: Uri): String { - return withContext(ioDispatcher) { - mapImageSHA1[uri]?.let{ - return@withContext it - } - try { - val result = fileUtilsWrapper.getSHA1(context.contentResolver.openInputStream(uri)) - mapImageSHA1[uri] = result - result - } catch (e: FileNotFoundException){ - e.printStackTrace() - "" - } - } - } - /** * Get result data from database. */ diff --git a/app/src/main/java/fr/free/nrw/commons/utils/CustomSelectorUtils.kt b/app/src/main/java/fr/free/nrw/commons/utils/CustomSelectorUtils.kt new file mode 100644 index 000000000..77fabeb70 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/utils/CustomSelectorUtils.kt @@ -0,0 +1,35 @@ +package fr.free.nrw.commons.utils + +import android.content.ContentResolver +import android.net.Uri +import fr.free.nrw.commons.upload.FileUtilsWrapper +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.withContext +import java.io.FileNotFoundException + +/** + * Util Class for Custom Selector + */ +class CustomSelectorUtils { + companion object { + /** + * Get image sha1 from uri, used to retrieve the original image sha1. + */ + suspend fun getImageSHA1(uri: Uri, + ioDispatcher : CoroutineDispatcher, + fileUtilsWrapper: FileUtilsWrapper, + contentResolver: ContentResolver + ): String { + return withContext(ioDispatcher) { + + try { + val result = fileUtilsWrapper.getSHA1(contentResolver.openInputStream(uri)) + result + } catch (e: FileNotFoundException){ + e.printStackTrace() + "" + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/not_for_upload.xml b/app/src/main/res/drawable/not_for_upload.xml new file mode 100644 index 000000000..a882eec7b --- /dev/null +++ b/app/src/main/res/drawable/not_for_upload.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/src/main/res/layout/item_custom_selector_image.xml b/app/src/main/res/layout/item_custom_selector_image.xml index f04a71922..4a44dbb98 100644 --- a/app/src/main/res/layout/item_custom_selector_image.xml +++ b/app/src/main/res/layout/item_custom_selector_image.xml @@ -82,6 +82,23 @@ android:visibility="gone" app:constraint_referenced_ids="uploaded_overlay,uploaded_overlay_icon"/> + + + diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index fcb48998d..2c8dff8a5 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -65,6 +65,7 @@ 20dp 40dp 42dp + 50dp 250dp 150dp 72dp diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index df40a57e2..4fb2f9207 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -735,4 +735,5 @@ Upload your first media by tapping on the add button. What is your feedback? Your feedback Mark as not for upload + Unmark as not for upload diff --git a/app/src/test/kotlin/fr/free/nrw/commons/customselector/ui/adapter/ImageAdapterTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/customselector/ui/adapter/ImageAdapterTest.kt index fac24cb32..3b616ce41 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/customselector/ui/adapter/ImageAdapterTest.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/customselector/ui/adapter/ImageAdapterTest.kt @@ -121,6 +121,9 @@ class ImageAdapterTest { holder.itemUploaded() func.invoke(imageAdapter, holder, 0) holder.itemNotUploaded() + holder.itemNotForUpload() + func.invoke(imageAdapter, holder, 0) + holder.itemNotForUpload() func.invoke(imageAdapter, holder, 0) selectedImageField.set(imageAdapter, images) func.invoke(imageAdapter, holder, 1) diff --git a/app/src/test/kotlin/fr/free/nrw/commons/customselector/ui/selector/CustomSelectorActivityTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/customselector/ui/selector/CustomSelectorActivityTest.kt index 21007daeb..9b2e8ff42 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/customselector/ui/selector/CustomSelectorActivityTest.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/customselector/ui/selector/CustomSelectorActivityTest.kt @@ -31,6 +31,8 @@ class CustomSelectorActivityTest { private lateinit var activity: CustomSelectorActivity + private lateinit var imageFragment: ImageFragment + /** * Set up the tests. */ @@ -44,6 +46,7 @@ class CustomSelectorActivityTest { val onCreate = activity.javaClass.getDeclaredMethod("onCreate", Bundle::class.java) onCreate.isAccessible = true onCreate.invoke(activity, null) + imageFragment = ImageFragment.newInstance(1,0) } /** @@ -81,7 +84,7 @@ class CustomSelectorActivityTest { @Test @Throws(Exception::class) fun testOnSelectedImagesChanged() { - activity.onSelectedImagesChanged(ArrayList()) + activity.onSelectedImagesChanged(ArrayList(), 0) } /** @@ -91,10 +94,40 @@ class CustomSelectorActivityTest { @Throws(Exception::class) fun testOnDone() { activity.onDone() - activity.onSelectedImagesChanged(ArrayList(arrayListOf(Image(1, "test", Uri.parse("test"), "test", 1)))); + activity.onSelectedImagesChanged( + ArrayList(arrayListOf(Image(1, "test", Uri.parse("test"), "test", 1))), + 1 + ) activity.onDone() } + /** + * Test onClickNotForUpload function. + */ + @Test + @Throws(Exception::class) + fun testOnClickNotForUpload() { + val method: Method = CustomSelectorActivity::class.java.getDeclaredMethod( + "onClickNotForUpload" + ) + method.isAccessible = true + method.invoke(activity) + activity.onSelectedImagesChanged( + ArrayList(arrayListOf(Image(1, "test", Uri.parse("test"), "test", 1))), + 0 + ) + method.invoke(activity) + } + + /** + * Test setOnDataListener Function. + */ + @Test + @Throws(Exception::class) + fun testSetOnDataListener() { + activity.setOnDataListener(imageFragment) + } + /** * Test onBackPressed Function. */ diff --git a/app/src/test/kotlin/fr/free/nrw/commons/customselector/ui/selector/ImageFragmentTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/customselector/ui/selector/ImageFragmentTest.kt index 10ebcc4e8..86323e672 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/customselector/ui/selector/ImageFragmentTest.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/customselector/ui/selector/ImageFragmentTest.kt @@ -47,6 +47,7 @@ import java.lang.reflect.Field class ImageFragmentTest { private lateinit var fragment: ImageFragment + private lateinit var activity: CustomSelectorActivity private lateinit var view: View private lateinit var selectorRV : RecyclerView private lateinit var loader : ProgressBar @@ -76,7 +77,7 @@ class ImageFragmentTest { AppAdapter.set(TestAppAdapter()) SoLoader.setInTestMode() Fresco.initialize(context) - val activity = Robolectric.buildActivity(CustomSelectorActivity::class.java).create().get() + activity = Robolectric.buildActivity(CustomSelectorActivity::class.java).create().get() fragment = ImageFragment.newInstance(1,0) val fragmentManager: FragmentManager = activity.supportFragmentManager @@ -92,6 +93,7 @@ class ImageFragmentTest { Whitebox.setInternalState(fragment, "imageAdapter", adapter) Whitebox.setInternalState(fragment, "selectorRV", selectorRV ) Whitebox.setInternalState(fragment, "loader", loader) + Whitebox.setInternalState(fragment, "filteredImages", arrayListOf(image,image)) viewModelField = fragment.javaClass.getDeclaredField("viewModel") viewModelField.isAccessible = true @@ -139,6 +141,21 @@ class ImageFragmentTest { assertEquals(3, func.invoke(fragment)) } + /** + * Test onAttach function. + */ + @Test + fun testOnAttach() { + fragment.onAttach(activity) + } + + /** + * Test refresh function. + */ + @Test + fun testRefresh() { + fragment.refresh() + } /** * Test onResume. diff --git a/app/src/test/kotlin/fr/free/nrw/commons/customselector/ui/selector/ImageLoaderTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/customselector/ui/selector/ImageLoaderTest.kt index 0c3a7de3a..375ae3316 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/customselector/ui/selector/ImageLoaderTest.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/customselector/ui/selector/ImageLoaderTest.kt @@ -5,6 +5,7 @@ import android.content.Context import android.net.Uri import com.nhaarman.mockitokotlin2.* import fr.free.nrw.commons.TestCommonsApplication +import fr.free.nrw.commons.customselector.database.NotForUploadStatusDao import fr.free.nrw.commons.customselector.database.UploadedStatus import fr.free.nrw.commons.customselector.database.UploadedStatusDao import fr.free.nrw.commons.customselector.model.Image @@ -61,6 +62,9 @@ class ImageLoaderTest { @Mock private lateinit var uploadedStatusDao: UploadedStatusDao + @Mock + private lateinit var notForUploadStatusDao: NotForUploadStatusDao + @Mock private lateinit var holder: ImageAdapter.ImageViewHolder @@ -97,7 +101,8 @@ class ImageLoaderTest { MockitoAnnotations.initMocks(this) imageLoader = - ImageLoader(mediaClient, fileProcessor, fileUtilsWrapper, uploadedStatusDao, context) + ImageLoader(mediaClient, fileProcessor, fileUtilsWrapper, uploadedStatusDao, + notForUploadStatusDao, context) uploadedStatus= UploadedStatus( "testSha1", "testSha1",