Issue#7 Enable Deleting Pending Video by swiping
This commit is contained in:
parent
8d709206fd
commit
136530b927
6 changed files with 115 additions and 10 deletions
|
|
@ -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) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,13 +2,16 @@ package org.fnives.tiktokdownloader.di.module
|
||||||
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import org.fnives.tiktokdownloader.data.usecase.AddVideoToQueueUseCase
|
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.StateOfVideosObservableUseCase
|
||||||
import org.fnives.tiktokdownloader.data.usecase.UrlVerificationUseCase
|
import org.fnives.tiktokdownloader.data.usecase.UrlVerificationUseCase
|
||||||
import org.fnives.tiktokdownloader.data.usecase.VideoDownloadingProcessorUseCase
|
import org.fnives.tiktokdownloader.data.usecase.VideoDownloadingProcessorUseCase
|
||||||
|
|
||||||
class UseCaseModule(
|
class UseCaseModule(
|
||||||
private val localSourceModule: LocalSourceModule,
|
private val localSourceModule: LocalSourceModule,
|
||||||
private val networkModule: NetworkModule) {
|
private val networkModule: NetworkModule
|
||||||
|
) {
|
||||||
|
|
||||||
val stateOfVideosObservableUseCase: StateOfVideosObservableUseCase
|
val stateOfVideosObservableUseCase: StateOfVideosObservableUseCase
|
||||||
get() = StateOfVideosObservableUseCase(
|
get() = StateOfVideosObservableUseCase(
|
||||||
|
|
@ -24,7 +27,18 @@ class UseCaseModule(
|
||||||
val addVideoToQueueUseCase: AddVideoToQueueUseCase
|
val addVideoToQueueUseCase: AddVideoToQueueUseCase
|
||||||
get() = AddVideoToQueueUseCase(
|
get() = AddVideoToQueueUseCase(
|
||||||
urlVerificationUseCase,
|
urlVerificationUseCase,
|
||||||
localSourceModule.videoInPendingLocalSource)
|
localSourceModule.videoInPendingLocalSource
|
||||||
|
)
|
||||||
|
|
||||||
|
val removeVideoFromQueueUseCase: RemoveVideoFromQueueUseCase
|
||||||
|
get() = RemoveVideoFromQueueUseCase(
|
||||||
|
localSourceModule.videoInPendingLocalSource
|
||||||
|
)
|
||||||
|
|
||||||
|
val moveVideoInQueue: MoveVideoInQueue
|
||||||
|
get() = MoveVideoInQueue(
|
||||||
|
localSourceModule.videoInPendingLocalSource
|
||||||
|
)
|
||||||
|
|
||||||
val videoDownloadingProcessorUseCase: VideoDownloadingProcessorUseCase by lazy {
|
val videoDownloadingProcessorUseCase: VideoDownloadingProcessorUseCase by lazy {
|
||||||
VideoDownloadingProcessorUseCase(
|
VideoDownloadingProcessorUseCase(
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ class ViewModelModule(private val useCaseModule: UseCaseModule) {
|
||||||
get() = QueueViewModel(
|
get() = QueueViewModel(
|
||||||
useCaseModule.stateOfVideosObservableUseCase,
|
useCaseModule.stateOfVideosObservableUseCase,
|
||||||
useCaseModule.addVideoToQueueUseCase,
|
useCaseModule.addVideoToQueueUseCase,
|
||||||
|
useCaseModule.removeVideoFromQueueUseCase,
|
||||||
useCaseModule.videoDownloadingProcessorUseCase
|
useCaseModule.videoDownloadingProcessorUseCase
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -9,7 +9,7 @@ import android.widget.EditText
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import androidx.core.widget.doAfterTextChanged
|
import androidx.core.widget.doAfterTextChanged
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.Observer
|
import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import org.fnives.tiktokdownloader.R
|
import org.fnives.tiktokdownloader.R
|
||||||
import org.fnives.tiktokdownloader.data.model.VideoState
|
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?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
val recycler = view.findViewById<RecyclerView>(R.id.recycler)
|
val recycler = view.findViewById<RecyclerView>(R.id.recycler)
|
||||||
val adapter = QueueItemAdapter(
|
recyclerViewSetup(recycler)
|
||||||
itemClicked = viewModel::onItemClicked,
|
navigationSetup()
|
||||||
urlClicked = viewModel::onUrlClicked
|
|
||||||
)
|
|
||||||
recycler.adapter = adapter
|
|
||||||
val saveUrlCta = view.findViewById<Button>(R.id.save_cta)
|
val saveUrlCta = view.findViewById<Button>(R.id.save_cta)
|
||||||
val input = view.findViewById<EditText>(R.id.download_url_input)
|
val input = view.findViewById<EditText>(R.id.download_url_input)
|
||||||
input.doAfterTextChanged {
|
input.doAfterTextChanged {
|
||||||
saveUrlCta.isEnabled = it?.isNotBlank() == true
|
saveUrlCta.isEnabled = it?.isNotBlank() == true
|
||||||
}
|
}
|
||||||
saveUrlCta.setOnClickListener {
|
saveUrlCta.setOnClickListener {
|
||||||
recycler.smoothScrollToPosition(0)
|
|
||||||
viewModel.onSaveClicked(input.text?.toString().orEmpty())
|
viewModel.onSaveClicked(input.text?.toString().orEmpty())
|
||||||
input.setText("")
|
input.setText("")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun navigationSetup() {
|
||||||
viewModel.navigationEvent.observe(viewLifecycleOwner) {
|
viewModel.navigationEvent.observe(viewLifecycleOwner) {
|
||||||
val intent = when (val data = it.item) {
|
val intent = when (val data = it.item) {
|
||||||
is QueueViewModel.NavigationEvent.OpenBrowser -> {
|
is QueueViewModel.NavigationEvent.OpenBrowser -> {
|
||||||
|
|
@ -49,6 +48,21 @@ class QueueFragment : Fragment(R.layout.fragment_queue) {
|
||||||
}
|
}
|
||||||
startActivity(intent)
|
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 ->
|
viewModel.downloads.observe(viewLifecycleOwner) { videoStates ->
|
||||||
adapter.submitList(videoStates, Runnable {
|
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 {
|
companion object {
|
||||||
|
|
||||||
fun newInstance(): QueueFragment = QueueFragment()
|
fun newInstance(): QueueFragment = QueueFragment()
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,10 @@ package org.fnives.tiktokdownloader.ui.main.queue
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
|
import org.fnives.tiktokdownloader.data.model.VideoState
|
||||||
import org.fnives.tiktokdownloader.data.usecase.AddVideoToQueueUseCase
|
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.StateOfVideosObservableUseCase
|
||||||
import org.fnives.tiktokdownloader.data.usecase.VideoDownloadingProcessorUseCase
|
import org.fnives.tiktokdownloader.data.usecase.VideoDownloadingProcessorUseCase
|
||||||
import org.fnives.tiktokdownloader.ui.shared.Event
|
import org.fnives.tiktokdownloader.ui.shared.Event
|
||||||
|
|
@ -12,7 +15,9 @@ import org.fnives.tiktokdownloader.ui.shared.asLiveData
|
||||||
class QueueViewModel(
|
class QueueViewModel(
|
||||||
stateOfVideosObservableUseCase: StateOfVideosObservableUseCase,
|
stateOfVideosObservableUseCase: StateOfVideosObservableUseCase,
|
||||||
private val addVideoToQueueUseCase: AddVideoToQueueUseCase,
|
private val addVideoToQueueUseCase: AddVideoToQueueUseCase,
|
||||||
private val videoDownloadingProcessorUseCase: VideoDownloadingProcessorUseCase
|
private val removeVideoFromQueueUseCase: RemoveVideoFromQueueUseCase,
|
||||||
|
private val videoDownloadingProcessorUseCase: VideoDownloadingProcessorUseCase,
|
||||||
|
private val moveVideoInQueue: MoveVideoInQueue
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
val downloads = asLiveData(stateOfVideosObservableUseCase())
|
val downloads = asLiveData(stateOfVideosObservableUseCase())
|
||||||
|
|
@ -32,6 +37,21 @@ class QueueViewModel(
|
||||||
_navigationEvent.value = Event(NavigationEvent.OpenBrowser(url))
|
_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 {
|
sealed class NavigationEvent {
|
||||||
data class OpenBrowser(val url: String) : NavigationEvent()
|
data class OpenBrowser(val url: String) : NavigationEvent()
|
||||||
data class OpenGallery(val uri: String) : NavigationEvent()
|
data class OpenGallery(val uri: String) : NavigationEvent()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue