Issue#7 Enable Deleting Pending Video by swiping

This commit is contained in:
Gergely Hegedus 2022-04-21 21:17:21 +03:00
parent 8d709206fd
commit 136530b927
6 changed files with 115 additions and 10 deletions

View file

@ -0,0 +1,13 @@
package org.fnives.tiktokdownloader.data.usecase
import org.fnives.tiktokdownloader.data.local.VideoInPendingLocalSource
import org.fnives.tiktokdownloader.data.model.VideoInPending
class MoveVideoInQueue(
private val videoInPendingLocalSource: VideoInPendingLocalSource
) {
operator fun invoke(videoInPending: VideoInPending, to: VideoInPending) {
}
}

View file

@ -0,0 +1,13 @@
package org.fnives.tiktokdownloader.data.usecase
import org.fnives.tiktokdownloader.data.local.VideoInPendingLocalSource
import org.fnives.tiktokdownloader.data.model.VideoInPending
class RemoveVideoFromQueueUseCase(
private val videoInPendingLocalSource: VideoInPendingLocalSource
) {
operator fun invoke(videoInPending: VideoInPending) {
videoInPendingLocalSource.removeVideoFromQueue(videoInPending)
}
}

View file

@ -2,13 +2,16 @@ package org.fnives.tiktokdownloader.di.module
import kotlinx.coroutines.Dispatchers
import org.fnives.tiktokdownloader.data.usecase.AddVideoToQueueUseCase
import org.fnives.tiktokdownloader.data.usecase.MoveVideoInQueue
import org.fnives.tiktokdownloader.data.usecase.RemoveVideoFromQueueUseCase
import org.fnives.tiktokdownloader.data.usecase.StateOfVideosObservableUseCase
import org.fnives.tiktokdownloader.data.usecase.UrlVerificationUseCase
import org.fnives.tiktokdownloader.data.usecase.VideoDownloadingProcessorUseCase
class UseCaseModule(
private val localSourceModule: LocalSourceModule,
private val networkModule: NetworkModule) {
private val networkModule: NetworkModule
) {
val stateOfVideosObservableUseCase: StateOfVideosObservableUseCase
get() = StateOfVideosObservableUseCase(
@ -24,7 +27,18 @@ class UseCaseModule(
val addVideoToQueueUseCase: AddVideoToQueueUseCase
get() = AddVideoToQueueUseCase(
urlVerificationUseCase,
localSourceModule.videoInPendingLocalSource)
localSourceModule.videoInPendingLocalSource
)
val removeVideoFromQueueUseCase: RemoveVideoFromQueueUseCase
get() = RemoveVideoFromQueueUseCase(
localSourceModule.videoInPendingLocalSource
)
val moveVideoInQueue: MoveVideoInQueue
get() = MoveVideoInQueue(
localSourceModule.videoInPendingLocalSource
)
val videoDownloadingProcessorUseCase: VideoDownloadingProcessorUseCase by lazy {
VideoDownloadingProcessorUseCase(

View file

@ -24,6 +24,7 @@ class ViewModelModule(private val useCaseModule: UseCaseModule) {
get() = QueueViewModel(
useCaseModule.stateOfVideosObservableUseCase,
useCaseModule.addVideoToQueueUseCase,
useCaseModule.removeVideoFromQueueUseCase,
useCaseModule.videoDownloadingProcessorUseCase
)
}

View file

@ -9,7 +9,7 @@ import android.widget.EditText
import androidx.core.net.toUri
import androidx.core.widget.doAfterTextChanged
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.RecyclerView
import org.fnives.tiktokdownloader.R
import org.fnives.tiktokdownloader.data.model.VideoState
@ -22,22 +22,21 @@ class QueueFragment : Fragment(R.layout.fragment_queue) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val recycler = view.findViewById<RecyclerView>(R.id.recycler)
val adapter = QueueItemAdapter(
itemClicked = viewModel::onItemClicked,
urlClicked = viewModel::onUrlClicked
)
recycler.adapter = adapter
recyclerViewSetup(recycler)
navigationSetup()
val saveUrlCta = view.findViewById<Button>(R.id.save_cta)
val input = view.findViewById<EditText>(R.id.download_url_input)
input.doAfterTextChanged {
saveUrlCta.isEnabled = it?.isNotBlank() == true
}
saveUrlCta.setOnClickListener {
recycler.smoothScrollToPosition(0)
viewModel.onSaveClicked(input.text?.toString().orEmpty())
input.setText("")
}
}
private fun navigationSetup() {
viewModel.navigationEvent.observe(viewLifecycleOwner) {
val intent = when (val data = it.item) {
is QueueViewModel.NavigationEvent.OpenBrowser -> {
@ -49,6 +48,21 @@ class QueueFragment : Fragment(R.layout.fragment_queue) {
}
startActivity(intent)
}
}
private fun recyclerViewSetup(recycler: RecyclerView) {
val adapter = QueueItemAdapter(
itemClicked = viewModel::onItemClicked,
urlClicked = viewModel::onUrlClicked
)
recycler.adapter = adapter
val touchHelper = ItemTouchHelper(PendingItemTouchHelper(
whichItem = { adapter.currentList.getOrNull(it.bindingAdapterPosition) },
onDeleteElement = viewModel::onElementDeleted,
onMovedElement = viewModel::onElementMoved
))
touchHelper.attachToRecyclerView(recycler)
viewModel.downloads.observe(viewLifecycleOwner) { videoStates ->
adapter.submitList(videoStates, Runnable {
@ -59,6 +73,36 @@ class QueueFragment : Fragment(R.layout.fragment_queue) {
}
}
class PendingItemTouchHelper(
private val whichItem: (RecyclerView.ViewHolder) -> VideoState?,
private val onDeleteElement: (VideoState) -> Unit,
private val onMovedElement: (VideoState, VideoState) -> Boolean
) : ItemTouchHelper.Callback() {
override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {
val item = whichItem(viewHolder) ?: return 0
when (item) {
is VideoState.InPending -> Unit
is VideoState.Downloaded,
is VideoState.InProcess -> return 0
}
val dragFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN
val swipeFlags = ItemTouchHelper.START or ItemTouchHelper.END
return makeMovementFlags(dragFlags, swipeFlags)
}
override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
val dragged = whichItem(target) ?: return false
val movedTo = whichItem(viewHolder) ?: return false
return onMovedElement(dragged, movedTo)
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
whichItem(viewHolder)?.let { onDeleteElement(it) }
}
}
companion object {
fun newInstance(): QueueFragment = QueueFragment()

View file

@ -3,7 +3,10 @@ package org.fnives.tiktokdownloader.ui.main.queue
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import org.fnives.tiktokdownloader.data.model.VideoState
import org.fnives.tiktokdownloader.data.usecase.AddVideoToQueueUseCase
import org.fnives.tiktokdownloader.data.usecase.MoveVideoInQueue
import org.fnives.tiktokdownloader.data.usecase.RemoveVideoFromQueueUseCase
import org.fnives.tiktokdownloader.data.usecase.StateOfVideosObservableUseCase
import org.fnives.tiktokdownloader.data.usecase.VideoDownloadingProcessorUseCase
import org.fnives.tiktokdownloader.ui.shared.Event
@ -12,7 +15,9 @@ import org.fnives.tiktokdownloader.ui.shared.asLiveData
class QueueViewModel(
stateOfVideosObservableUseCase: StateOfVideosObservableUseCase,
private val addVideoToQueueUseCase: AddVideoToQueueUseCase,
private val videoDownloadingProcessorUseCase: VideoDownloadingProcessorUseCase
private val removeVideoFromQueueUseCase: RemoveVideoFromQueueUseCase,
private val videoDownloadingProcessorUseCase: VideoDownloadingProcessorUseCase,
private val moveVideoInQueue: MoveVideoInQueue
) : ViewModel() {
val downloads = asLiveData(stateOfVideosObservableUseCase())
@ -32,6 +37,21 @@ class QueueViewModel(
_navigationEvent.value = Event(NavigationEvent.OpenBrowser(url))
}
fun onElementDeleted(videoState: VideoState) {
when (videoState) {
is VideoState.InPending -> removeVideoFromQueueUseCase(videoState.videoInPending)
is VideoState.Downloaded,
is VideoState.InProcess -> Unit
}
}
fun onElementMoved(moved: VideoState, to: VideoState): Boolean {
if (moved !is VideoState.InPending) return false
if (to !is VideoState.InPending) return false
moveVideoInQueue(moved.videoInPending, to.videoInPending)
return true
}
sealed class NavigationEvent {
data class OpenBrowser(val url: String) : NavigationEvent()
data class OpenGallery(val uri: String) : NavigationEvent()