mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 12:23:58 +01:00
feat: show the proper message in the custom picker when all images are either uploaded or marked. (#6095)
* feat: show the message "Congratulations, all pictures in this album have been either uploaded or marked as not for upload." in the custom picker when all images are either uploaded or marked. * refactor: fix indentation in the code * refactor: replace LiveData with StateFlow * fix: fixed the bug that was causing one ImageFragment testcase to fail. * fix: fixed the Congratulation message being shown for a brief moment while switching off the switch * refactor: move hardcoded string to strings.xml. * docs: add comment to clarify visibility logic in ImageFragment --------- Co-authored-by: Nicolas Raoul <nicolas.raoul@gmail.com>
This commit is contained in:
parent
23e1f01783
commit
1c6ebafb29
4 changed files with 81 additions and 3 deletions
|
|
@ -24,6 +24,7 @@ import kotlinx.coroutines.CoroutineScope
|
|||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.TreeMap
|
||||
import kotlin.collections.ArrayList
|
||||
|
|
@ -103,6 +104,18 @@ class ImageAdapter(
|
|||
*/
|
||||
private var imagePositionAsPerIncreasingOrder = 0
|
||||
|
||||
/**
|
||||
* Stores the number of images currently visible on the screen
|
||||
*/
|
||||
private val _currentImagesCount = MutableStateFlow(0)
|
||||
val currentImagesCount = _currentImagesCount
|
||||
|
||||
/**
|
||||
* Stores whether images are being loaded or not
|
||||
*/
|
||||
private val _isLoadingImages = MutableStateFlow(false)
|
||||
val isLoadingImages = _isLoadingImages
|
||||
|
||||
/**
|
||||
* Coroutine Dispatchers and Scope.
|
||||
*/
|
||||
|
|
@ -184,8 +197,12 @@ class ImageAdapter(
|
|||
// If the position is not already visited, that means the position is new then
|
||||
// finds the next actionable image position from all images
|
||||
if (!alreadyAddedPositions.contains(position)) {
|
||||
processThumbnailForActionedImage(holder, position, uploadingContributionList)
|
||||
|
||||
processThumbnailForActionedImage(
|
||||
holder,
|
||||
position,
|
||||
uploadingContributionList
|
||||
)
|
||||
_isLoadingImages.value = false
|
||||
// If the position is already visited, that means the image is already present
|
||||
// inside map, so it will fetch the image from the map and load in the holder
|
||||
} else {
|
||||
|
|
@ -231,6 +248,7 @@ class ImageAdapter(
|
|||
position: Int,
|
||||
uploadingContributionList: List<Contribution>,
|
||||
) {
|
||||
_isLoadingImages.value = true
|
||||
val next =
|
||||
imageLoader.nextActionableImage(
|
||||
allImages,
|
||||
|
|
@ -252,6 +270,7 @@ class ImageAdapter(
|
|||
actionableImagesMap[next] = allImages[next]
|
||||
alreadyAddedPositions.add(imagePositionAsPerIncreasingOrder)
|
||||
imagePositionAsPerIncreasingOrder++
|
||||
_currentImagesCount.value = imagePositionAsPerIncreasingOrder
|
||||
Glide
|
||||
.with(holder.image)
|
||||
.load(allImages[next].uri)
|
||||
|
|
@ -267,6 +286,7 @@ class ImageAdapter(
|
|||
reachedEndOfFolder = true
|
||||
notifyItemRemoved(position)
|
||||
}
|
||||
_isLoadingImages.value = false
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -372,6 +392,7 @@ class ImageAdapter(
|
|||
emptyMap: TreeMap<Int, Image>,
|
||||
uploadedImages: List<Contribution> = ArrayList(),
|
||||
) {
|
||||
_isLoadingImages.value = true
|
||||
allImages = fixedImages
|
||||
val oldImageList: ArrayList<Image> = images
|
||||
val newImageList: ArrayList<Image> = ArrayList(newImages)
|
||||
|
|
@ -382,6 +403,7 @@ class ImageAdapter(
|
|||
reachedEndOfFolder = false
|
||||
selectedImages = ArrayList()
|
||||
imagePositionAsPerIncreasingOrder = 0
|
||||
_currentImagesCount.value = imagePositionAsPerIncreasingOrder
|
||||
val diffResult =
|
||||
DiffUtil.calculateDiff(
|
||||
ImagesDiffCallback(oldImageList, newImageList),
|
||||
|
|
@ -441,6 +463,7 @@ class ImageAdapter(
|
|||
val entry = iterator.next()
|
||||
if (entry.value == image) {
|
||||
imagePositionAsPerIncreasingOrder -= 1
|
||||
_currentImagesCount.value = imagePositionAsPerIncreasingOrder
|
||||
iterator.remove()
|
||||
alreadyAddedPositions.removeAt(alreadyAddedPositions.size - 1)
|
||||
notifyItemRemoved(index)
|
||||
|
|
|
|||
|
|
@ -12,8 +12,12 @@ import android.widget.ProgressBar
|
|||
import android.widget.Switch
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import fr.free.nrw.commons.contributions.Contribution
|
||||
|
|
@ -38,6 +42,10 @@ import fr.free.nrw.commons.theme.BaseActivity
|
|||
import fr.free.nrw.commons.upload.FileProcessor
|
||||
import fr.free.nrw.commons.upload.FileUtilsWrapper
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.TreeMap
|
||||
import javax.inject.Inject
|
||||
import kotlin.collections.ArrayList
|
||||
|
|
@ -80,6 +88,12 @@ class ImageFragment :
|
|||
*/
|
||||
var allImages: ArrayList<Image> = ArrayList()
|
||||
|
||||
/**
|
||||
* Keeps track of switch state
|
||||
*/
|
||||
private val _switchState = MutableStateFlow(false)
|
||||
val switchState = _switchState.asStateFlow()
|
||||
|
||||
/**
|
||||
* View model Factory.
|
||||
*/
|
||||
|
|
@ -214,7 +228,11 @@ class ImageFragment :
|
|||
|
||||
switch = binding?.switchWidget
|
||||
switch?.visibility = View.VISIBLE
|
||||
switch?.setOnCheckedChangeListener { _, isChecked -> onChangeSwitchState(isChecked) }
|
||||
_switchState.value = switch?.isChecked ?: false
|
||||
switch?.setOnCheckedChangeListener { _, isChecked ->
|
||||
onChangeSwitchState(isChecked)
|
||||
_switchState.value = isChecked
|
||||
}
|
||||
selectorRV = binding?.selectorRv
|
||||
loader = binding?.loader
|
||||
progressLayout = binding?.progressLayout
|
||||
|
|
@ -234,6 +252,28 @@ class ImageFragment :
|
|||
return binding?.root
|
||||
}
|
||||
|
||||
/**
|
||||
* onViewCreated
|
||||
* Updates empty text view visibility based on image count, switch state, and loading status.
|
||||
*/
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
combine(
|
||||
imageAdapter.currentImagesCount,
|
||||
switchState,
|
||||
imageAdapter.isLoadingImages
|
||||
) { imageCount, isChecked, isLoadingImages ->
|
||||
Triple(imageCount, isChecked, isLoadingImages)
|
||||
}.collect { (imageCount, isChecked, isLoadingImages) ->
|
||||
binding?.allImagesUploadedOrMarked?.isVisible =
|
||||
!isLoadingImages && !isChecked && imageCount == 0 && (switch?.isVisible == true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun onChangeSwitchState(checked: Boolean) {
|
||||
if (checked) {
|
||||
showAlreadyActionedImages = true
|
||||
|
|
|
|||
|
|
@ -49,6 +49,20 @@
|
|||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/all_images_uploaded_or_marked"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
android:textSize="16sp"
|
||||
android:padding="@dimen/standard_gap"
|
||||
android:textColor="@color/text_color_selector"
|
||||
android:text="@string/congratulations_all_pictures_in_this_album_have_been_either_uploaded_or_marked_as_not_for_upload"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
/>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/loader"
|
||||
|
|
|
|||
|
|
@ -867,5 +867,6 @@ Upload your first media by tapping on the add button.</string>
|
|||
<string name="account_vanish_request_confirm"><![CDATA[Vanishing is a <b>last resort</b> and should <b>only be used when you wish to stop editing forever</b> and also to hide as many of your past associations as possible.<br/><br/>Account deletion on Wikimedia Commons is done by changing your account name to make it so others cannot recognize your contributions in a process called account vanishing. <b>Vanishing does not guarantee complete anonymity or remove contributions to the projects</b>.]]></string>
|
||||
<string name="caption">Caption</string>
|
||||
<string name="caption_copied_to_clipboard">Caption copied to clipboard</string>
|
||||
<string name="congratulations_all_pictures_in_this_album_have_been_either_uploaded_or_marked_as_not_for_upload">Congratulations, all pictures in this album have been either uploaded or marked as not for upload.</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue