UI for channel tabs

This commit is contained in:
Bnyro 2022-10-29 12:06:25 +02:00
parent 36e2da52fb
commit 18eebe663b
4 changed files with 130 additions and 10 deletions

View File

@ -6,11 +6,13 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.TextView import android.widget.TextView
import androidx.core.view.children
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.github.libretube.R import com.github.libretube.R
import com.github.libretube.api.RetrofitInstance import com.github.libretube.api.RetrofitInstance
import com.github.libretube.api.SubscriptionHelper import com.github.libretube.api.SubscriptionHelper
import com.github.libretube.api.obj.ChannelTab
import com.github.libretube.constants.IntentData import com.github.libretube.constants.IntentData
import com.github.libretube.constants.ShareObjectType import com.github.libretube.constants.ShareObjectType
import com.github.libretube.databinding.FragmentChannelBinding import com.github.libretube.databinding.FragmentChannelBinding
@ -18,9 +20,14 @@ import com.github.libretube.extensions.TAG
import com.github.libretube.extensions.formatShort import com.github.libretube.extensions.formatShort
import com.github.libretube.extensions.toID import com.github.libretube.extensions.toID
import com.github.libretube.ui.adapters.ChannelAdapter import com.github.libretube.ui.adapters.ChannelAdapter
import com.github.libretube.ui.adapters.SearchAdapter
import com.github.libretube.ui.base.BaseFragment import com.github.libretube.ui.base.BaseFragment
import com.github.libretube.ui.dialogs.ShareDialog import com.github.libretube.ui.dialogs.ShareDialog
import com.github.libretube.util.ImageHelper import com.github.libretube.util.ImageHelper
import com.google.android.material.chip.Chip
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import retrofit2.HttpException import retrofit2.HttpException
import java.io.IOException import java.io.IOException
@ -35,6 +42,10 @@ class ChannelFragment : BaseFragment() {
private var isLoading = true private var isLoading = true
private var isSubscribed: Boolean? = false private var isSubscribed: Boolean? = false
private var onScrollEnd: () -> Unit = {}
val scope = CoroutineScope(Dispatchers.IO)
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
arguments?.let { arguments?.let {
@ -73,11 +84,10 @@ class ChannelFragment : BaseFragment() {
if (binding.channelScrollView.getChildAt(0).bottom if (binding.channelScrollView.getChildAt(0).bottom
== (binding.channelScrollView.height + binding.channelScrollView.scrollY) == (binding.channelScrollView.height + binding.channelScrollView.scrollY)
) { ) {
// scroll view is at bottom try {
if (nextPage != null && !isLoading) { onScrollEnd.invoke()
isLoading = true } catch (e: Exception) {
binding.channelRefresh.isRefreshing = true Log.e("tabs failed", e.toString())
fetchChannelNextPage()
} }
} }
} }
@ -103,6 +113,14 @@ class ChannelFragment : BaseFragment() {
// needed if the channel gets loaded by the ID // needed if the channel gets loaded by the ID
channelId = response.id channelId = response.id
onScrollEnd = {
if (nextPage != null && !isLoading) {
isLoading = true
binding.channelRefresh.isRefreshing = true
fetchChannelNextPage()
}
}
// fetch and update the subscription status // fetch and update the subscription status
isSubscribed = SubscriptionHelper.isSubscribed(channelId!!) isSubscribed = SubscriptionHelper.isSubscribed(channelId!!)
if (isSubscribed == null) return@launchWhenCreated if (isSubscribed == null) return@launchWhenCreated
@ -166,17 +184,68 @@ class ChannelFragment : BaseFragment() {
// recyclerview of the videos by the channel // recyclerview of the videos by the channel
channelAdapter = ChannelAdapter( channelAdapter = ChannelAdapter(
response.relatedStreams!!.toMutableList(), response.relatedStreams.orEmpty().toMutableList(),
childFragmentManager childFragmentManager
) )
binding.channelRecView.adapter = channelAdapter binding.channelRecView.adapter = channelAdapter
} }
response.tabs?.forEach { binding.videos.setOnClickListener {
try { binding.channelRecView.adapter = channelAdapter
RetrofitInstance.api.getChannelTab(it.data!!).toString() }
response.tabs?.firstOrNull { it.name == "Playlists" }?.let {
setupTab(binding.playlists, it)
}
response.tabs?.firstOrNull { it.name == "Channels" }?.let {
setupTab(binding.channels, it)
}
response.tabs?.firstOrNull { it.name == "Livestreams" }?.let {
setupTab(binding.livestreams, it)
}
response.tabs?.firstOrNull { it.name == "Shorts" }?.let {
setupTab(binding.shorts, it)
}
}
}
private fun setupTab(chip: Chip, tab: ChannelTab) {
chip.visibility = View.VISIBLE
chip.setOnClickListener {
binding.tabChips.children.forEach {
if (it != chip) it.isSelected = false
}
scope.launch {
val response = try {
RetrofitInstance.api.getChannelTab(tab.data!!)
} catch (e: Exception) { } catch (e: Exception) {
Log.e("error", e.toString()) return@launch
}
val adapter = SearchAdapter(
response.content.toMutableList(),
childFragmentManager
)
runOnUiThread {
binding.channelRecView.adapter = adapter
}
onScrollEnd = {
if (response.nextpage != null) {
scope.launch {
val newContent = try {
RetrofitInstance.api.getChannelTab(tab.data, response.nextpage)
} catch (e: Exception) {
e.printStackTrace()
null
}
newContent?.content?.let { adapter.updateItems(it) }
}
}
} }
} }
} }

View File

@ -115,6 +115,47 @@
android:maxLines="2" android:maxLines="2"
android:padding="10dp" /> android:padding="10dp" />
<HorizontalScrollView
android:id="@+id/tab_chips"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingHorizontal="10dp"
android:scrollbars="none">
<com.google.android.material.chip.ChipGroup
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.google.android.material.chip.Chip
android:id="@+id/videos"
style="@style/channelChip"
android:text="@string/videos"
android:visibility="visible" />
<com.google.android.material.chip.Chip
android:id="@+id/playlists"
style="@style/channelChip"
android:text="@string/playlists" />
<com.google.android.material.chip.Chip
android:id="@+id/shorts"
style="@style/channelChip"
android:text="@string/yt_shorts" />
<com.google.android.material.chip.Chip
android:id="@+id/channels"
style="@style/channelChip"
android:text="@string/channels" />
<com.google.android.material.chip.Chip
android:id="@+id/livestreams"
style="@style/channelChip"
android:text="@string/livestreams" />
</com.google.android.material.chip.ChipGroup>
</HorizontalScrollView>
<RelativeLayout <RelativeLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"

View File

@ -352,6 +352,7 @@
<string name="queue">Queue</string> <string name="queue">Queue</string>
<string name="sb_markers">Markers</string> <string name="sb_markers">Markers</string>
<string name="sb_markers_summary">Mark the segments on the time bar.</string> <string name="sb_markers_summary">Mark the segments on the time bar.</string>
<string name="livestreams">Livestreams</string>
<!-- Notification channel strings --> <!-- Notification channel strings -->
<string name="download_channel_name">Download Service</string> <string name="download_channel_name">Download Service</string>

View File

@ -179,4 +179,13 @@
<item name="animationMode">slide</item> <item name="animationMode">slide</item>
</style> </style>
<style name="channelChip" parent="@style/Widget.Material3.Chip.Filter.Elevated">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:padding">10dp</item>
<item name="android:visibility">gone</item>
</style>
</resources> </resources>