eliminar imagenes
This commit is contained in:
parent
e9304a7a4e
commit
71fef94f0d
5
app/src/main/java/com/isolaatti/common/Deletable.kt
Normal file
5
app/src/main/java/com/isolaatti/common/Deletable.kt
Normal file
@ -0,0 +1,5 @@
|
||||
package com.isolaatti.common
|
||||
|
||||
open class Deletable {
|
||||
var delete = false
|
||||
}
|
||||
@ -25,7 +25,7 @@ interface ImagesApi {
|
||||
@Part setAsProfile: MultipartBody.Part? = null,
|
||||
@Part squadId: MultipartBody.Part? = null): Call<ImageDto>
|
||||
|
||||
@POST("images/delete_many")
|
||||
@POST("images/delete/delete_many")
|
||||
fun deleteImages(@Body deleteImagesDto: DeleteImagesDto): Call<Void>
|
||||
|
||||
@GET("images/of_squad/{squadId}")
|
||||
|
||||
@ -46,7 +46,7 @@ class ImagesRepositoryImpl @Inject constructor(private val imagesApi: ImagesApi,
|
||||
|
||||
override fun deleteImages(images: List<Image>): Flow<Resource<Boolean>> = flow {
|
||||
emit(Resource.Loading())
|
||||
val dto = DeleteImagesDto(images.map { it.imageUrl })
|
||||
val dto = DeleteImagesDto(images.map { it.id })
|
||||
try {
|
||||
val response = imagesApi.deleteImages(dto).awaitResponse()
|
||||
if(response.isSuccessful) {
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.isolaatti.images.common.domain.entity
|
||||
|
||||
import com.isolaatti.common.Deletable
|
||||
import com.isolaatti.images.common.data.remote.ImageDto
|
||||
import com.isolaatti.utils.UrlGen
|
||||
import java.io.Serializable
|
||||
@ -9,7 +10,7 @@ data class Image(
|
||||
val userId: Int,
|
||||
val name: String,
|
||||
val username: String
|
||||
): Serializable {
|
||||
): Deletable(), Serializable {
|
||||
val imageUrl: String get() = UrlGen.imageUrl(id)
|
||||
val smallImageUrl : String get() = UrlGen.imageUrl(id, UrlGen.IMAGE_MODE_SMALL)
|
||||
val reducedImageUrl: String get() = UrlGen.imageUrl(id, UrlGen.IMAGE_MODE_REDUCED)
|
||||
|
||||
@ -18,10 +18,16 @@ import kotlin.properties.Delegates
|
||||
@HiltViewModel
|
||||
class ImageListViewModel @Inject constructor(private val imagesRepository: ImagesRepository) : ViewModel() {
|
||||
|
||||
val liveList: MutableLiveData<List<Image>> = MutableLiveData()
|
||||
enum class Event {
|
||||
REMOVED_IMAGE, ADDED_IMAGE_BEGINNING
|
||||
}
|
||||
|
||||
val liveList: MutableLiveData<List<Image>> = MutableLiveData(listOf())
|
||||
val error: MutableLiveData<Resource.Error.ErrorType?> = MutableLiveData()
|
||||
val loading: MutableLiveData<Boolean> = MutableLiveData()
|
||||
val deleting: MutableLiveData<Boolean> = MutableLiveData()
|
||||
var noMoreContent = false
|
||||
var lastEvent: Event? = null
|
||||
private var loadedFirstTime = false
|
||||
var userId by Delegates.notNull<Int>()
|
||||
|
||||
@ -74,10 +80,16 @@ class ImageListViewModel @Inject constructor(private val imagesRepository: Image
|
||||
viewModelScope.launch {
|
||||
imagesRepository.deleteImages(images).onEach {
|
||||
when(it) {
|
||||
is Resource.Error -> {}
|
||||
is Resource.Loading -> {}
|
||||
is Resource.Error -> {
|
||||
deleting.postValue(false)
|
||||
}
|
||||
is Resource.Loading -> {
|
||||
deleting.postValue(true)
|
||||
}
|
||||
is Resource.Success -> {
|
||||
liveList.value = list.filterNot { image -> images.contains(image) }
|
||||
deleting.postValue(false)
|
||||
lastEvent = Event.REMOVED_IMAGE
|
||||
liveList.postValue(list.filterNot { image -> images.contains(image) })
|
||||
}
|
||||
}
|
||||
}.flowOn(Dispatchers.IO).launchIn(this)
|
||||
|
||||
@ -34,13 +34,11 @@ class ImagesAdapter(
|
||||
}
|
||||
}
|
||||
|
||||
private var selectionState: Array<Boolean> = arrayOf()
|
||||
|
||||
var deleteMode: Boolean = false
|
||||
set(value) {
|
||||
field = value
|
||||
if(!value) {
|
||||
selectionState.forEachIndexed { index, _ -> selectionState[index] = false }
|
||||
currentList.forEach { it.delete = false }
|
||||
}
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
@ -48,7 +46,7 @@ class ImagesAdapter(
|
||||
inner class ImageViewHolder(val imageItemBinding: ImageItemBinding) : RecyclerView.ViewHolder(imageItemBinding.root)
|
||||
|
||||
fun getSelectedImages(): List<Image> {
|
||||
return currentList.filterIndexed { index, _ -> selectionState[index] }
|
||||
return currentList.filter { it.delete }
|
||||
}
|
||||
|
||||
override fun onCurrentListChanged(
|
||||
@ -57,7 +55,6 @@ class ImagesAdapter(
|
||||
) {
|
||||
super.onCurrentListChanged(previousList, currentList)
|
||||
noMoreContent = (currentList.size - previousList.size) == 0
|
||||
selectionState = Array(currentList.size) { false }
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ImageViewHolder {
|
||||
@ -89,11 +86,11 @@ class ImagesAdapter(
|
||||
holder.imageItemBinding.root.setOnClickListener {
|
||||
holder.imageItemBinding.imageCheckbox.isChecked = !holder.imageItemBinding.imageCheckbox.isChecked
|
||||
}
|
||||
holder.imageItemBinding.imageCheckbox.isChecked = selectionState[position]
|
||||
holder.imageItemBinding.imageCheckbox.isChecked = image.delete
|
||||
holder.imageItemBinding.imageCheckbox.setOnCheckedChangeListener { buttonView, isChecked ->
|
||||
selectionState[position] = isChecked
|
||||
image.delete = isChecked
|
||||
|
||||
onImageSelectedCountUpdate?.invoke(selectionState.count { it })
|
||||
onImageSelectedCountUpdate?.invoke(currentList.count { it.delete })
|
||||
}
|
||||
holder.imageItemBinding.root.setOnLongClickListener(null)
|
||||
} else {
|
||||
@ -105,9 +102,9 @@ class ImagesAdapter(
|
||||
}
|
||||
holder.imageItemBinding.imageCheckbox.setOnCheckedChangeListener(null)
|
||||
holder.imageItemBinding.root.setOnLongClickListener {
|
||||
selectionState[position] = true
|
||||
image.delete = true
|
||||
onDeleteMode?.invoke(true)
|
||||
onImageSelectedCountUpdate?.invoke(selectionState.count { it })
|
||||
onImageSelectedCountUpdate?.invoke(currentList.count { it.delete })
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.isolaatti.images.image_list.ui
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.res.Resources
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
@ -51,6 +52,7 @@ class ImagesFragment : Fragment() {
|
||||
|
||||
private val imageMakerLauncher = registerForActivityResult(ImageMakerContract()) { image ->
|
||||
image?.also {
|
||||
viewModel.lastEvent = ImageListViewModel.Event.ADDED_IMAGE_BEGINNING
|
||||
viewModel.addImageAtTheBeginning(it)
|
||||
}
|
||||
}
|
||||
@ -73,6 +75,8 @@ class ImagesFragment : Fragment() {
|
||||
return FileProvider.getUriForFile(requireContext(), "${MyApplication.myApp.packageName}.provider", cacheFile)
|
||||
}
|
||||
|
||||
private var deletingImagesDialog: Dialog? = null
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
@ -93,7 +97,6 @@ class ImagesFragment : Fragment() {
|
||||
viewModel.loadNext()
|
||||
}
|
||||
}
|
||||
|
||||
setupAdapter()
|
||||
setupObservers()
|
||||
setupListeners()
|
||||
@ -201,6 +204,11 @@ class ImagesFragment : Fragment() {
|
||||
private fun setupObservers() {
|
||||
|
||||
viewModel.liveList.observe(viewLifecycleOwner) { list ->
|
||||
if(viewModel.lastEvent == ImageListViewModel.Event.REMOVED_IMAGE || viewModel.lastEvent == ImageListViewModel.Event.ADDED_IMAGE_BEGINNING) {
|
||||
actionMode?.finish()
|
||||
|
||||
}
|
||||
viewBinding.noImagesCard.visibility = if(list.isEmpty()) View.VISIBLE else View.GONE
|
||||
adapter.submitList(list)
|
||||
}
|
||||
|
||||
@ -218,6 +226,18 @@ class ImagesFragment : Fragment() {
|
||||
viewModel.error.observe(viewLifecycleOwner) {
|
||||
errorViewModel.error.value = it
|
||||
}
|
||||
|
||||
viewModel.deleting.observe(viewLifecycleOwner) { deleting ->
|
||||
if(deleting) {
|
||||
deletingImagesDialog = MaterialAlertDialogBuilder(requireContext())
|
||||
.setMessage(R.string.deleting_please_wait)
|
||||
.setCancelable(false)
|
||||
.show()
|
||||
} else {
|
||||
deletingImagesDialog?.dismiss()
|
||||
deletingImagesDialog = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@ -65,14 +65,17 @@ class ImageMakerActivity : IsolaattiBaseActivity() {
|
||||
is Resource.Error -> {
|
||||
errorViewModel.error.value = it.errorType
|
||||
binding.progressBarLoading.visibility = View.GONE
|
||||
binding.uploadPhotoFab.visibility = View.VISIBLE
|
||||
binding.textImageName.isEnabled = true
|
||||
}
|
||||
is Resource.Loading -> {
|
||||
binding.progressBarLoading.visibility = View.VISIBLE
|
||||
binding.uploadPhotoFab.visibility = View.INVISIBLE
|
||||
binding.textImageName.isEnabled = false
|
||||
}
|
||||
is Resource.Success -> {
|
||||
binding.progressBarLoading.visibility = View.GONE
|
||||
binding.uploadPhotoFab.visibility = View.VISIBLE
|
||||
setResult(Activity.RESULT_OK, Intent().putExtra(EXTRA_IMAGE, it.data))
|
||||
finish()
|
||||
}
|
||||
|
||||
9
app/src/main/res/drawable/face_kiss_wink_heart_solid.xml
Normal file
9
app/src/main/res/drawable/face_kiss_wink_heart_solid.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="512"
|
||||
android:viewportHeight="512">
|
||||
<path
|
||||
android:pathData="M498,339.7c9.1,-26.2 14,-54.4 14,-83.7C512,114.6 397.4,0 256,0S0,114.6 0,256S114.6,512 256,512c35.4,0 69.1,-7.2 99.7,-20.2c-4.8,-5.5 -8.5,-12.2 -10.4,-19.7l-22.9,-89.3c-10,-39 11.8,-80.9 51.8,-92.1c37.2,-10.4 73.8,10.1 87.5,44c12.7,-1.6 25.1,0.4 36.2,5zM296,332c0,6.9 -3.1,13.2 -7.3,18.3c-4.3,5.2 -10.1,9.7 -16.7,13.4c-2.7,1.5 -5.7,3 -8.7,4.3c3.1,1.3 6,2.7 8.7,4.3c6.6,3.7 12.5,8.2 16.7,13.4c4.3,5.1 7.3,11.4 7.3,18.3s-3.1,13.2 -7.3,18.3c-4.3,5.2 -10.1,9.7 -16.7,13.4C258.7,443.1 241.4,448 224,448c-3.6,0 -6.8,-2.5 -7.7,-6s0.6,-7.2 3.8,-9l0,0 0,0 0,0 0,0 0.2,-0.1c0.2,-0.1 0.5,-0.3 0.9,-0.5c0.8,-0.5 2,-1.2 3.4,-2.1c2.8,-1.9 6.5,-4.5 10.2,-7.6c3.7,-3.1 7.2,-6.6 9.6,-10.1c2.5,-3.5 3.5,-6.4 3.5,-8.6s-1,-5 -3.5,-8.6c-2.5,-3.5 -5.9,-6.9 -9.6,-10.1c-3.7,-3.1 -7.4,-5.7 -10.2,-7.6c-1.4,-0.9 -2.6,-1.6 -3.4,-2.1l-0.6,-0.4 -0.3,-0.2 -0.2,-0.1 0,0 0,0 0,0c-2.5,-1.4 -4.1,-4.1 -4.1,-7s1.6,-5.6 4.1,-7l0,0 0,0 0,0 0,0 0,0 0.2,-0.1c0.2,-0.1 0.5,-0.3 0.9,-0.5c0.8,-0.5 2,-1.2 3.4,-2.1c2.8,-1.9 6.5,-4.5 10.2,-7.6c3.7,-3.1 7.2,-6.6 9.6,-10.1c2.5,-3.5 3.5,-6.4 3.5,-8.6s-1,-5 -3.5,-8.6c-2.5,-3.5 -5.9,-6.9 -9.6,-10.1c-3.7,-3.1 -7.4,-5.7 -10.2,-7.6c-1.4,-0.9 -2.6,-1.6 -3.4,-2.1c-0.4,-0.2 -0.7,-0.4 -0.9,-0.5l-0.2,-0.1 0,0 0,0 0,0c-3.2,-1.8 -4.7,-5.5 -3.8,-9s4.1,-6 7.7,-6c17.4,0 34.7,4.9 47.9,12.3c6.6,3.7 12.5,8.2 16.7,13.4c4.3,5.1 7.3,11.4 7.3,18.3zM176.4,176a32,32 0,1 1,0 64,32 32,0 1,1 0,-64zM371.2,233.6c-17.6,-23.5 -52.8,-23.5 -70.4,0c-5.3,7.1 -15.3,8.5 -22.4,3.2s-8.5,-15.3 -3.2,-22.4c30.4,-40.5 91.2,-40.5 121.6,0c5.3,7.1 3.9,17.1 -3.2,22.4s-17.1,3.9 -22.4,-3.2zM434,352.3c-6,-23.2 -28.8,-37 -51.1,-30.8s-35.4,30.1 -29.5,53.4l22.9,89.3c2.2,8.7 11.2,13.9 19.8,11.4l84.9,-23.8c22.2,-6.2 35.4,-30.1 29.5,-53.4s-28.8,-37 -51.1,-30.8l-20.2,5.6 -5.4,-21z"
|
||||
android:fillColor="#1E3050"/>
|
||||
</vector>
|
||||
@ -43,4 +43,29 @@
|
||||
android:layout_margin="16dp"
|
||||
app:srcCompat="@drawable/baseline_add_24"
|
||||
android:contentDescription="@string/upload_a_picture" />
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/no_images_card"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginHorizontal="24dp"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_margin="24dp">
|
||||
<ImageView
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
android:src="@drawable/face_kiss_wink_heart_solid"
|
||||
android:layout_gravity="center_horizontal" />
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:text="No images to show, use the plus button to add a new Image"/>
|
||||
</LinearLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
@ -124,4 +124,5 @@
|
||||
<string name="audio_options">Audio options</string>
|
||||
<string name="yes_discard_image">Yes, discard image</string>
|
||||
<string name="discard_image">Discard image?</string>
|
||||
<string name="deleting_please_wait">Deleting, please wait…</string>
|
||||
</resources>
|
||||
Loading…
x
Reference in New Issue
Block a user