diff --git a/app/src/main/java/com/github/libretube/adapters/SearchAdapter.kt b/app/src/main/java/com/github/libretube/adapters/SearchAdapter.kt index 3a76bbb68..793440518 100644 --- a/app/src/main/java/com/github/libretube/adapters/SearchAdapter.kt +++ b/app/src/main/java/com/github/libretube/adapters/SearchAdapter.kt @@ -13,18 +13,15 @@ import com.github.libretube.databinding.VideoRowBinding import com.github.libretube.dialogs.PlaylistOptionsDialog import com.github.libretube.dialogs.VideoOptionsDialog import com.github.libretube.obj.SearchItem -import com.github.libretube.obj.Subscribe -import com.github.libretube.preferences.PreferenceHelper import com.github.libretube.util.ConnectionHelper import com.github.libretube.util.NavigationHelper -import com.github.libretube.util.RetrofitInstance +import com.github.libretube.util.SubscriptionHelper import com.github.libretube.util.formatShort import com.github.libretube.util.setWatchProgressLength import com.github.libretube.util.toID import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -import java.io.IOException class SearchAdapter( private val searchItems: MutableList, @@ -128,80 +125,41 @@ class SearchAdapter( NavigationHelper.navigateChannel(root.context, item.url) } val channelId = item.url.toID() - val token = PreferenceHelper.getToken() - // only show subscribe button if logged in - if (token != "") isSubscribed(channelId, token, binding) + isSubscribed(channelId, binding) } } - private fun isSubscribed(channelId: String, token: String, binding: ChannelRowBinding) { - var isSubscribed = false - + private fun isSubscribed(channelId: String, binding: ChannelRowBinding) { // check whether the user subscribed to the channel CoroutineScope(Dispatchers.Main).launch { - val response = try { - RetrofitInstance.authApi.isSubscribed( - channelId, - token - ) - } catch (e: Exception) { - return@launch - } + var isSubscribed = SubscriptionHelper.isSubscribed(channelId) // if subscribed change text to unsubscribe - if (response.subscribed == true) { - isSubscribed = true + if (isSubscribed == true) { binding.searchSubButton.text = binding.root.context.getString(R.string.unsubscribe) } // make sub button visible and set the on click listeners to (un)subscribe - if (response.subscribed != null) { - binding.searchSubButton.visibility = View.VISIBLE + if (isSubscribed == null) return@launch + binding.searchSubButton.visibility = View.VISIBLE - binding.searchSubButton.setOnClickListener { - if (!isSubscribed) { - subscribe(token, channelId) - binding.searchSubButton.text = - binding.root.context.getString(R.string.unsubscribe) - isSubscribed = true - } else { - unsubscribe(token, channelId) - binding.searchSubButton.text = - binding.root.context.getString(R.string.subscribe) - isSubscribed = false - } + binding.searchSubButton.setOnClickListener { + if (isSubscribed == false) { + SubscriptionHelper.subscribe(channelId) + 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 } } } } - private fun subscribe(token: String, channelId: String) { - CoroutineScope(Dispatchers.IO).launch { - try { - RetrofitInstance.authApi.subscribe( - token, - Subscribe(channelId) - ) - } catch (e: Exception) { - return@launch - } - } - } - - private fun unsubscribe(token: String, channelId: String) { - CoroutineScope(Dispatchers.IO).launch { - try { - RetrofitInstance.authApi.unsubscribe( - token, - Subscribe(channelId) - ) - } catch (e: IOException) { - return@launch - } - } - } - private fun bindPlaylist(item: SearchItem, binding: PlaylistSearchRowBinding) { binding.apply { ConnectionHelper.loadImage(item.thumbnail, searchThumbnail) diff --git a/app/src/main/java/com/github/libretube/adapters/SubscriptionChannelAdapter.kt b/app/src/main/java/com/github/libretube/adapters/SubscriptionChannelAdapter.kt index 7e33c0c35..9d4af078b 100644 --- a/app/src/main/java/com/github/libretube/adapters/SubscriptionChannelAdapter.kt +++ b/app/src/main/java/com/github/libretube/adapters/SubscriptionChannelAdapter.kt @@ -1,21 +1,15 @@ package com.github.libretube.adapters -import android.util.Log import android.view.LayoutInflater import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import com.github.libretube.R import com.github.libretube.databinding.ChannelSubscriptionRowBinding -import com.github.libretube.obj.Subscribe import com.github.libretube.obj.Subscription -import com.github.libretube.preferences.PreferenceHelper import com.github.libretube.util.ConnectionHelper import com.github.libretube.util.NavigationHelper -import com.github.libretube.util.RetrofitInstance +import com.github.libretube.util.SubscriptionHelper import com.github.libretube.util.toID -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch class SubscriptionChannelAdapter(private val subscriptions: MutableList) : RecyclerView.Adapter() { @@ -46,51 +40,17 @@ class SubscriptionChannelAdapter(private val subscriptions: MutableList Unit) { this ?: return if (!isAdded) return // Fragment not attached to an Activity diff --git a/app/src/main/java/com/github/libretube/fragments/SubscriptionsFragment.kt b/app/src/main/java/com/github/libretube/fragments/SubscriptionsFragment.kt index 573657c66..4d1400cbc 100644 --- a/app/src/main/java/com/github/libretube/fragments/SubscriptionsFragment.kt +++ b/app/src/main/java/com/github/libretube/fragments/SubscriptionsFragment.kt @@ -19,6 +19,7 @@ import com.github.libretube.obj.StreamItem import com.github.libretube.preferences.PreferenceHelper import com.github.libretube.preferences.PreferenceKeys import com.github.libretube.util.RetrofitInstance +import com.github.libretube.util.SubscriptionHelper import com.github.libretube.util.toID import com.google.android.material.dialog.MaterialAlertDialogBuilder import retrofit2.HttpException @@ -53,63 +54,57 @@ class SubscriptionsFragment : Fragment() { super.onViewCreated(view, savedInstanceState) token = PreferenceHelper.getToken() - if (token != "") { - binding.loginOrRegister.visibility = View.GONE - binding.subRefresh.isEnabled = true + binding.subRefresh.isEnabled = true - binding.subProgress.visibility = View.VISIBLE + binding.subProgress.visibility = View.VISIBLE - val grid = PreferenceHelper.getString( - PreferenceKeys.GRID_COLUMNS, - resources.getInteger(R.integer.grid_items).toString() - ) - binding.subFeed.layoutManager = GridLayoutManager(view.context, grid.toInt()) + val grid = PreferenceHelper.getString( + PreferenceKeys.GRID_COLUMNS, + resources.getInteger(R.integer.grid_items).toString() + ) + binding.subFeed.layoutManager = GridLayoutManager(view.context, grid.toInt()) + fetchFeed() + + binding.subRefresh.setOnRefreshListener { + fetchChannels() fetchFeed() - - binding.subRefresh.setOnRefreshListener { - fetchChannels() - fetchFeed() - } - - binding.sortTV.setOnClickListener { - showSortDialog() - } - - binding.toggleSubs.visibility = View.VISIBLE - var loadedSubbedChannels = false - - binding.toggleSubs.setOnClickListener { - if (!binding.subChannelsContainer.isVisible) { - if (!loadedSubbedChannels) { - binding.subChannels.layoutManager = LinearLayoutManager(context) - fetchChannels() - loadedSubbedChannels = true - } - binding.subChannelsContainer.visibility = View.VISIBLE - binding.subFeedContainer.visibility = View.GONE - } else { - binding.subChannelsContainer.visibility = View.GONE - binding.subFeedContainer.visibility = View.VISIBLE - } - } - - binding.scrollviewSub.viewTreeObserver - .addOnScrollChangedListener { - if (binding.scrollviewSub.getChildAt(0).bottom - == (binding.scrollviewSub.height + binding.scrollviewSub.scrollY) - ) { - // scroll view is at bottom - if (isLoaded) { - binding.subRefresh.isRefreshing = true - subscriptionAdapter?.updateItems() - binding.subRefresh.isRefreshing = false - } - } - } - } else { - binding.subRefresh.isEnabled = false - binding.subFeedContainer.visibility = View.GONE } + + binding.sortTV.setOnClickListener { + showSortDialog() + } + + binding.toggleSubs.visibility = View.VISIBLE + var loadedSubbedChannels = false + + binding.toggleSubs.setOnClickListener { + if (!binding.subChannelsContainer.isVisible) { + if (!loadedSubbedChannels) { + binding.subChannels.layoutManager = LinearLayoutManager(context) + fetchChannels() + loadedSubbedChannels = true + } + binding.subChannelsContainer.visibility = View.VISIBLE + binding.subFeedContainer.visibility = View.GONE + } else { + binding.subChannelsContainer.visibility = View.GONE + binding.subFeedContainer.visibility = View.VISIBLE + } + } + + binding.scrollviewSub.viewTreeObserver + .addOnScrollChangedListener { + if (binding.scrollviewSub.getChildAt(0).bottom + == (binding.scrollviewSub.height + binding.scrollviewSub.scrollY) + ) { + // scroll view is at bottom + if (isLoaded) { + binding.subRefresh.isRefreshing = true + subscriptionAdapter?.updateItems() + binding.subRefresh.isRefreshing = false + } + } + } } private fun showSortDialog() { @@ -130,7 +125,10 @@ class SubscriptionsFragment : Fragment() { fun run() { lifecycleScope.launchWhenCreated { feed = try { - RetrofitInstance.authApi.getFeed(token) + if (token != "") RetrofitInstance.authApi.getFeed(token) + else RetrofitInstance.authApi.getUnauthenticatedFeed( + SubscriptionHelper.getFormattedLocalSubscriptions() + ) } catch (e: IOException) { Log.e(TAG, e.toString()) Log.e(TAG, "IOException, you might not have internet connection") @@ -148,15 +146,7 @@ class SubscriptionsFragment : Fragment() { showFeed() } else { runOnUiThread { - with(binding.boogh) { - visibility = View.VISIBLE - setImageResource(R.drawable.ic_list) - } - with(binding.textLike) { - visibility = View.VISIBLE - text = getString(R.string.emptyList) - } - binding.loginOrRegister.visibility = View.VISIBLE + binding.emptyFeed.visibility = View.VISIBLE } } binding.subProgress.visibility = View.GONE @@ -185,7 +175,10 @@ class SubscriptionsFragment : Fragment() { fun run() { lifecycleScope.launchWhenCreated { val response = try { - RetrofitInstance.authApi.subscriptions(token) + if (token != "") RetrofitInstance.authApi.subscriptions(token) + else RetrofitInstance.authApi.unauthenticatedSubscriptions( + SubscriptionHelper.getFormattedLocalSubscriptions() + ) } catch (e: IOException) { Log.e(TAG, e.toString()) Log.e(TAG, "IOException, you might not have internet connection") diff --git a/app/src/main/java/com/github/libretube/preferences/PreferenceHelper.kt b/app/src/main/java/com/github/libretube/preferences/PreferenceHelper.kt index 00e4800f0..4403eba5a 100644 --- a/app/src/main/java/com/github/libretube/preferences/PreferenceHelper.kt +++ b/app/src/main/java/com/github/libretube/preferences/PreferenceHelper.kt @@ -235,6 +235,21 @@ object PreferenceHelper { return getString(PreferenceKeys.ERROR_LOG, "") } + fun getLocalSubscriptions(): List { + val json = settings.getString(PreferenceKeys.LOCAL_SUBSCRIPTIONS, "") + return try { + val type = object : TypeReference>() {} + mapper.readValue(json, type) + } catch (e: Exception) { + listOf() + } + } + + fun setLocalSubscriptions(channels: List) { + val json = mapper.writeValueAsString(channels) + editor.putString(PreferenceKeys.LOCAL_SUBSCRIPTIONS, json).commit() + } + private fun getDefaultSharedPreferences(context: Context): SharedPreferences { return PreferenceManager.getDefaultSharedPreferences(context) } diff --git a/app/src/main/java/com/github/libretube/preferences/PreferenceKeys.kt b/app/src/main/java/com/github/libretube/preferences/PreferenceKeys.kt index 820172302..f136d6f96 100644 --- a/app/src/main/java/com/github/libretube/preferences/PreferenceKeys.kt +++ b/app/src/main/java/com/github/libretube/preferences/PreferenceKeys.kt @@ -61,7 +61,6 @@ object PreferenceKeys { /** * Download */ - const val DOWNLOAD_VIDEO_FORMAT = "video_format" const val DOWNLOAD_LOCATION = "download_location" const val DOWNLOAD_FOLDER = "download_folder" @@ -86,4 +85,9 @@ object PreferenceKeys { * Error logs */ const val ERROR_LOG = "error_log" + + /** + * Data + */ + const val LOCAL_SUBSCRIPTIONS = "local_subscriptions" } diff --git a/app/src/main/java/com/github/libretube/util/PipedApi.kt b/app/src/main/java/com/github/libretube/util/PipedApi.kt index 394da668e..36fc4902b 100644 --- a/app/src/main/java/com/github/libretube/util/PipedApi.kt +++ b/app/src/main/java/com/github/libretube/util/PipedApi.kt @@ -99,6 +99,9 @@ interface PipedApi { @GET("feed") suspend fun getFeed(@Query("authToken") token: String?): List + @GET("feed/unauthenticated") + suspend fun getUnauthenticatedFeed(@Query("channels") channels: String): List + @GET("subscribed") suspend fun isSubscribed( @Query("channelId") channelId: String, @@ -108,6 +111,9 @@ interface PipedApi { @GET("subscriptions") suspend fun subscriptions(@Header("Authorization") token: String): List + @GET("subscriptions/unauthenticated") + suspend fun unauthenticatedSubscriptions(@Query("channels") channels: String): List + @POST("subscribe") suspend fun subscribe( @Header("Authorization") token: String, diff --git a/app/src/main/java/com/github/libretube/util/SubscriptionHelper.kt b/app/src/main/java/com/github/libretube/util/SubscriptionHelper.kt new file mode 100644 index 000000000..19511413f --- /dev/null +++ b/app/src/main/java/com/github/libretube/util/SubscriptionHelper.kt @@ -0,0 +1,71 @@ +package com.github.libretube.util + +import android.util.Log +import com.github.libretube.obj.Subscribe +import com.github.libretube.preferences.PreferenceHelper +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch + +object SubscriptionHelper { + val TAG = "SubscriptionHelper" + + fun subscribe(channelId: String) { + if (PreferenceHelper.getToken() != "") { + CoroutineScope(Dispatchers.IO).launch { + try { + RetrofitInstance.authApi.subscribe( + PreferenceHelper.getToken(), + Subscribe(channelId) + ) + } catch (e: Exception) { + Log.e(TAG, e.toString()) + } + } + } else { + val channels = PreferenceHelper.getLocalSubscriptions().toMutableList() + channels.add(channelId) + PreferenceHelper.setLocalSubscriptions(channels) + } + } + + fun unsubscribe(channelId: String) { + if (PreferenceHelper.getToken() != "") { + CoroutineScope(Dispatchers.IO).launch { + try { + RetrofitInstance.authApi.unsubscribe( + PreferenceHelper.getToken(), + Subscribe(channelId) + ) + } catch (e: Exception) { + Log.e(TAG, e.toString()) + } + } + } else { + val channels = PreferenceHelper.getLocalSubscriptions().toMutableList() + channels.remove(channelId) + PreferenceHelper.setLocalSubscriptions(channels) + } + } + + suspend fun isSubscribed(channelId: String): Boolean? { + if (PreferenceHelper.getToken() != "") { + val isSubscribed = try { + RetrofitInstance.authApi.isSubscribed( + channelId, + PreferenceHelper.getToken() + ) + } catch (e: Exception) { + Log.e(TAG, e.toString()) + return null + } + return isSubscribed.subscribed + } else { + return PreferenceHelper.getLocalSubscriptions().contains(channelId) + } + } + + fun getFormattedLocalSubscriptions(): String { + return PreferenceHelper.getLocalSubscriptions().joinToString(",") + } +} diff --git a/app/src/main/res/layout/fragment_subscriptions.xml b/app/src/main/res/layout/fragment_subscriptions.xml index 5812ff1be..6e27f08f0 100644 --- a/app/src/main/res/layout/fragment_subscriptions.xml +++ b/app/src/main/res/layout/fragment_subscriptions.xml @@ -15,10 +15,11 @@ android:visibility="gone" /> + android:layout_centerInParent="true" + android:visibility="gone"> + android:src="@drawable/ic_list" />