diff --git a/app/src/main/java/com/github/libretube/db/obj/WatchPosition.kt b/app/src/main/java/com/github/libretube/db/obj/WatchPosition.kt index 2f6f0e050..50d953899 100644 --- a/app/src/main/java/com/github/libretube/db/obj/WatchPosition.kt +++ b/app/src/main/java/com/github/libretube/db/obj/WatchPosition.kt @@ -5,6 +5,9 @@ import androidx.room.Entity import androidx.room.PrimaryKey import kotlinx.serialization.Serializable +/** + * @param position: Position in milliseconds + */ @Serializable @Entity(tableName = "watchPosition") data class WatchPosition( diff --git a/app/src/main/java/com/github/libretube/ui/sheets/ChannelOptionsBottomSheet.kt b/app/src/main/java/com/github/libretube/ui/sheets/ChannelOptionsBottomSheet.kt index f9f8795f4..321b10415 100644 --- a/app/src/main/java/com/github/libretube/ui/sheets/ChannelOptionsBottomSheet.kt +++ b/app/src/main/java/com/github/libretube/ui/sheets/ChannelOptionsBottomSheet.kt @@ -17,7 +17,7 @@ import kotlinx.coroutines.withContext /** * Dialog with different options for a selected video. * - * Needs the [videoId] to load the content from the right video. + * Needs the [channelId] to load the content from the right video. */ class ChannelOptionsBottomSheet( private val channelId: String, diff --git a/app/src/main/java/com/github/libretube/ui/sheets/PlayingQueueSheet.kt b/app/src/main/java/com/github/libretube/ui/sheets/PlayingQueueSheet.kt index 5464e78c1..9b4724c00 100644 --- a/app/src/main/java/com/github/libretube/ui/sheets/PlayingQueueSheet.kt +++ b/app/src/main/java/com/github/libretube/ui/sheets/PlayingQueueSheet.kt @@ -10,21 +10,30 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.github.libretube.R import com.github.libretube.databinding.QueueBottomSheetBinding +import com.github.libretube.db.DatabaseHelper +import com.github.libretube.db.DatabaseHolder +import com.github.libretube.db.obj.WatchPosition +import com.github.libretube.extensions.toID import com.github.libretube.ui.adapters.PlayingQueueAdapter import com.github.libretube.ui.dialogs.AddToPlaylistDialog import com.github.libretube.util.PlayingQueue import com.google.android.material.dialog.MaterialAlertDialogBuilder import java.lang.IllegalArgumentException +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext class PlayingQueueSheet : ExpandedBottomSheet() { - private lateinit var binding: QueueBottomSheetBinding + private var _binding: QueueBottomSheetBinding? = null + private val binding get() = _binding!! override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { - binding = QueueBottomSheetBinding.inflate(layoutInflater) + _binding = QueueBottomSheetBinding.inflate(layoutInflater) return binding.root } @@ -89,6 +98,10 @@ class PlayingQueueSheet : ExpandedBottomSheet() { dialog?.dismiss() } + binding.watchPositionsOptions.setOnClickListener { + showWatchPositionsOptions() + } + val callback = object : ItemTouchHelper.SimpleCallback( ItemTouchHelper.UP or ItemTouchHelper.DOWN, ItemTouchHelper.LEFT @@ -141,7 +154,60 @@ class PlayingQueueSheet : ExpandedBottomSheet() { else -> throw IllegalArgumentException() } PlayingQueue.setStreams(newQueue) - binding.optionsRecycler.adapter?.notifyDataSetChanged() + _binding?.optionsRecycler?.adapter?.notifyDataSetChanged() + } + .show() + } + + @SuppressLint("NotifyDataSetChanged") + private fun showWatchPositionsOptions() { + val options = arrayOf( + getString(R.string.mark_as_watched), + getString(R.string.mark_as_unwatched), + getString(R.string.remove_watched_videos) + ) + MaterialAlertDialogBuilder(requireContext()) + .setTitle(R.string.watch_positions) + .setItems(options) { _, index -> + when (index) { + 0 -> { + CoroutineScope(Dispatchers.IO).launch { + PlayingQueue.getStreams().forEach { + val videoId = it.url.orEmpty().toID() + val duration = it.duration ?: 0 + val watchPosition = WatchPosition(videoId, duration * 1000) + DatabaseHolder.Database.watchPositionDao().insert(watchPosition) + } + } + } + + 1 -> { + CoroutineScope(Dispatchers.IO).launch { + PlayingQueue.getStreams().forEach { + DatabaseHolder.Database.watchPositionDao() + .deleteByVideoId(it.url.orEmpty().toID()) + } + } + } + + 2 -> { + CoroutineScope(Dispatchers.IO).launch { + val currentStream = PlayingQueue.getCurrent() + val streams = DatabaseHelper + .filterUnwatched(PlayingQueue.getStreams()) + .toMutableList() + if (currentStream != null && + streams.none { it.url?.toID() == currentStream.url?.toID() } + ) { + streams.add(0, currentStream) + } + PlayingQueue.setStreams(streams) + withContext(Dispatchers.Main) { + _binding?.optionsRecycler?.adapter?.notifyDataSetChanged() + } + } + } + } } .show() } diff --git a/app/src/main/res/drawable/ic_eye.xml b/app/src/main/res/drawable/ic_eye.xml new file mode 100644 index 000000000..9cd541120 --- /dev/null +++ b/app/src/main/res/drawable/ic_eye.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/layout/queue_bottom_sheet.xml b/app/src/main/res/layout/queue_bottom_sheet.xml index 0d55de50f..63f94d7d0 100644 --- a/app/src/main/res/layout/queue_bottom_sheet.xml +++ b/app/src/main/res/layout/queue_bottom_sheet.xml @@ -39,64 +39,42 @@ + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 53de2cd0a..a773f66a4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -439,6 +439,7 @@ Sort by Uploader name Duration: %1$s + Remove watched videos Import subscriptions from diff --git a/app/src/main/res/values/style.xml b/app/src/main/res/values/style.xml index 7af5319f4..46f67d8b7 100644 --- a/app/src/main/res/values/style.xml +++ b/app/src/main/res/values/style.xml @@ -248,4 +248,13 @@ + + \ No newline at end of file