diff --git a/app/build.gradle b/app/build.gradle index 4b71fb21c..5bba979cd 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -122,6 +122,7 @@ dependencies { implementation "androidx.exifinterface:exifinterface:1.3.2" implementation "androidx.core:core-ktx:$CORE_KTX_VERSION" implementation "androidx.multidex:multidex:2.0.1" + compile 'com.simplecityapps:recyclerview-fastscroll:2.0.1' //swipe_layout implementation 'com.daimajia.swipelayout:library:1.2.0@aar' diff --git a/app/src/main/java/fr/free/nrw/commons/customselector/model/Image.kt b/app/src/main/java/fr/free/nrw/commons/customselector/model/Image.kt index 12e75580d..d3ceae093 100644 --- a/app/src/main/java/fr/free/nrw/commons/customselector/model/Image.kt +++ b/app/src/main/java/fr/free/nrw/commons/customselector/model/Image.kt @@ -41,7 +41,13 @@ data class Image( /** sha1 : sha1 of original image. */ - var sha1: String = "" + var sha1: String = "", + + /** + * date: Addition date of the image to show it inside the bubble during bubble scroll. + */ + var date: String = "" + ) : Parcelable { /** @@ -54,6 +60,7 @@ data class Image( parcel.readString()!!, parcel.readLong(), parcel.readString()!!, + parcel.readString()!!, parcel.readString()!! ) @@ -68,6 +75,7 @@ data class Image( parcel.writeLong(bucketId) parcel.writeString(bucketName) parcel.writeString(sha1) + parcel.writeString(date) } /** 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 1fb6273c4..8bac6ac93 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 @@ -10,6 +10,7 @@ import androidx.constraintlayout.widget.Group import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView import com.bumptech.glide.Glide +import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView import fr.free.nrw.commons.R import fr.free.nrw.commons.customselector.helper.ImageHelper import fr.free.nrw.commons.customselector.listeners.ImageSelectListener @@ -36,7 +37,7 @@ class ImageAdapter( private var imageLoader: ImageLoader ): - RecyclerViewAdapter(context) { + RecyclerViewAdapter(context), FastScrollRecyclerView.SectionedAdapter { /** * ImageSelectedOrUpdated payload class. @@ -278,4 +279,11 @@ class ImageAdapter( } + /** + * Returns the text for showing inside the bubble during bubble scroll. + */ + override fun getSectionName(position: Int): String { + return images[position].date + } + } \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/ImageFileLoader.kt b/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/ImageFileLoader.kt index 38b5cf0a4..8e22574e3 100644 --- a/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/ImageFileLoader.kt +++ b/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/ImageFileLoader.kt @@ -3,10 +3,15 @@ package fr.free.nrw.commons.customselector.ui.selector import android.content.ContentUris import android.content.Context import android.provider.MediaStore +import android.text.format.DateFormat import fr.free.nrw.commons.customselector.listeners.ImageLoaderListener import fr.free.nrw.commons.customselector.model.Image -import kotlinx.coroutines.* +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import java.io.File +import java.util.* import kotlin.coroutines.CoroutineContext /** @@ -28,7 +33,9 @@ class ImageFileLoader(val context: Context) : CoroutineScope{ MediaStore.Images.Media.DISPLAY_NAME, MediaStore.Images.Media.DATA, MediaStore.Images.Media.BUCKET_ID, - MediaStore.Images.Media.BUCKET_DISPLAY_NAME) + MediaStore.Images.Media.BUCKET_DISPLAY_NAME, + MediaStore.Images.Media.DATE_ADDED + ) /** * Load Device Images under coroutine. @@ -57,6 +64,7 @@ class ImageFileLoader(val context: Context) : CoroutineScope{ val dataColumn = cursor.getColumnIndex(MediaStore.Images.Media.DATA) val bucketIdColumn = cursor.getColumnIndex(MediaStore.Images.Media.BUCKET_ID) val bucketNameColumn = cursor.getColumnIndex(MediaStore.Images.Media.BUCKET_DISPLAY_NAME) + val dateColumn = cursor.getColumnIndex(MediaStore.Images.Media.DATE_ADDED) val images = arrayListOf() if (cursor.moveToFirst()) { @@ -70,6 +78,7 @@ class ImageFileLoader(val context: Context) : CoroutineScope{ val path = cursor.getString(dataColumn) val bucketId = cursor.getLong(bucketIdColumn) val bucketName = cursor.getString(bucketNameColumn) + val date = cursor.getLong(dateColumn) val file = if (path == null || path.isEmpty()) { @@ -84,7 +93,22 @@ class ImageFileLoader(val context: Context) : CoroutineScope{ if (file != null && file.exists()) { if (name != null && path != null && bucketName != null) { val uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id) - val image = Image(id, name, uri, path, bucketId, bucketName) + + val calendar = Calendar.getInstance() + calendar.timeInMillis = date * 1000L + val date: Date = calendar.time + val dateFormat = DateFormat.getMediumDateFormat(context) + val formattedDate = dateFormat.format(date) + + val image = Image( + id, + name, + uri, + path, + bucketId, + bucketName, + date = (formattedDate) + ) images.add(image) } } diff --git a/app/src/main/res/layout/fragment_custom_selector.xml b/app/src/main/res/layout/fragment_custom_selector.xml index b0b4e6c28..8dc97325c 100644 --- a/app/src/main/res/layout/fragment_custom_selector.xml +++ b/app/src/main/res/layout/fragment_custom_selector.xml @@ -5,11 +5,18 @@ android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto"> - 3dp 110dp 160dp + 36dp 24sp diff --git a/app/src/test/kotlin/fr/free/nrw/commons/customselector/ui/selector/ImageFileLoaderTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/customselector/ui/selector/ImageFileLoaderTest.kt index 15ee8eca0..3a2d6e683 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/customselector/ui/selector/ImageFileLoaderTest.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/customselector/ui/selector/ImageFileLoaderTest.kt @@ -64,7 +64,8 @@ class ImageFileLoaderTest { MediaStore.Images.Media.DISPLAY_NAME, MediaStore.Images.Media.DATA, MediaStore.Images.Media.BUCKET_ID, - MediaStore.Images.Media.BUCKET_DISPLAY_NAME + MediaStore.Images.Media.BUCKET_DISPLAY_NAME, + MediaStore.Images.Media.DATE_ADDED ) Whitebox.setInternalState(imageFileLoader, "coroutineContext", coroutineContext) @@ -103,6 +104,7 @@ class ImageFileLoaderTest { anyOrNull(), anyOrNull(), anyOrNull(), + anyOrNull(), anyOrNull() ) } doReturn imageCursor;