mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-27 12:53:55 +01:00
[GSOC] Added Image Fetch (#4449)
* Added basic Fetch * added permission request * Folder count rectified * Loaded thumbnail * disabled overlay * Added sha1 function * Documented the code
This commit is contained in:
parent
dc26621185
commit
aed4bc8ebf
12 changed files with 240 additions and 40 deletions
|
|
@ -142,6 +142,10 @@ dependencies {
|
||||||
def work_version = "2.4.0"
|
def work_version = "2.4.0"
|
||||||
// Kotlin + coroutines
|
// Kotlin + coroutines
|
||||||
implementation "androidx.work:work-runtime-ktx:$work_version"
|
implementation "androidx.work:work-runtime-ktx:$work_version"
|
||||||
|
|
||||||
|
//Glide
|
||||||
|
implementation 'com.github.bumptech.glide:glide:4.12.0'
|
||||||
|
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import fr.free.nrw.commons.R;
|
import fr.free.nrw.commons.R;
|
||||||
|
import fr.free.nrw.commons.customselector.ui.selector.CustomSelectorActivity;
|
||||||
import fr.free.nrw.commons.filepicker.DefaultCallback;
|
import fr.free.nrw.commons.filepicker.DefaultCallback;
|
||||||
import fr.free.nrw.commons.filepicker.FilePicker;
|
import fr.free.nrw.commons.filepicker.FilePicker;
|
||||||
import fr.free.nrw.commons.filepicker.FilePicker.ImageSource;
|
import fr.free.nrw.commons.filepicker.FilePicker.ImageSource;
|
||||||
|
|
@ -58,6 +59,25 @@ public class ContributionController {
|
||||||
initiateGalleryUpload(activity, allowMultipleUploads);
|
initiateGalleryUpload(activity, allowMultipleUploads);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initiate gallery picker with permission
|
||||||
|
*/
|
||||||
|
public void initiateCustomGalleryPickWithPermission(final Activity activity) {
|
||||||
|
boolean useExtStorage = defaultKvStore.getBoolean("useExternalStorage", true);
|
||||||
|
Intent intent = new Intent(activity,CustomSelectorActivity.class);
|
||||||
|
if (!useExtStorage) {
|
||||||
|
activity.startActivity(intent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PermissionUtils.checkPermissionsAndPerformAction(activity,
|
||||||
|
Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
||||||
|
() -> activity.startActivity(intent),
|
||||||
|
R.string.storage_permission_title,
|
||||||
|
R.string.write_storage_permission_rationale);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open chooser for gallery uploads
|
* Open chooser for gallery uploads
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -259,8 +259,7 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl
|
||||||
|
|
||||||
@OnClick(R.id.fab_custom_gallery)
|
@OnClick(R.id.fab_custom_gallery)
|
||||||
void launchCustomSelector(){
|
void launchCustomSelector(){
|
||||||
Intent intent = new Intent(getActivity(), CustomSelectorActivity.class);
|
controller.initiateCustomGalleryPickWithPermission(getActivity());
|
||||||
startActivity(intent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void animateFAB(final boolean isFabOpen) {
|
private void animateFAB(final boolean isFabOpen) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,94 @@
|
||||||
|
package fr.free.nrw.commons.customselector.helper
|
||||||
|
|
||||||
|
import fr.free.nrw.commons.customselector.model.Folder
|
||||||
|
import fr.free.nrw.commons.customselector.model.Image
|
||||||
|
import timber.log.Timber
|
||||||
|
import java.io.*
|
||||||
|
import java.math.BigInteger
|
||||||
|
import java.security.MessageDigest
|
||||||
|
import java.security.NoSuchAlgorithmException
|
||||||
|
import kotlin.collections.ArrayList
|
||||||
|
import kotlin.collections.LinkedHashMap
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Image Helper object, includes all the static functions required by custom selector
|
||||||
|
*/
|
||||||
|
|
||||||
|
object ImageHelper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of folders from given image list.
|
||||||
|
*/
|
||||||
|
fun folderListFromImages(images: List<Image>): List<Folder> {
|
||||||
|
val folderMap: MutableMap<Long, Folder> = LinkedHashMap()
|
||||||
|
for (image in images) {
|
||||||
|
val bucketId = image.bucketId
|
||||||
|
val bucketName = image.bucketName
|
||||||
|
var folder = folderMap[bucketId]
|
||||||
|
if (folder == null) {
|
||||||
|
folder = Folder(bucketId, bucketName)
|
||||||
|
folderMap[bucketId] = folder
|
||||||
|
}
|
||||||
|
folder.images.add(image)
|
||||||
|
}
|
||||||
|
return ArrayList(folderMap.values)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters the images based on the given bucketId (folder)
|
||||||
|
*/
|
||||||
|
fun filterImages(images: ArrayList<Image>, bukketId: Long?): ArrayList<Image> {
|
||||||
|
if (bukketId == null) return images
|
||||||
|
|
||||||
|
val filteredImages = arrayListOf<Image>()
|
||||||
|
for (image in images) {
|
||||||
|
if (image.bucketId == bukketId) {
|
||||||
|
filteredImages.add(image)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filteredImages
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates the file sha1 from file input stream.
|
||||||
|
*/
|
||||||
|
fun generateSHA1(`is`: InputStream): String {
|
||||||
|
val digest: MessageDigest = try {
|
||||||
|
MessageDigest.getInstance("SHA1")
|
||||||
|
} catch (e: NoSuchAlgorithmException) {
|
||||||
|
Timber.e(e, "Exception while getting Digest")
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
val buffer = ByteArray(8192)
|
||||||
|
var read: Int
|
||||||
|
return try {
|
||||||
|
while (`is`.read(buffer).also { read = it } > 0) {
|
||||||
|
digest.update(buffer, 0, read)
|
||||||
|
}
|
||||||
|
val md5sum = digest.digest()
|
||||||
|
val bigInt = BigInteger(1, md5sum)
|
||||||
|
var output = bigInt.toString(16)
|
||||||
|
output = String.format("%40s", output).replace(' ', '0')
|
||||||
|
Timber.i("File SHA1: %s", output)
|
||||||
|
output
|
||||||
|
} catch (e: IOException) {
|
||||||
|
Timber.e(e, "IO Exception")
|
||||||
|
""
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
`is`.close()
|
||||||
|
} catch (e: IOException) {
|
||||||
|
Timber.e(e, "Exception on closing input stream")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the file input stream from the file path.
|
||||||
|
*/
|
||||||
|
@Throws(FileNotFoundException::class)
|
||||||
|
fun getFileInputStream(filePath: String?): InputStream {
|
||||||
|
return FileInputStream(filePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -7,6 +7,7 @@ import android.widget.ImageView
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.bumptech.glide.Glide
|
||||||
import fr.free.nrw.commons.R
|
import fr.free.nrw.commons.R
|
||||||
import fr.free.nrw.commons.customselector.listeners.FolderClickListener
|
import fr.free.nrw.commons.customselector.listeners.FolderClickListener
|
||||||
import fr.free.nrw.commons.customselector.model.Folder
|
import fr.free.nrw.commons.customselector.model.Folder
|
||||||
|
|
@ -49,8 +50,9 @@ class FolderAdapter(
|
||||||
val folder = folders[position]
|
val folder = folders[position]
|
||||||
val count = folder.images.size
|
val count = folder.images.size
|
||||||
val previewImage = folder.images[0]
|
val previewImage = folder.images[0]
|
||||||
|
Glide.with(context).load(previewImage.uri).into(holder.image)
|
||||||
holder.name.text = folder.name
|
holder.name.text = folder.name
|
||||||
holder.count.text= count.toString()
|
holder.count.text = count.toString()
|
||||||
holder.itemView.setOnClickListener{
|
holder.itemView.setOnClickListener{
|
||||||
itemClickListener.onFolderClick(folder)
|
itemClickListener.onFolderClick(folder)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import android.widget.TextView
|
||||||
import androidx.constraintlayout.widget.Group
|
import androidx.constraintlayout.widget.Group
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.bumptech.glide.Glide
|
||||||
import fr.free.nrw.commons.customselector.listeners.ImageSelectListener
|
import fr.free.nrw.commons.customselector.listeners.ImageSelectListener
|
||||||
import fr.free.nrw.commons.customselector.model.Image
|
import fr.free.nrw.commons.customselector.model.Image
|
||||||
|
|
||||||
|
|
@ -49,6 +50,7 @@ class ImageAdapter(
|
||||||
override fun onBindViewHolder(holder: ImageViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: ImageViewHolder, position: Int) {
|
||||||
val image=images[position]
|
val image=images[position]
|
||||||
// todo load image thumbnail, set selected view.
|
// todo load image thumbnail, set selected view.
|
||||||
|
Glide.with(context).load(image.uri).into(holder.image)
|
||||||
holder.itemView.setOnClickListener {
|
holder.itemView.setOnClickListener {
|
||||||
selectOrRemoveImage(image, position)
|
selectOrRemoveImage(image, position)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,20 @@
|
||||||
package fr.free.nrw.commons.customselector.ui.selector
|
package fr.free.nrw.commons.customselector.ui.selector
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.util.Log
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import fr.free.nrw.commons.customselector.listeners.ImageLoaderListener
|
import fr.free.nrw.commons.customselector.listeners.ImageLoaderListener
|
||||||
import fr.free.nrw.commons.customselector.model.CallbackStatus
|
import fr.free.nrw.commons.customselector.model.CallbackStatus
|
||||||
import fr.free.nrw.commons.customselector.model.Image
|
import fr.free.nrw.commons.customselector.model.Image
|
||||||
import fr.free.nrw.commons.customselector.model.Result
|
import fr.free.nrw.commons.customselector.model.Result
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.cancel
|
||||||
|
|
||||||
class CustomSelectorViewModel(val context: Context,var imageFileLoader: ImageFileLoader) : ViewModel() {
|
class CustomSelectorViewModel(var context: Context,var imageFileLoader: ImageFileLoader) : ViewModel() {
|
||||||
|
|
||||||
|
private val scope = CoroutineScope(Dispatchers.Main)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Result Live Data
|
* Result Live Data
|
||||||
|
|
@ -20,9 +26,8 @@ class CustomSelectorViewModel(val context: Context,var imageFileLoader: ImageFil
|
||||||
*/
|
*/
|
||||||
fun fetchImages() {
|
fun fetchImages() {
|
||||||
result.postValue(Result(CallbackStatus.FETCHING, arrayListOf()))
|
result.postValue(Result(CallbackStatus.FETCHING, arrayListOf()))
|
||||||
imageFileLoader.abortLoadImage()
|
scope.cancel()
|
||||||
imageFileLoader.loadDeviceImages(object: ImageLoaderListener {
|
imageFileLoader.loadDeviceImages(object: ImageLoaderListener {
|
||||||
|
|
||||||
override fun onImageLoaded(images: ArrayList<Image>) {
|
override fun onImageLoaded(images: ArrayList<Image>) {
|
||||||
result.postValue(Result(CallbackStatus.SUCCESS, images))
|
result.postValue(Result(CallbackStatus.SUCCESS, images))
|
||||||
}
|
}
|
||||||
|
|
@ -30,7 +35,14 @@ class CustomSelectorViewModel(val context: Context,var imageFileLoader: ImageFil
|
||||||
override fun onFailed(throwable: Throwable) {
|
override fun onFailed(throwable: Throwable) {
|
||||||
result.postValue(Result(CallbackStatus.SUCCESS, arrayListOf()))
|
result.postValue(Result(CallbackStatus.SUCCESS, arrayListOf()))
|
||||||
}
|
}
|
||||||
|
},scope)
|
||||||
|
}
|
||||||
|
|
||||||
})
|
/**
|
||||||
|
* Clear the coroutine task linked with context.
|
||||||
|
*/
|
||||||
|
override fun onCleared() {
|
||||||
|
scope.cancel()
|
||||||
|
super.onCleared()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8,6 +8,7 @@ import androidx.lifecycle.Observer
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import fr.free.nrw.commons.R
|
import fr.free.nrw.commons.R
|
||||||
|
import fr.free.nrw.commons.customselector.helper.ImageHelper
|
||||||
import fr.free.nrw.commons.customselector.model.Result
|
import fr.free.nrw.commons.customselector.model.Result
|
||||||
import fr.free.nrw.commons.customselector.listeners.FolderClickListener
|
import fr.free.nrw.commons.customselector.listeners.FolderClickListener
|
||||||
import fr.free.nrw.commons.customselector.model.CallbackStatus
|
import fr.free.nrw.commons.customselector.model.CallbackStatus
|
||||||
|
|
@ -29,7 +30,7 @@ class FolderFragment : CommonsDaggerSupportFragment() {
|
||||||
* View Model Factory.
|
* View Model Factory.
|
||||||
*/
|
*/
|
||||||
var customSelectorViewModelFactory: CustomSelectorViewModelFactory? = null
|
var customSelectorViewModelFactory: CustomSelectorViewModelFactory? = null
|
||||||
@Inject set
|
@Inject set
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -67,7 +68,7 @@ class FolderFragment : CommonsDaggerSupportFragment() {
|
||||||
*/
|
*/
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
val root = inflater.inflate(R.layout.fragment_custom_selector, container, false)
|
val root = inflater.inflate(R.layout.fragment_custom_selector, container, false)
|
||||||
folderAdapter = FolderAdapter(requireActivity(), activity as FolderClickListener)
|
folderAdapter = FolderAdapter(activity!!, activity as FolderClickListener)
|
||||||
gridLayoutManager = GridLayoutManager(context, columnCount())
|
gridLayoutManager = GridLayoutManager(context, columnCount())
|
||||||
with(root.selector_rv){
|
with(root.selector_rv){
|
||||||
this.layoutManager = gridLayoutManager
|
this.layoutManager = gridLayoutManager
|
||||||
|
|
@ -87,10 +88,7 @@ class FolderFragment : CommonsDaggerSupportFragment() {
|
||||||
*/
|
*/
|
||||||
private fun handleResult(result: Result) {
|
private fun handleResult(result: Result) {
|
||||||
if(result.status is CallbackStatus.SUCCESS){
|
if(result.status is CallbackStatus.SUCCESS){
|
||||||
val folders = arrayListOf<Folder>()
|
val folders = ImageHelper.folderListFromImages(result.images)
|
||||||
for( i in 1..12) {
|
|
||||||
folders.add(Folder(i.toLong(), "Folder$i",result.images))
|
|
||||||
}
|
|
||||||
folderAdapter.init(folders)
|
folderAdapter.init(folders)
|
||||||
folderAdapter.notifyDataSetChanged()
|
folderAdapter.notifyDataSetChanged()
|
||||||
selector_rv.visibility = View.VISIBLE
|
selector_rv.visibility = View.VISIBLE
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,97 @@
|
||||||
package fr.free.nrw.commons.customselector.ui.selector
|
package fr.free.nrw.commons.customselector.ui.selector
|
||||||
|
|
||||||
|
import android.content.ContentUris
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.Uri
|
import android.provider.MediaStore
|
||||||
import fr.free.nrw.commons.customselector.listeners.ImageLoaderListener
|
import fr.free.nrw.commons.customselector.listeners.ImageLoaderListener
|
||||||
import fr.free.nrw.commons.customselector.model.Image
|
import fr.free.nrw.commons.customselector.model.Image
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
import java.io.File
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
class ImageFileLoader(val context: Context) {
|
class ImageFileLoader(val context: Context) : CoroutineScope{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load Device Images.
|
* Coroutine context for fetching images.
|
||||||
*/
|
*/
|
||||||
fun loadDeviceImages(listener: ImageLoaderListener) {
|
override val coroutineContext: CoroutineContext = Dispatchers.Main
|
||||||
var tempImage = Image(0, "temp", Uri.parse("http://www.google.com"), "path", 0, "bucket", "1223")
|
|
||||||
var array: ArrayList<Image> = ArrayList()
|
|
||||||
for(i in 1..100) {
|
|
||||||
array.add(tempImage)
|
|
||||||
}
|
|
||||||
listener.onImageLoaded(array)
|
|
||||||
|
|
||||||
// todo load images from device using cursor.
|
/**
|
||||||
|
* Media paramerters required.
|
||||||
|
*/
|
||||||
|
private val projection = arrayOf(
|
||||||
|
MediaStore.Images.Media._ID,
|
||||||
|
MediaStore.Images.Media.DISPLAY_NAME,
|
||||||
|
MediaStore.Images.Media.DATA,
|
||||||
|
MediaStore.Images.Media.BUCKET_ID,
|
||||||
|
MediaStore.Images.Media.BUCKET_DISPLAY_NAME)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load Device Images under coroutine.
|
||||||
|
*/
|
||||||
|
fun loadDeviceImages(listener: ImageLoaderListener, scope: CoroutineScope) {
|
||||||
|
launch(Dispatchers.Main) {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
getImages(listener)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load the device images using cursor
|
||||||
|
*/
|
||||||
|
private fun getImages(listener:ImageLoaderListener) {
|
||||||
|
val cursor = context.contentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, null, null, MediaStore.Images.Media.DATE_ADDED + " DESC")
|
||||||
|
if (cursor == null) {
|
||||||
|
listener.onFailed(NullPointerException())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val idColumn = cursor.getColumnIndex(MediaStore.Images.Media._ID)
|
||||||
|
val nameColumn = cursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME)
|
||||||
|
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 images = arrayListOf<Image>()
|
||||||
|
if (cursor.moveToFirst()) {
|
||||||
|
do {
|
||||||
|
if (Thread.interrupted()) {
|
||||||
|
listener.onFailed(NullPointerException())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val id = cursor.getLong(idColumn)
|
||||||
|
val name = cursor.getString(nameColumn)
|
||||||
|
val path = cursor.getString(dataColumn)
|
||||||
|
val bucketId = cursor.getLong(bucketIdColumn)
|
||||||
|
val bucketName = cursor.getString(bucketNameColumn)
|
||||||
|
|
||||||
|
val file =
|
||||||
|
if (path == null || path.isEmpty()) {
|
||||||
|
null
|
||||||
|
} else try {
|
||||||
|
File(path)
|
||||||
|
} catch (ignored: Exception) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (file != null && file.exists()) {
|
||||||
|
if (id != null && name != null && path != null && bucketId != null && bucketName != null) {
|
||||||
|
val uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id)
|
||||||
|
val image = Image(id, name, uri, path, bucketId, bucketName)
|
||||||
|
images.add(image)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (cursor.moveToNext())
|
||||||
|
}
|
||||||
|
cursor.close()
|
||||||
|
listener.onImageLoaded(images)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abort loading images.
|
* Abort loading images.
|
||||||
*/
|
*/
|
||||||
|
|
@ -31,7 +102,6 @@ class ImageFileLoader(val context: Context) {
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* TODO
|
* TODO
|
||||||
* Runnable Thread for image loading.
|
|
||||||
* Sha1 for image (original image).
|
* Sha1 for image (original image).
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,11 @@ import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import fr.free.nrw.commons.R
|
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.ImageSelectListener
|
||||||
import fr.free.nrw.commons.customselector.model.CallbackStatus
|
import fr.free.nrw.commons.customselector.model.CallbackStatus
|
||||||
import fr.free.nrw.commons.customselector.model.Result
|
import fr.free.nrw.commons.customselector.model.Result
|
||||||
|
|
@ -34,7 +34,7 @@ class ImageFragment: CommonsDaggerSupportFragment() {
|
||||||
* View model Factory.
|
* View model Factory.
|
||||||
*/
|
*/
|
||||||
lateinit var customSelectorViewModelFactory: CustomSelectorViewModelFactory
|
lateinit var customSelectorViewModelFactory: CustomSelectorViewModelFactory
|
||||||
@Inject set
|
@Inject set
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Image Adapter for recycle view.
|
* Image Adapter for recycle view.
|
||||||
|
|
@ -106,7 +106,7 @@ class ImageFragment: CommonsDaggerSupportFragment() {
|
||||||
if(result.status is CallbackStatus.SUCCESS){
|
if(result.status is CallbackStatus.SUCCESS){
|
||||||
val images = result.images
|
val images = result.images
|
||||||
if(images.isNotEmpty()) {
|
if(images.isNotEmpty()) {
|
||||||
imageAdapter.init(images)
|
imageAdapter.init(ImageHelper.filterImages(images,bucketId))
|
||||||
selector_rv.visibility = View.VISIBLE
|
selector_rv.visibility = View.VISIBLE
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
|
|
|
||||||
|
|
@ -19,30 +19,30 @@
|
||||||
android:background="@color/white"
|
android:background="@color/white"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<ImageView
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
android:id="@+id/folder_thumbnail"
|
android:id="@+id/folder_thumbnail"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@color/black"
|
|
||||||
android:alpha="0.15"
|
|
||||||
android:scaleType="centerCrop" />
|
android:scaleType="centerCrop" />
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:id="@+id/album_overlay"
|
android:id="@+id/album_overlay"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:alpha="0.05" />
|
android:background="@color/black"
|
||||||
|
android:alpha="0.15" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/folder_details"
|
android:id="@+id/folder_details"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:background="#4D000000"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
app:layout_constraintBottom_toBottomOf="parent">
|
app:layout_constraintBottom_toBottomOf="parent">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/folder_name"
|
android:id="@+id/folder_name"
|
||||||
style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title"
|
android:textColor="@color/white"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="@dimen/dimen_6"
|
android:layout_margin="@dimen/dimen_6"
|
||||||
|
|
@ -50,18 +50,17 @@
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:padding="@dimen/dimen_6"
|
android:padding="@dimen/dimen_6"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
android:textSize="16sp"
|
android:textSize="15sp"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintLeft_toLeftOf="parent" />
|
app:layout_constraintLeft_toLeftOf="parent" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/folder_count"
|
android:id="@+id/folder_count"
|
||||||
style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title"
|
android:textColor="@color/white"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="5dp"
|
android:layout_margin="5dp"
|
||||||
android:textSize="16sp"
|
android:textSize="14sp"
|
||||||
android:textStyle="bold"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintRight_toRightOf="parent" />
|
app:layout_constraintRight_toRightOf="parent" />
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<ImageView
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
android:id="@+id/image_thumbnail"
|
android:id="@+id/image_thumbnail"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
|
@ -53,7 +53,7 @@
|
||||||
android:id="@+id/selected_group"
|
android:id="@+id/selected_group"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:visibility="visible"
|
android:visibility="gone"
|
||||||
app:constraint_referenced_ids="selected_overlay,selected_count"/>
|
app:constraint_referenced_ids="selected_overlay,selected_count"/>
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -78,7 +78,7 @@
|
||||||
android:id="@+id/uploaded_group"
|
android:id="@+id/uploaded_group"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:visibility="visible"
|
android:visibility="gone"
|
||||||
app:constraint_referenced_ids="uploaded_overlay,uploaded_overlay_icon"/>
|
app:constraint_referenced_ids="uploaded_overlay,uploaded_overlay_icon"/>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue