diff --git a/app/src/main/java/com/github/libretube/api/SubscriptionHelper.kt b/app/src/main/java/com/github/libretube/api/SubscriptionHelper.kt index 86c241d7f..42af1e63f 100644 --- a/app/src/main/java/com/github/libretube/api/SubscriptionHelper.kt +++ b/app/src/main/java/com/github/libretube/api/SubscriptionHelper.kt @@ -1,12 +1,16 @@ package com.github.libretube.api +import android.content.Context import android.util.Log +import com.github.libretube.R +import com.github.libretube.constants.PreferenceKeys import com.github.libretube.db.DatabaseHolder.Companion.Database import com.github.libretube.db.obj.LocalSubscription import com.github.libretube.extensions.TAG import com.github.libretube.extensions.awaitQuery import com.github.libretube.extensions.query import com.github.libretube.util.PreferenceHelper +import com.google.android.material.dialog.MaterialAlertDialogBuilder import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -55,6 +59,24 @@ object SubscriptionHelper { } } + fun handleUnsubscribe(context: Context, channelId: String, channelName: String?, onUnsubscribe: () -> Unit) { + if (!PreferenceHelper.getBoolean(PreferenceKeys.CONFIRM_UNSUBSCRIBE, false)) { + unsubscribe(channelId) + onUnsubscribe.invoke() + return + } + + MaterialAlertDialogBuilder(context) + .setTitle(R.string.unsubscribe) + .setMessage(context.getString(R.string.confirm_unsubscribe, channelName)) + .setPositiveButton(R.string.unsubscribe) { _, _ -> + unsubscribe(channelId) + onUnsubscribe.invoke() + } + .setNegativeButton(R.string.cancel, null) + .show() + } + suspend fun isSubscribed(channelId: String): Boolean? { if (PreferenceHelper.getToken() != "") { val isSubscribed = try { @@ -99,7 +121,7 @@ object SubscriptionHelper { } } - fun getLocalSubscriptions(): List { + private fun getLocalSubscriptions(): List { return awaitQuery { Database.localSubscriptionDao().getAll() } @@ -107,6 +129,6 @@ object SubscriptionHelper { fun getFormattedLocalSubscriptions(): String { val localSubscriptions = getLocalSubscriptions() - return localSubscriptions.map { it.channelId }.joinToString(",") + return localSubscriptions.joinToString(",") { it.channelId } } } diff --git a/app/src/main/java/com/github/libretube/constants/PreferenceKeys.kt b/app/src/main/java/com/github/libretube/constants/PreferenceKeys.kt index 738a0f6e8..f29f5716b 100644 --- a/app/src/main/java/com/github/libretube/constants/PreferenceKeys.kt +++ b/app/src/main/java/com/github/libretube/constants/PreferenceKeys.kt @@ -104,6 +104,7 @@ object PreferenceKeys { const val CLEAR_WATCH_HISTORY = "clear_watch_history" const val CLEAR_WATCH_POSITIONS = "clear_watch_positions" const val SHARE_WITH_TIME_CODE = "share_with_time_code" + const val CONFIRM_UNSUBSCRIBE = "confirm_unsubscribing" /** * History diff --git a/app/src/main/java/com/github/libretube/ui/adapters/SearchAdapter.kt b/app/src/main/java/com/github/libretube/ui/adapters/SearchAdapter.kt index 02c570010..371b25ec4 100644 --- a/app/src/main/java/com/github/libretube/ui/adapters/SearchAdapter.kt +++ b/app/src/main/java/com/github/libretube/ui/adapters/SearchAdapter.kt @@ -1,6 +1,7 @@ package com.github.libretube.ui.adapters import android.annotation.SuppressLint +import android.content.Context import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -128,13 +129,13 @@ class SearchAdapter( root.setOnClickListener { NavigationHelper.navigateChannel(root.context, item.url) } - val channelId = item.url!!.toID() - isSubscribed(channelId, binding) + isSubscribed(root.context, item, binding) } } - private fun isSubscribed(channelId: String, binding: ChannelRowBinding) { + private fun isSubscribed(context: Context, streamItem: ContentItem, binding: ChannelRowBinding) { + val channelId = streamItem.url!!.toID() // check whether the user subscribed to the channel CoroutineScope(Dispatchers.Main).launch { var isSubscribed = SubscriptionHelper.isSubscribed(channelId) @@ -151,14 +152,13 @@ class SearchAdapter( binding.searchSubButton.setOnClickListener { if (isSubscribed == false) { SubscriptionHelper.subscribe(channelId) - binding.searchSubButton.text = - binding.root.context.getString(R.string.unsubscribe) + binding.searchSubButton.text = binding.root.context.getString(R.string.unsubscribe) isSubscribed = true } else { - SubscriptionHelper.unsubscribe(channelId) - binding.searchSubButton.text = - binding.root.context.getString(R.string.subscribe) - isSubscribed = false + SubscriptionHelper.handleUnsubscribe(context, channelId, streamItem.uploaderName) { + binding.searchSubButton.text = binding.root.context.getString(R.string.subscribe) + isSubscribed = false + } } } } diff --git a/app/src/main/java/com/github/libretube/ui/adapters/SubscriptionChannelAdapter.kt b/app/src/main/java/com/github/libretube/ui/adapters/SubscriptionChannelAdapter.kt index ca792802d..029131b03 100644 --- a/app/src/main/java/com/github/libretube/ui/adapters/SubscriptionChannelAdapter.kt +++ b/app/src/main/java/com/github/libretube/ui/adapters/SubscriptionChannelAdapter.kt @@ -38,13 +38,13 @@ class SubscriptionChannelAdapter(private val subscriptions: MutableList?) { + tabs?.firstOrNull { it.name == "Playlists" }?.let { + binding.playlists.visibility = View.VISIBLE + } + + tabs?.firstOrNull { it.name == "Channels" }?.let { + binding.playlists.visibility = View.VISIBLE + } + + tabs?.firstOrNull { it.name == "Livestreams" }?.let { + binding.playlists.visibility = View.VISIBLE + } + + tabs?.firstOrNull { it.name == "Shorts" }?.let { + binding.playlists.visibility = View.VISIBLE + } + + binding.tabChips.setOnCheckedStateChangeListener { _, _ -> + reactToTabChange(tabs) + } + } + + private fun reactToTabChange(tabs: List?) { + when (binding.tabChips.checkedChipId) { + binding.videos.id -> { binding.channelRecView.adapter = channelAdapter onScrollEnd = { fetchChannelNextPage() } - binding.tabChips.children.forEach { child -> - if (child != it) (child as Chip).isChecked = false - } } - - response.tabs?.firstOrNull { it.name == "Playlists" }?.let { - setupTab(binding.playlists, it) + binding.channels.id -> { + tabs?.first { it.name == "Channels" }?.let { loadTab(it) } } - - response.tabs?.firstOrNull { it.name == "Channels" }?.let { - setupTab(binding.channels, it) + binding.playlists.id -> { + tabs?.first { it.name == "Playlists" }?.let { loadTab(it) } } - - response.tabs?.firstOrNull { it.name == "Livestreams" }?.let { - setupTab(binding.livestreams, it) + binding.livestreams.id -> { + tabs?.first { it.name == "Livestreams" }?.let { loadTab(it) } } - - response.tabs?.firstOrNull { it.name == "Shorts" }?.let { - setupTab(binding.shorts, it) + binding.shorts.id -> { + tabs?.first { it.name == "Shorts" }?.let { loadTab(it) } } } } - private fun setupTab(chip: Chip, tab: ChannelTab) { - chip.visibility = View.VISIBLE - chip.setOnClickListener { - binding.tabChips.children.forEach { - if (it != chip) (it as Chip).isChecked = false + private fun loadTab(tab: ChannelTab) { + scope.launch { + val response = try { + RetrofitInstance.api.getChannelTab(tab.data!!) + } catch (e: Exception) { + return@launch } - scope.launch { - val response = try { - RetrofitInstance.api.getChannelTab(tab.data!!) - } catch (e: Exception) { - return@launch - } - val adapter = SearchAdapter( - response.content.toMutableList(), - childFragmentManager - ) + val adapter = SearchAdapter( + response.content.toMutableList(), + childFragmentManager + ) - runOnUiThread { - binding.channelRecView.adapter = adapter - } + runOnUiThread { + binding.channelRecView.adapter = adapter + } - var tabNextPage = response.nextpage - onScrollEnd = { - tabNextPage?.let { - fetchTabNextPage(it, tab, adapter) { nextPage -> - tabNextPage = nextPage - } + var tabNextPage = response.nextpage + onScrollEnd = { + tabNextPage?.let { + fetchTabNextPage(it, tab, adapter) { nextPage -> + tabNextPage = nextPage } } } diff --git a/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt b/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt index 411150682..d93ee248b 100644 --- a/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt +++ b/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt @@ -863,20 +863,16 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions { } }) - // check if livestream - if (response.duration > 0) { - // download clicked - binding.relPlayerDownload.setOnClickListener { - if (!DownloadService.IS_DOWNLOAD_RUNNING) { - val newFragment = DownloadDialog(videoId!!) - newFragment.show(childFragmentManager, DownloadDialog::class.java.name) - } else { - Toast.makeText(context, R.string.dlisinprogress, Toast.LENGTH_SHORT) - .show() - } + binding.relPlayerDownload.setOnClickListener { + if (response.duration <= 0) { + Toast.makeText(context, R.string.cannotDownload, Toast.LENGTH_SHORT).show() + } else if (!DownloadService.IS_DOWNLOAD_RUNNING) { + val newFragment = DownloadDialog(videoId!!) + newFragment.show(childFragmentManager, DownloadDialog::class.java.name) + } else { + Toast.makeText(context, R.string.dlisinprogress, Toast.LENGTH_SHORT) + .show() } - } else { - Toast.makeText(context, R.string.cannotDownload, Toast.LENGTH_SHORT).show() } if (response.hls != null) { @@ -1271,9 +1267,10 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions { } binding.playerSubscribe.setOnClickListener { if (isSubscribed == true) { - SubscriptionHelper.unsubscribe(channelId) - binding.playerSubscribe.text = getString(R.string.subscribe) - isSubscribed = false + SubscriptionHelper.handleUnsubscribe(requireContext(), channelId, streams.uploader) { + binding.playerSubscribe.text = getString(R.string.subscribe) + isSubscribed = false + } } else { SubscriptionHelper.subscribe(channelId) binding.playerSubscribe.text = getString(R.string.unsubscribe) diff --git a/app/src/main/res/drawable/ic_check.xml b/app/src/main/res/drawable/ic_check.xml new file mode 100644 index 000000000..b648f5705 --- /dev/null +++ b/app/src/main/res/drawable/ic_check.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/layout/fragment_channel.xml b/app/src/main/res/layout/fragment_channel.xml index ab26d98aa..f3197e338 100644 --- a/app/src/main/res/layout/fragment_channel.xml +++ b/app/src/main/res/layout/fragment_channel.xml @@ -124,12 +124,15 @@ + android:layout_height="wrap_content" + app:checkedChip="@+id/videos" + app:selectionRequired="true" + app:singleLine="true" + app:singleSelection="true"> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index fd274b7cd..6ee7f5fb4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -356,6 +356,9 @@ Alternative videos layout Default light Playlist cloned + Are you sure you want to unsubscribe %1$s? + Confirm unsubscribing + Show a confirmation dialog before unsubscribing. Download Service diff --git a/app/src/main/res/values/style.xml b/app/src/main/res/values/style.xml index a46541859..fbae8030c 100644 --- a/app/src/main/res/values/style.xml +++ b/app/src/main/res/values/style.xml @@ -186,7 +186,7 @@ slide -