mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2025-04-20 03:24:50 +00:00
finished UI and interactions
Changelog: added
This commit is contained in:
parent
76103a2a8c
commit
bd87a47551
18 changed files with 1953 additions and 302 deletions
|
@ -160,6 +160,9 @@ android {
|
|||
dependencies {
|
||||
implementation 'com.google.dagger:dagger:2.48'
|
||||
implementation 'androidx.test:monitor:1.7.2'
|
||||
implementation 'androidx.compose.material:material-icons-extended:1.7.8'
|
||||
implementation 'com.github.bumptech.glide:compose:1.0.0-beta01'
|
||||
implementation 'androidx.constraintlayout:constraintlayout-compose:1.1.1'
|
||||
annotationProcessor 'com.google.dagger:dagger-compiler:2.48'
|
||||
|
||||
//Core
|
||||
|
|
|
@ -743,6 +743,7 @@ let plugin = {
|
|||
//To override by plugin
|
||||
const source = {
|
||||
getHome() { return new ContentPager([], false, {}); },
|
||||
getShorts() { return new VideoPager([], false, {}); },
|
||||
|
||||
enable(config){ },
|
||||
disable() {},
|
||||
|
|
|
@ -12,6 +12,7 @@ import com.futo.platformplayer.api.media.models.live.IPlatformLiveEvent
|
|||
import com.futo.platformplayer.api.media.models.playback.IPlaybackTracker
|
||||
import com.futo.platformplayer.api.media.models.playlists.IPlatformPlaylist
|
||||
import com.futo.platformplayer.api.media.models.playlists.IPlatformPlaylistDetails
|
||||
import com.futo.platformplayer.api.media.models.video.IPlatformVideo
|
||||
import com.futo.platformplayer.api.media.structures.IPager
|
||||
import com.futo.platformplayer.models.ImageVariable
|
||||
|
||||
|
@ -35,6 +36,11 @@ interface IPlatformClient {
|
|||
*/
|
||||
fun getHome(): IPager<IPlatformContent>
|
||||
|
||||
/**
|
||||
* Gets the shorts feed
|
||||
*/
|
||||
fun getShorts(): IPager<IPlatformVideo>
|
||||
|
||||
//Search
|
||||
/**
|
||||
* Gets search suggestion for the provided query string
|
||||
|
|
|
@ -22,6 +22,7 @@ import com.futo.platformplayer.api.media.models.live.IPlatformLiveEvent
|
|||
import com.futo.platformplayer.api.media.models.playback.IPlaybackTracker
|
||||
import com.futo.platformplayer.api.media.models.playlists.IPlatformPlaylist
|
||||
import com.futo.platformplayer.api.media.models.playlists.IPlatformPlaylistDetails
|
||||
import com.futo.platformplayer.api.media.models.video.IPlatformVideo
|
||||
import com.futo.platformplayer.api.media.platforms.js.internal.JSCallDocs
|
||||
import com.futo.platformplayer.api.media.platforms.js.internal.JSDocs
|
||||
import com.futo.platformplayer.api.media.platforms.js.internal.JSDocsParameter
|
||||
|
@ -41,6 +42,7 @@ import com.futo.platformplayer.api.media.platforms.js.models.JSLiveEventPager
|
|||
import com.futo.platformplayer.api.media.platforms.js.models.JSPlaybackTracker
|
||||
import com.futo.platformplayer.api.media.platforms.js.models.JSPlaylistDetails
|
||||
import com.futo.platformplayer.api.media.platforms.js.models.JSPlaylistPager
|
||||
import com.futo.platformplayer.api.media.platforms.js.models.JSVideoPager
|
||||
import com.futo.platformplayer.api.media.structures.EmptyPager
|
||||
import com.futo.platformplayer.api.media.structures.IPager
|
||||
import com.futo.platformplayer.constructs.Event1
|
||||
|
@ -116,6 +118,7 @@ open class JSClient : IPlatformClient {
|
|||
|
||||
val enableInSearch get() = descriptor.appSettings.tabEnabled.enableSearch ?: true
|
||||
val enableInHome get() = descriptor.appSettings.tabEnabled.enableHome ?: true
|
||||
val enableInShorts get() = descriptor.appSettings.tabEnabled.enableShorts ?: true
|
||||
|
||||
fun getSubscriptionRateLimit(): Int? {
|
||||
val pluginRateLimit = config.subscriptionRateLimit;
|
||||
|
@ -288,6 +291,13 @@ open class JSClient : IPlatformClient {
|
|||
plugin.executeTyped("source.getHome()"));
|
||||
}
|
||||
|
||||
@JSDocs(2, "source.getShorts()", "Gets the Shorts feed of the platform")
|
||||
override fun getShorts(): IPager<IPlatformVideo> = isBusyWith("getShorts") {
|
||||
ensureEnabled()
|
||||
return@isBusyWith JSVideoPager(config, this,
|
||||
plugin.executeTyped("source.getShorts()"))
|
||||
}
|
||||
|
||||
@JSDocs(3, "source.searchSuggestions(query)", "Gets search suggestions for a given query")
|
||||
@JSDocsParameter("query", "Query to complete suggestions for")
|
||||
override fun searchSuggestions(query: String): Array<String> = isBusyWith("searchSuggestions") {
|
||||
|
|
|
@ -47,6 +47,7 @@ class SourcePluginConfig(
|
|||
var subscriptionRateLimit: Int? = null,
|
||||
var enableInSearch: Boolean = true,
|
||||
var enableInHome: Boolean = true,
|
||||
var enableInShorts: Boolean = true,
|
||||
var supportedClaimTypes: List<Int> = listOf(),
|
||||
var primaryClaimFieldType: Int? = null,
|
||||
var developerSubmitUrl: String? = null,
|
||||
|
|
|
@ -103,9 +103,11 @@ class SourcePluginDescriptor {
|
|||
@FormField(R.string.home, FieldForm.TOGGLE, R.string.show_content_in_home_tab, 1)
|
||||
var enableHome: Boolean? = null;
|
||||
|
||||
|
||||
@FormField(R.string.search, FieldForm.TOGGLE, R.string.show_content_in_search_results, 2)
|
||||
var enableSearch: Boolean? = null;
|
||||
|
||||
@FormField(R.string.shorts, FieldForm.TOGGLE, R.string.show_content_in_shorts_tab, 3)
|
||||
var enableShorts: Boolean? = null;
|
||||
}
|
||||
|
||||
@FormField(R.string.ratelimit, "group", R.string.ratelimit_description, 3)
|
||||
|
@ -143,6 +145,8 @@ class SourcePluginDescriptor {
|
|||
tabEnabled.enableHome = config.enableInHome
|
||||
if(tabEnabled.enableSearch == null)
|
||||
tabEnabled.enableSearch = config.enableInSearch
|
||||
if(tabEnabled.enableShorts == null)
|
||||
tabEnabled.enableShorts = config.enableInShorts
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,12 +7,12 @@ import java.util.stream.IntStream
|
|||
* A Content MultiPager that returns results based on a specified distribution
|
||||
* TODO: Merge all basic distribution pagers
|
||||
*/
|
||||
class MultiDistributionContentPager : MultiPager<IPlatformContent> {
|
||||
class MultiDistributionContentPager<T : IPlatformContent> : MultiPager<T> {
|
||||
|
||||
private val dist : HashMap<IPager<IPlatformContent>, Float>;
|
||||
private val distConsumed : HashMap<IPager<IPlatformContent>, Float>;
|
||||
private val dist : HashMap<IPager<T>, Float>;
|
||||
private val distConsumed : HashMap<IPager<T>, Float>;
|
||||
|
||||
constructor(pagers : Map<IPager<IPlatformContent>, Float>) : super(pagers.keys.toMutableList()) {
|
||||
constructor(pagers : Map<IPager<T>, Float>) : super(pagers.keys.toMutableList()) {
|
||||
val distTotal = pagers.values.sum();
|
||||
dist = HashMap();
|
||||
|
||||
|
@ -25,7 +25,7 @@ class MultiDistributionContentPager : MultiPager<IPlatformContent> {
|
|||
}
|
||||
|
||||
@Synchronized
|
||||
override fun selectItemIndex(options: Array<SelectionOption<IPlatformContent>>): Int {
|
||||
override fun selectItemIndex(options: Array<SelectionOption<T>>): Int {
|
||||
if(options.size == 0)
|
||||
return -1;
|
||||
var bestIndex = 0;
|
||||
|
@ -42,6 +42,4 @@ class MultiDistributionContentPager : MultiPager<IPlatformContent> {
|
|||
distConsumed[options[bestIndex].pager.getPager()] = bestConsumed;
|
||||
return bestIndex;
|
||||
}
|
||||
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,15 +1,30 @@
|
|||
package com.futo.platformplayer.fragment.mainactivity.main
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.graphics.drawable.Animatable
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.ImageView
|
||||
import androidx.annotation.OptIn
|
||||
import androidx.core.view.get
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewpager2.widget.ViewPager2
|
||||
import com.futo.platformplayer.R
|
||||
import com.futo.platformplayer.api.media.models.video.IPlatformVideo
|
||||
import com.futo.platformplayer.api.media.structures.IPager
|
||||
import com.futo.platformplayer.constructs.Event0
|
||||
import com.futo.platformplayer.states.StatePlatform
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlin.coroutines.cancellation.CancellationException
|
||||
|
||||
@UnstableApi
|
||||
class ShortsFragment : MainFragment() {
|
||||
|
@ -17,14 +32,25 @@ class ShortsFragment : MainFragment() {
|
|||
override val isTab: Boolean = true
|
||||
override val hasBottomBar: Boolean get() = true
|
||||
|
||||
private var previousShownView: ShortView? = null
|
||||
private var loadPagerJob: Job? = null
|
||||
private var nextPageJob: Job? = null
|
||||
|
||||
private lateinit var viewPager: ViewPager2
|
||||
private var shortsPager: IPager<IPlatformVideo>? = null
|
||||
private val videos: MutableList<IPlatformVideo> = mutableListOf()
|
||||
|
||||
private var viewPager: ViewPager2? = null
|
||||
private lateinit var overlayLoading: FrameLayout
|
||||
private lateinit var overlayLoadingSpinner: ImageView
|
||||
private lateinit var overlayQualityContainer: FrameLayout
|
||||
private lateinit var customViewAdapter: CustomViewAdapter
|
||||
private val urls = listOf(
|
||||
"https://youtube.com/shorts/fHU6dfPHT-o?si=TVCYnt_mvAxWYACZ", "https://youtube.com/shorts/j9LQ0c4MyGk?si=FVlr90UD42y1ZIO0", "https://youtube.com/shorts/Q8LndW9YZvQ?si=mDrSsm-3Uq7IEXAT", "https://youtube.com/shorts/OIS5qHDOOzs?si=RGYeaAH9M-TRuZSr", "https://youtube.com/shorts/1Cp6EbLWVnI?si=N4QqytC48CTnfJra", "https://youtube.com/shorts/fHU6dfPHT-o?si=TVCYnt_mvAxWYACZ", "https://youtube.com/shorts/j9LQ0c4MyGk?si=FVlr90UD42y1ZIO0", "https://youtube.com/shorts/Q8LndW9YZvQ?si=mDrSsm-3Uq7IEXAT", "https://youtube.com/shorts/OIS5qHDOOzs?si=RGYeaAH9M-TRuZSr", "https://youtube.com/shorts/1Cp6EbLWVnI?si=N4QqytC48CTnfJra"
|
||||
"https://youtube.com/shorts/fHU6dfPHT-o?si=TVCYnt_mvAxWYACZ", "https://youtube.com/shorts/j9LQ0c4MyGk?si=FVlr90UD42y1ZIO0", "https://youtube.com/shorts/Q8LndW9YZvQ?si=mDrSsm-3Uq7IEXAT", "https://www.youtube.com/watch?v=MXHSS-7XcBc", "https://youtube.com/shorts/OIS5qHDOOzs?si=RGYeaAH9M-TRuZSr", "https://youtube.com/shorts/1Cp6EbLWVnI?si=N4QqytC48CTnfJra", "https://youtube.com/shorts/fHU6dfPHT-o?si=TVCYnt_mvAxWYACZ", "https://youtube.com/shorts/j9LQ0c4MyGk?si=FVlr90UD42y1ZIO0", "https://youtube.com/shorts/Q8LndW9YZvQ?si=mDrSsm-3Uq7IEXAT", "https://youtube.com/shorts/OIS5qHDOOzs?si=RGYeaAH9M-TRuZSr", "https://youtube.com/shorts/1Cp6EbLWVnI?si=N4QqytC48CTnfJra"
|
||||
)
|
||||
|
||||
init {
|
||||
loadPager()
|
||||
}
|
||||
|
||||
override fun onCreateMainView(
|
||||
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
|
||||
): View {
|
||||
|
@ -35,31 +61,146 @@ class ShortsFragment : MainFragment() {
|
|||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
viewPager = view.findViewById(R.id.viewPager)
|
||||
overlayLoading = view.findViewById(R.id.short_view_loading_overlay)
|
||||
overlayLoadingSpinner = view.findViewById(R.id.short_view_loader)
|
||||
overlayQualityContainer = view.findViewById(R.id.videodetail_quality_overview)
|
||||
|
||||
customViewAdapter = CustomViewAdapter(urls, layoutInflater, this)
|
||||
viewPager.adapter = customViewAdapter
|
||||
setLoading(true)
|
||||
|
||||
// TODO something is laggy sometimes when swiping between videos
|
||||
viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
|
||||
@OptIn(UnstableApi::class)
|
||||
override fun onPageSelected(position: Int) {
|
||||
previousShownView?.stop()
|
||||
if (loadPagerJob?.isActive == false && videos.isEmpty()) {
|
||||
loadPager()
|
||||
}
|
||||
|
||||
val focusedView =
|
||||
((viewPager[0] as RecyclerView).findViewHolderForAdapterPosition(position) as CustomViewHolder).shortView
|
||||
focusedView.play()
|
||||
loadPagerJob!!.invokeOnCompletion {
|
||||
customViewAdapter = CustomViewAdapter(videos, layoutInflater, this@ShortsFragment, overlayQualityContainer) {
|
||||
if (!shortsPager!!.hasMorePages()) {
|
||||
return@CustomViewAdapter
|
||||
}
|
||||
nextPage()
|
||||
}
|
||||
customViewAdapter.onResetTriggered.subscribe {
|
||||
setLoading(true)
|
||||
loadPager()
|
||||
loadPagerJob!!.invokeOnCompletion {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
val viewPager = viewPager!!
|
||||
viewPager.adapter = customViewAdapter
|
||||
|
||||
// TODO something is laggy sometimes when swiping between videos
|
||||
viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
|
||||
@OptIn(UnstableApi::class)
|
||||
override fun onPageSelected(position: Int) {
|
||||
val adapter = (viewPager.adapter as CustomViewAdapter)
|
||||
adapter.previousShownView?.stop()
|
||||
adapter.previousShownView = null
|
||||
|
||||
// viewPager.post {
|
||||
val recycler = (viewPager.getChildAt(0) as RecyclerView)
|
||||
val viewHolder =
|
||||
recycler.findViewHolderForAdapterPosition(position) as CustomViewHolder?
|
||||
|
||||
if (viewHolder == null) {
|
||||
adapter.needToPlay = position
|
||||
} else {
|
||||
val focusedView = viewHolder.shortView
|
||||
focusedView.play()
|
||||
adapter.previousShownView = focusedView
|
||||
}
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
previousShownView = focusedView
|
||||
})
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
private fun nextPage() {
|
||||
nextPageJob?.cancel()
|
||||
|
||||
nextPageJob = CoroutineScope(Dispatchers.Main).launch {
|
||||
try {
|
||||
withContext(Dispatchers.IO) {
|
||||
shortsPager!!.nextPage()
|
||||
}
|
||||
} catch (_: CancellationException) {
|
||||
return@launch
|
||||
}
|
||||
|
||||
})
|
||||
// if it's been canceled then don't update the results
|
||||
if (!isActive) {
|
||||
return@launch
|
||||
}
|
||||
|
||||
val newVideos = shortsPager!!.getResults()
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
val prevCount = customViewAdapter.itemCount
|
||||
videos.addAll(newVideos)
|
||||
customViewAdapter.notifyItemRangeInserted(prevCount, newVideos.size)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we just completely reset the data structure so we want to tell the adapter that
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
private fun loadPager() {
|
||||
loadPagerJob?.cancel()
|
||||
|
||||
// if the view pager exists go back to the beginning
|
||||
videos.clear()
|
||||
viewPager?.adapter?.notifyDataSetChanged()
|
||||
viewPager?.currentItem = 0
|
||||
|
||||
loadPagerJob = CoroutineScope(Dispatchers.Main).launch {
|
||||
// delay(5000)
|
||||
val pager = try {
|
||||
withContext(Dispatchers.IO) {
|
||||
StatePlatform.instance.getShorts()
|
||||
// StatePlatform.instance.getHome()
|
||||
// as IPager<IPlatformVideo>
|
||||
}
|
||||
} catch (_: CancellationException) {
|
||||
return@launch
|
||||
}
|
||||
|
||||
// if it's been canceled then don't set the video pager
|
||||
if (!isActive) {
|
||||
return@launch
|
||||
}
|
||||
|
||||
videos.clear()
|
||||
videos.addAll(pager.getResults())
|
||||
shortsPager = pager
|
||||
|
||||
// if the viewPager exists then trigger data changed
|
||||
viewPager?.adapter?.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setLoading(isLoading: Boolean) {
|
||||
if (isLoading) {
|
||||
(overlayLoadingSpinner.drawable as Animatable?)?.start()
|
||||
overlayLoading.visibility = View.VISIBLE
|
||||
} else {
|
||||
overlayLoading.visibility = View.GONE
|
||||
(overlayLoadingSpinner.drawable as Animatable?)?.stop()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
previousShownView?.stop()
|
||||
customViewAdapter.previousShownView?.pause()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
customViewAdapter.previousShownView?.stop()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -69,26 +210,51 @@ class ShortsFragment : MainFragment() {
|
|||
}
|
||||
|
||||
class CustomViewAdapter(
|
||||
private val urls: List<String>, private val inflater: LayoutInflater, private val fragment: MainFragment
|
||||
private val videos: MutableList<IPlatformVideo>,
|
||||
private val inflater: LayoutInflater,
|
||||
private val fragment: MainFragment,
|
||||
private val overlayQualityContainer: FrameLayout,
|
||||
private val onNearEnd: () -> Unit,
|
||||
) : RecyclerView.Adapter<CustomViewHolder>() {
|
||||
val onResetTriggered = Event0()
|
||||
var previousShownView: ShortView? = null
|
||||
var needToPlay: Int? = null
|
||||
|
||||
@OptIn(UnstableApi::class)
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomViewHolder {
|
||||
val shortView = ShortView(inflater, fragment)
|
||||
val shortView = ShortView(inflater, fragment, overlayQualityContainer)
|
||||
shortView.onResetTriggered.subscribe {
|
||||
onResetTriggered.emit()
|
||||
}
|
||||
return CustomViewHolder(shortView)
|
||||
}
|
||||
|
||||
@OptIn(UnstableApi::class)
|
||||
override fun onBindViewHolder(holder: CustomViewHolder, position: Int) {
|
||||
holder.shortView.setVideo(urls[position])
|
||||
holder.shortView.changeVideo(videos[position])
|
||||
|
||||
if (position == itemCount - 1) {
|
||||
onNearEnd()
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(UnstableApi::class)
|
||||
override fun onViewRecycled(holder: CustomViewHolder) {
|
||||
super.onViewRecycled(holder)
|
||||
holder.shortView.detach()
|
||||
holder.shortView.cancel()
|
||||
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = urls.size
|
||||
override fun onViewAttachedToWindow(holder: CustomViewHolder) {
|
||||
super.onViewAttachedToWindow(holder)
|
||||
|
||||
if (holder.absoluteAdapterPosition == needToPlay) {
|
||||
holder.shortView.play()
|
||||
needToPlay = null
|
||||
previousShownView = holder.shortView
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = videos.size
|
||||
}
|
||||
|
||||
@OptIn(UnstableApi::class)
|
||||
|
|
|
@ -417,6 +417,47 @@ class StatePlatform {
|
|||
pager.initialize();
|
||||
return pager;
|
||||
}
|
||||
fun getShorts(): IPager<IPlatformVideo> {
|
||||
Logger.i(TAG, "Platform - getShorts");
|
||||
var clientIdsOngoing = mutableListOf<String>();
|
||||
val clients = getSortedEnabledClient().filter { if (it is JSClient) it.enableInShorts else true };
|
||||
|
||||
StateApp.instance.scopeOrNull?.let {
|
||||
it.launch(Dispatchers.Default) {
|
||||
try {
|
||||
// plugins that take longer than 5 seconds to load are considered "slow"
|
||||
delay(5000);
|
||||
val slowClients = synchronized(clientIdsOngoing) {
|
||||
return@synchronized clients.filter { clientIdsOngoing.contains(it.id) };
|
||||
};
|
||||
for(client in slowClients)
|
||||
UIDialogs.toast("${client.name} is still loading..\nConsider disabling it for Home", false);
|
||||
} catch (e: Throwable) {
|
||||
Logger.e(TAG, "Failed to show toast for slow source.", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val pages = clients.parallelStream()
|
||||
.map {
|
||||
Logger.i(TAG, "getShorts - ${it.name}")
|
||||
synchronized(clientIdsOngoing) {
|
||||
clientIdsOngoing.add(it.id);
|
||||
}
|
||||
val shortsResult = it.fromPool(_pagerClientPool).getShorts();
|
||||
synchronized(clientIdsOngoing) {
|
||||
clientIdsOngoing.remove(it.id);
|
||||
}
|
||||
return@map shortsResult;
|
||||
}
|
||||
.asSequence()
|
||||
.toList()
|
||||
.associateWith { 1f };
|
||||
|
||||
val pager = MultiDistributionContentPager(pages);
|
||||
pager.initialize();
|
||||
return pager;
|
||||
}
|
||||
suspend fun getHomeRefresh(scope: CoroutineScope): IPager<IPlatformContent> {
|
||||
Logger.i(TAG, "Platform - getHome (Refresh)");
|
||||
val clients = getSortedEnabledClient().filter { if (it is JSClient) it.enableInHome else true };
|
||||
|
|
|
@ -34,7 +34,7 @@ class PlayerManager {
|
|||
|
||||
@Synchronized
|
||||
fun attach(view: PlayerView, stateName: String) {
|
||||
if(view != _currentView) {
|
||||
if(view != _currentView || _currentView?.player == null) {
|
||||
_currentView?.player = null;
|
||||
switchState(stateName);
|
||||
view.player = player;
|
||||
|
|
|
@ -9,6 +9,7 @@ import android.util.AttributeSet
|
|||
import android.view.LayoutInflater
|
||||
import android.view.animation.LinearInterpolator
|
||||
import androidx.annotation.OptIn
|
||||
import androidx.media3.common.PlaybackParameters
|
||||
import androidx.media3.common.Player
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import androidx.media3.ui.DefaultTimeBar
|
||||
|
@ -21,6 +22,7 @@ import com.futo.platformplayer.R
|
|||
import com.futo.platformplayer.Settings
|
||||
import com.futo.platformplayer.api.media.models.video.IPlatformVideoDetails
|
||||
import com.futo.platformplayer.helpers.VideoHelper
|
||||
import com.futo.platformplayer.logging.Logger
|
||||
import com.futo.platformplayer.states.StatePlayer
|
||||
|
||||
@UnstableApi
|
||||
|
@ -33,6 +35,7 @@ class FutoShortPlayer(context: Context, attrs: AttributeSet? = null) :
|
|||
}
|
||||
|
||||
private var playerAttached = false
|
||||
// private set;
|
||||
|
||||
private val videoView: PlayerView
|
||||
private val progressBar: DefaultTimeBar
|
||||
|
@ -64,12 +67,15 @@ class FutoShortPlayer(context: Context, attrs: AttributeSet? = null) :
|
|||
}
|
||||
|
||||
if (player.isPlaying) {
|
||||
if (!progressAnimator.isStarted) {
|
||||
if (progressAnimator.isPaused){
|
||||
progressAnimator.resume()
|
||||
}
|
||||
else if (!progressAnimator.isStarted) {
|
||||
progressAnimator.start()
|
||||
}
|
||||
} else {
|
||||
if (progressAnimator.isRunning) {
|
||||
progressAnimator.cancel()
|
||||
progressAnimator.pause()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -81,10 +87,12 @@ class FutoShortPlayer(context: Context, attrs: AttributeSet? = null) :
|
|||
videoView = findViewById(R.id.video_player)
|
||||
progressBar = findViewById(R.id.video_player_progress_bar)
|
||||
|
||||
player.player.repeatMode = Player.REPEAT_MODE_ONE
|
||||
|
||||
progressBar.addListener(object : TimeBar.OnScrubListener {
|
||||
override fun onScrubStart(timeBar: TimeBar, position: Long) {
|
||||
if (progressAnimator.isRunning) {
|
||||
progressAnimator.cancel()
|
||||
progressAnimator.pause()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,7 +101,7 @@ class FutoShortPlayer(context: Context, attrs: AttributeSet? = null) :
|
|||
override fun onScrubStop(timeBar: TimeBar, position: Long, canceled: Boolean) {
|
||||
if (canceled) {
|
||||
progressAnimator.currentPlayTime = player.player.currentPosition
|
||||
progressAnimator.start()
|
||||
progressAnimator.resume()
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -110,9 +118,7 @@ class FutoShortPlayer(context: Context, attrs: AttributeSet? = null) :
|
|||
interpolator = LinearInterpolator()
|
||||
|
||||
addUpdateListener { animation ->
|
||||
val progress = animation.animatedValue as Float
|
||||
val duration = animation.duration
|
||||
progressBar.setPosition((progress * duration).toLong())
|
||||
progressBar.setPosition(animation.currentPlayTime)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -169,11 +175,28 @@ class FutoShortPlayer(context: Context, attrs: AttributeSet? = null) :
|
|||
@OptIn(UnstableApi::class)
|
||||
fun setArtwork(drawable: Drawable?) {
|
||||
if (drawable != null) {
|
||||
videoView.defaultArtwork = drawable
|
||||
videoView.artworkDisplayMode = PlayerView.ARTWORK_DISPLAY_MODE_FILL
|
||||
videoView.defaultArtwork = drawable
|
||||
} else {
|
||||
videoView.defaultArtwork = null
|
||||
videoView.artworkDisplayMode = PlayerView.ARTWORK_DISPLAY_MODE_OFF
|
||||
videoView.defaultArtwork = null
|
||||
}
|
||||
}
|
||||
|
||||
fun getPlaybackRate(): Float {
|
||||
return exoPlayer?.player?.playbackParameters?.speed ?: 1.0f
|
||||
}
|
||||
|
||||
fun setPlaybackRate(playbackRate: Float) {
|
||||
val exoPlayer = exoPlayer?.player
|
||||
Logger.i(TAG, "setPlaybackRate playbackRate=$playbackRate exoPlayer=${exoPlayer}")
|
||||
|
||||
val param = PlaybackParameters(playbackRate)
|
||||
exoPlayer?.playbackParameters = param
|
||||
}
|
||||
|
||||
// TODO remove stub
|
||||
fun hideControls(stub: Boolean) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,37 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.viewpager2.widget.ViewPager2 xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/viewPager"
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical" />
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/viewPager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/short_view_loading_overlay"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#77000000"
|
||||
android:elevation="4dp"
|
||||
android:visibility="gone">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/short_view_loader"
|
||||
android:layout_width="80dp"
|
||||
android:layout_height="80dp"
|
||||
android:layout_gravity="center_vertical|center_horizontal"
|
||||
android:alpha="0.7"
|
||||
android:contentDescription="@string/loading"
|
||||
app:srcCompat="@drawable/ic_loader_animated" />
|
||||
</FrameLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/videodetail_quality_overview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:elevation="100dp"
|
||||
android:visibility="gone" />
|
||||
</FrameLayout>
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/standard_bottom_sheet"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
@ -10,222 +12,401 @@
|
|||
android:id="@+id/drag_handle"
|
||||
style="@style/Widget.Material3.BottomSheet.DragHandle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingBottom="0dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
<FrameLayout
|
||||
android:id="@+id/contentContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
style="@style/Widget.Material3.CheckedTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="Bottom Sheet Content"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
<LinearLayout
|
||||
android:id="@+id/videodetail_container_main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/black"
|
||||
android:orientation="vertical"
|
||||
tools:ignore="SpeakableTextPresentCheck">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
style="@style/Widget.Material3.CheckedTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="Bottom Sheet Content"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_top"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
style="@style/Widget.Material3.CheckedTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="Bottom Sheet Content"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
<!--Title Segment-->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
style="@style/Widget.Material3.CheckedTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="Bottom Sheet Content"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
<!--Title + Meta-->
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="14dp"
|
||||
android:layout_marginEnd="14dp">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
style="@style/Widget.Material3.CheckedTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="Bottom Sheet Content"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
<TextView
|
||||
android:id="@+id/videodetail_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:fontFamily="@font/inter_medium"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="17dp"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toLeftOf="@id/layout_title_right"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="Some Text" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
style="@style/Widget.Material3.CheckedTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="Bottom Sheet Content"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
<TextView
|
||||
android:id="@+id/videodetail_meta"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:fontFamily="@font/inter_regular"
|
||||
android:textColor="#ACACAC"
|
||||
android:textSize="10dp"
|
||||
app:layout_constraintLeft_toLeftOf="@id/videodetail_title"
|
||||
app:layout_constraintRight_toLeftOf="@id/layout_title_right"
|
||||
app:layout_constraintTop_toBottomOf="@id/videodetail_title"
|
||||
tools:text="51K views - 3 years ago" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
style="@style/Widget.Material3.CheckedTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="Bottom Sheet Content"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
<!--Source Button-->
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_title_right"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="end"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
style="@style/Widget.Material3.CheckedTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="Bottom Sheet Content"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
<com.futo.platformplayer.views.platform.PlatformIndicator
|
||||
android:id="@+id/videodetail_platform"
|
||||
android:layout_width="25dp"
|
||||
android:layout_height="25dp"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
style="@style/Widget.Material3.CheckedTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="Bottom Sheet Content"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_rating"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
style="@style/Widget.Material3.CheckedTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="Bottom Sheet Content"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
style="@style/Widget.Material3.CheckedTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="Bottom Sheet Content"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
<ImageView
|
||||
android:id="@+id/image_like_icon"
|
||||
android:layout_width="14dp"
|
||||
android:layout_height="14dp"
|
||||
app:srcCompat="@drawable/ic_thumb_up"
|
||||
app:tint="#ACACAC" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
style="@style/Widget.Material3.CheckedTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="Bottom Sheet Content"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
<TextView
|
||||
android:id="@+id/text_likes"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="18dp"
|
||||
android:layout_marginStart="4dp"
|
||||
android:gravity="center_vertical"
|
||||
android:textColor="#ACACAC"
|
||||
android:textSize="10dp"
|
||||
tools:text="500K" />
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
style="@style/Widget.Material3.CheckedTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="Bottom Sheet Content"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
style="@style/Widget.Material3.CheckedTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="Bottom Sheet Content"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
<ImageView
|
||||
android:id="@+id/image_dislike_icon"
|
||||
android:layout_width="14dp"
|
||||
android:layout_height="14dp"
|
||||
android:layout_marginTop="2dp"
|
||||
app:srcCompat="@drawable/ic_thumb_down"
|
||||
app:tint="#ACACAC" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
style="@style/Widget.Material3.CheckedTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="Bottom Sheet Content"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
<TextView
|
||||
android:id="@+id/text_dislikes"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="18dp"
|
||||
android:layout_marginStart="4dp"
|
||||
android:gravity="center_vertical"
|
||||
android:textColor="#ACACAC"
|
||||
android:textSize="10dp"
|
||||
tools:text="500K" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
style="@style/Widget.Material3.CheckedTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="Bottom Sheet Content"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
style="@style/Widget.Material3.CheckedTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="Bottom Sheet Content"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
<!--Channel/Subscribe Segment-->
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="14dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginRight="14dp"
|
||||
android:layout_marginBottom="10dp">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
style="@style/Widget.Material3.CheckedTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="Bottom Sheet Content"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
<LinearLayout
|
||||
android:id="@+id/videodetail_channel_button"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="7dp"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toLeftOf="@id/button_subscribe"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
style="@style/Widget.Material3.CheckedTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="Bottom Sheet Content"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
<com.futo.platformplayer.views.others.CreatorThumbnail
|
||||
android:id="@+id/creator_thumbnail"
|
||||
android:layout_width="35dp"
|
||||
android:layout_height="35dp"
|
||||
android:contentDescription="@string/cd_creator_thumbnail" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
style="@style/Widget.Material3.CheckedTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="Bottom Sheet Content"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
style="@style/Widget.Material3.CheckedTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="Bottom Sheet Content"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
<TextView
|
||||
android:id="@+id/videodetail_channel_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:paddingEnd="10dp"
|
||||
android:textColor="@color/white"
|
||||
tools:text="Channel Name" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
style="@style/Widget.Material3.CheckedTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="Bottom Sheet Content"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
<TextView
|
||||
android:id="@+id/videodetail_channel_meta"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_weight="1"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="#ACACAC"
|
||||
android:textSize="9sp"
|
||||
tools:text="" />
|
||||
|
||||
<androidx.compose.ui.platform.ComposeView
|
||||
android:id="@+id/compose_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
<com.futo.platformplayer.views.subscriptions.SubscribeButton
|
||||
android:id="@+id/button_subscribe"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="10dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<!--Description-->
|
||||
<LinearLayout
|
||||
android:id="@+id/videodetail_description_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="14dp"
|
||||
android:layout_marginRight="14dp"
|
||||
android:animateLayoutChanges="true"
|
||||
android:background="@drawable/background_videodetail_description"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="12dp"
|
||||
android:paddingTop="3dp"
|
||||
android:paddingRight="12dp"
|
||||
android:paddingBottom="5dp">
|
||||
|
||||
<com.futo.platformplayer.views.behavior.NonScrollingTextView
|
||||
android:id="@+id/videodetail_description"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="5dp"
|
||||
android:background="@color/transparent"
|
||||
android:fontFamily="@font/inter_light"
|
||||
android:isScrollContainer="false"
|
||||
android:maxLines="3"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="11dp"
|
||||
tools:text="@string/lorem_ipsum" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/videodetail_description_view_more"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:background="@color/transparent"
|
||||
android:fontFamily="@font/inter_regular"
|
||||
android:text="@string/click_to_read_more"
|
||||
android:textAlignment="center"
|
||||
android:textColor="#585656"
|
||||
android:textSize="12dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<com.futo.platformplayer.views.MonetizationView
|
||||
android:id="@+id/monetization"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<com.futo.platformplayer.views.videometa.UpNextView
|
||||
android:id="@+id/up_next"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone">
|
||||
|
||||
<Button
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="15dp"
|
||||
android:text="@string/live_chat" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_change_bottom_section"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="14dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginRight="14dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:background="@drawable/background_videodetail_description"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_polycentric"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:ellipsize="marquee"
|
||||
android:lines="1"
|
||||
android:padding="10dp"
|
||||
android:text="Polycentric"
|
||||
android:textColor="#fff"
|
||||
android:textSize="10dp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_platform"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:ellipsize="marquee"
|
||||
android:lines="1"
|
||||
android:padding="10dp"
|
||||
android:text="Platform"
|
||||
android:textColor="#fff"
|
||||
android:textSize="10dp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_recommended"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:ellipsize="marquee"
|
||||
android:lines="1"
|
||||
android:padding="10dp"
|
||||
android:text="Recommended"
|
||||
android:textColor="#fff"
|
||||
android:textSize="10dp"
|
||||
android:visibility="gone" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_recommended"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="12dp"
|
||||
android:layout_marginRight="12dp"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone"></LinearLayout>
|
||||
|
||||
<com.futo.platformplayer.views.comments.AddCommentView
|
||||
android:id="@+id/add_comment_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="28dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginEnd="28dp"
|
||||
android:layout_marginBottom="12dp" />
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<com.futo.platformplayer.views.segments.CommentsList
|
||||
android:id="@+id/comments_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="400dp"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/layout_top" />
|
||||
</LinearLayout>
|
||||
|
||||
<com.futo.platformplayer.views.overlays.DescriptionOverlay
|
||||
android:id="@+id/videodetail_container_description"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone" />
|
||||
|
||||
<com.futo.platformplayer.views.overlays.LiveChatOverlay
|
||||
android:id="@+id/videodetail_container_livechat"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone" />
|
||||
|
||||
<com.futo.platformplayer.views.overlays.WebviewOverlay
|
||||
android:id="@+id/videodetail_container_webview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone" />
|
||||
|
||||
<com.futo.platformplayer.views.overlays.QueueEditorOverlay
|
||||
android:id="@+id/videodetail_container_queue"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone" />
|
||||
|
||||
<com.futo.platformplayer.views.overlays.RepliesOverlay
|
||||
android:id="@+id/videodetail_container_replies"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone" />
|
||||
|
||||
<com.futo.platformplayer.views.overlays.SupportOverlay
|
||||
android:id="@+id/videodetail_container_support"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone" />
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent" />
|
||||
|
||||
<ScrollView
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginStart="15dp"
|
||||
|
@ -37,6 +37,6 @@
|
|||
android:textSize="13sp"
|
||||
android:textIsSelectable="true"
|
||||
tools:text="@string/lorem_ipsum" />
|
||||
</ScrollView>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -20,8 +20,7 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:elevation="1dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
app:layout_constraintBottom_toBottomOf="parent" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/short_view_loading_overlay"
|
||||
|
|
|
@ -560,6 +560,7 @@
|
|||
<string name="enable_where_this_plugins_content_are_visible">Enable where this plugin\'s content are visible</string>
|
||||
<string name="show_content_in_home_tab">Show content in home tab</string>
|
||||
<string name="show_content_in_search_results">Show content in search results</string>
|
||||
<string name="show_content_in_shorts_tab">Show content in shorts tab</string>
|
||||
<string name="no_valid_url_provided">No valid URL provided..</string>
|
||||
<string name="invalid_config_format">Invalid Config Format</string>
|
||||
<string name="failed_to_fetch_configuration">Failed to fetch configuration</string>
|
||||
|
|
|
@ -41,4 +41,18 @@
|
|||
<item name="cornerSizeBottomLeft">4dp</item>
|
||||
<item name="cornerSizeBottomRight">4dp</item>
|
||||
</style>
|
||||
|
||||
<!--this section here attempts to emulate the look of the default material 3 bottom sheet i got the values from the material 3 theme-->
|
||||
<style name="Custom.BottomSheet.ShapeAppearance" parent="">
|
||||
<item name="cornerFamily">?attr/shapeCornerFamily</item>
|
||||
<item name="cornerSize">28dp</item>
|
||||
</style>
|
||||
<style name="Custom.BottomSheet.Modal.Style" parent="Widget.MaterialComponents.BottomSheet.Modal">
|
||||
<item name="shapeAppearanceOverlay">@style/Custom.BottomSheet.ShapeAppearance</item>
|
||||
<!-- force black background while grayjay only has a dark theme-->
|
||||
<item name="backgroundTint">@color/black</item>
|
||||
</style>
|
||||
<style name="Custom.BottomSheetDialog.Theme" parent="@style/ThemeOverlay.Material3.BottomSheetDialog">
|
||||
<item name="bottomSheetStyle">@style/Custom.BottomSheet.Modal.Style</item>
|
||||
</style>
|
||||
</resources>
|
Loading…
Add table
Reference in a new issue