add back button when in channel shorts

hide refresh button when in channel shorts

prevent main player being open when viewing shorts

show info toast when long pressing refresh button

switch bottom bar button ids back to their original values

Changelog: changed
This commit is contained in:
Kai 2025-07-10 09:30:42 -05:00
commit cac8a8fde4
No known key found for this signature in database
6 changed files with 118 additions and 139 deletions

View file

@ -353,10 +353,6 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
_fragBrowser = BrowserFragment.newInstance();
_fragShorts.onShownEvent.subscribe {
_fragVideoDetail.closeVideoDetails()
};
//Overlays
_fragVideoDetail = VideoDetailFragment.newInstance();
//Overlay Init

View file

@ -392,13 +392,13 @@ class MenuBottomBarFragment : MainActivityFragment() {
ButtonDefinition(2, R.drawable.ic_creators, R.drawable.ic_creators_filled, R.string.creators, canToggle = false, { it.currentMain is CreatorsFragment }, { it.navigate<CreatorsFragment>(withHistory = false) }),
ButtonDefinition(3, R.drawable.ic_sources, R.drawable.ic_sources_filled, R.string.sources, canToggle = false, { it.currentMain is SourcesFragment }, { it.navigate<SourcesFragment>(withHistory = false) }),
ButtonDefinition(4, R.drawable.ic_playlist, R.drawable.ic_playlist_filled, R.string.playlists, canToggle = false, { it.currentMain is PlaylistsFragment }, { it.navigate<PlaylistsFragment>(withHistory = false) }),
ButtonDefinition(5, R.drawable.ic_smart_display, R.drawable.ic_smart_display_filled, R.string.shorts, canToggle = true, { it.currentMain is ShortsFragment && !(it.currentMain as ShortsFragment).isChannelShortsMode }, { it.navigate<ShortsFragment>(withHistory = false) }),
ButtonDefinition(6, R.drawable.ic_history, R.drawable.ic_history, R.string.history, canToggle = false, { it.currentMain is HistoryFragment }, { it.navigate<HistoryFragment>(withHistory = false) }),
ButtonDefinition(7, R.drawable.ic_download, R.drawable.ic_download, R.string.downloads, canToggle = false, { it.currentMain is DownloadsFragment }, { it.navigate<DownloadsFragment>(withHistory = false) }),
ButtonDefinition(11, R.drawable.ic_smart_display, R.drawable.ic_smart_display_filled, R.string.shorts, canToggle = true, { it.currentMain is ShortsFragment && !(it.currentMain as ShortsFragment).isChannelShortsMode }, { it.navigate<ShortsFragment>(withHistory = false) }),
ButtonDefinition(5, R.drawable.ic_history, R.drawable.ic_history, R.string.history, canToggle = false, { it.currentMain is HistoryFragment }, { it.navigate<HistoryFragment>(withHistory = false) }),
ButtonDefinition(6, R.drawable.ic_download, R.drawable.ic_download, R.string.downloads, canToggle = false, { it.currentMain is DownloadsFragment }, { it.navigate<DownloadsFragment>(withHistory = false) }),
ButtonDefinition(8, R.drawable.ic_chat, R.drawable.ic_chat_filled, R.string.comments, canToggle = true, { it.currentMain is CommentsFragment }, { it.navigate<CommentsFragment>(withHistory = false) }),
ButtonDefinition(9, R.drawable.ic_subscriptions, R.drawable.ic_subscriptions_filled, R.string.subscription_group_menu, canToggle = true, { it.currentMain is SubscriptionGroupListFragment }, { it.navigate<SubscriptionGroupListFragment>(withHistory = false) }),
ButtonDefinition(10, R.drawable.ic_help_square, R.drawable.ic_help_square_fill, R.string.tutorials, canToggle = true, { it.currentMain is TutorialFragment }, { it.navigate<TutorialFragment>(withHistory = false) }),
ButtonDefinition(11, R.drawable.ic_settings, R.drawable.ic_settings_filled, R.string.settings, canToggle = false, { false }, {
ButtonDefinition(7, R.drawable.ic_settings, R.drawable.ic_settings_filled, R.string.settings, canToggle = false, { false }, {
val c = it.context ?: return@ButtonDefinition;
Logger.i(TAG, "settings preventPictureInPicture()");
it.requireFragment<VideoDetailFragment>().preventPictureInPicture();

View file

@ -21,6 +21,7 @@ import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.graphics.drawable.toDrawable
import androidx.core.net.toUri
import androidx.lifecycle.lifecycleScope
@ -122,6 +123,9 @@ class ShortView : FrameLayout {
private val videoTitle: TextView
private val platformIndicator: PlatformIndicator
private val backButton: MaterialButton
private val backButtonContainer: ConstraintLayout
private val likeContainer: FrameLayout
private val dislikeContainer: FrameLayout
private val likeButton: MaterialButton
@ -132,6 +136,7 @@ class ShortView : FrameLayout {
private val commentsButton: MaterialButton
private val shareButton: MaterialButton
private val refreshButton: MaterialButton
private val refreshButtonContainer: View
private val qualityButton: MaterialButton
private val playPauseOverlay: FrameLayout
@ -180,129 +185,7 @@ class ShortView : FrameLayout {
dislikeCount.text = value.toString()
}
// Required constructor for XML inflation
constructor(context: Context) : super(context) {
inflate(context, R.layout.view_short, this)
player = findViewById(R.id.short_player)
channelInfo = findViewById(R.id.channel_info)
creatorThumbnail = findViewById(R.id.creator_thumbnail)
channelName = findViewById(R.id.channel_name)
videoTitle = findViewById(R.id.video_title)
platformIndicator = findViewById(R.id.short_platform_indicator)
likeContainer = findViewById(R.id.like_container)
dislikeContainer = findViewById(R.id.dislike_container)
likeButton = findViewById(R.id.like_button)
likeCount = findViewById(R.id.like_count)
dislikeButton = findViewById(R.id.dislike_button)
dislikeCount = findViewById(R.id.dislike_count)
commentsButton = findViewById(R.id.comments_button)
shareButton = findViewById(R.id.share_button)
refreshButton = findViewById(R.id.refresh_button)
qualityButton = findViewById(R.id.quality_button)
playPauseOverlay = findViewById(R.id.play_pause_overlay)
playPauseIcon = findViewById(R.id.play_pause_icon)
overlayLoading = findViewById(R.id.short_view_loading_overlay)
overlayLoadingSpinner = findViewById(R.id.short_view_loader)
init()
}
// Required constructor for XML inflation with attributes
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
inflate(context, R.layout.view_short, this)
player = findViewById(R.id.short_player)
channelInfo = findViewById(R.id.channel_info)
creatorThumbnail = findViewById(R.id.creator_thumbnail)
channelName = findViewById(R.id.channel_name)
videoTitle = findViewById(R.id.video_title)
platformIndicator = findViewById(R.id.short_platform_indicator)
likeContainer = findViewById(R.id.like_container)
dislikeContainer = findViewById(R.id.dislike_container)
likeButton = findViewById(R.id.like_button)
likeCount = findViewById(R.id.like_count)
dislikeButton = findViewById(R.id.dislike_button)
dislikeCount = findViewById(R.id.dislike_count)
commentsButton = findViewById(R.id.comments_button)
shareButton = findViewById(R.id.share_button)
refreshButton = findViewById(R.id.refresh_button)
qualityButton = findViewById(R.id.quality_button)
playPauseOverlay = findViewById(R.id.play_pause_overlay)
playPauseIcon = findViewById(R.id.play_pause_icon)
overlayLoading = findViewById(R.id.short_view_loading_overlay)
overlayLoadingSpinner = findViewById(R.id.short_view_loader)
init()
}
// Required constructor for XML inflation with attributes and style
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
inflate(context, R.layout.view_short, this)
player = findViewById(R.id.short_player)
channelInfo = findViewById(R.id.channel_info)
creatorThumbnail = findViewById(R.id.creator_thumbnail)
channelName = findViewById(R.id.channel_name)
videoTitle = findViewById(R.id.video_title)
platformIndicator = findViewById(R.id.short_platform_indicator)
likeContainer = findViewById(R.id.like_container)
dislikeContainer = findViewById(R.id.dislike_container)
likeButton = findViewById(R.id.like_button)
likeCount = findViewById(R.id.like_count)
dislikeButton = findViewById(R.id.dislike_button)
dislikeCount = findViewById(R.id.dislike_count)
commentsButton = findViewById(R.id.comments_button)
shareButton = findViewById(R.id.share_button)
refreshButton = findViewById(R.id.refresh_button)
qualityButton = findViewById(R.id.quality_button)
playPauseOverlay = findViewById(R.id.play_pause_overlay)
playPauseIcon = findViewById(R.id.play_pause_icon)
overlayLoading = findViewById(R.id.short_view_loading_overlay)
overlayLoadingSpinner = findViewById(R.id.short_view_loader)
init()
}
constructor(inflater: LayoutInflater, fragment: MainFragment, overlayQualityContainer: FrameLayout) : super(inflater.context) {
inflater.inflate(R.layout.view_short, this, true)
player = findViewById(R.id.short_player)
channelInfo = findViewById(R.id.channel_info)
creatorThumbnail = findViewById(R.id.creator_thumbnail)
channelName = findViewById(R.id.channel_name)
videoTitle = findViewById(R.id.video_title)
platformIndicator = findViewById(R.id.short_platform_indicator)
likeContainer = findViewById(R.id.like_container)
dislikeContainer = findViewById(R.id.dislike_container)
likeButton = findViewById(R.id.like_button)
likeCount = findViewById(R.id.like_count)
dislikeButton = findViewById(R.id.dislike_button)
dislikeCount = findViewById(R.id.dislike_count)
commentsButton = findViewById(R.id.comments_button)
shareButton = findViewById(R.id.share_button)
refreshButton = findViewById(R.id.refresh_button)
qualityButton = findViewById(R.id.quality_button)
playPauseOverlay = findViewById(R.id.play_pause_overlay)
playPauseIcon = findViewById(R.id.play_pause_icon)
overlayLoading = findViewById(R.id.short_view_loading_overlay)
overlayLoadingSpinner = findViewById(R.id.short_view_loader)
constructor(inflater: LayoutInflater, fragment: MainFragment, overlayQualityContainer: FrameLayout) : this(inflater.context) {
this.overlayQualityContainer = overlayQualityContainer
layoutParams = LayoutParams(
@ -311,11 +194,46 @@ class ShortView : FrameLayout {
this.mainFragment = fragment
bottomSheet.mainFragment = fragment
init()
}
private fun init() {
// Required constructor for XML inflation
constructor(context: Context) : this(context, null, null)
// Required constructor for XML inflation with attributes
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, null)
// Required constructor for XML inflation with attributes and style
constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int? = null) : super(
context, attrs, defStyleAttr ?: 0
) {
// Inflate the layout once here
inflate(context, R.layout.view_short, this)
// Initialize all val properties using findViewById
player = findViewById(R.id.short_player)
channelInfo = findViewById(R.id.channel_info)
creatorThumbnail = findViewById(R.id.creator_thumbnail)
channelName = findViewById(R.id.channel_name)
videoTitle = findViewById(R.id.video_title)
platformIndicator = findViewById(R.id.short_platform_indicator)
backButton = findViewById(R.id.back_button)
backButtonContainer = findViewById(R.id.back_button_container)
likeContainer = findViewById(R.id.like_container)
dislikeContainer = findViewById(R.id.dislike_container)
likeButton = findViewById(R.id.like_button)
likeCount = findViewById(R.id.like_count)
dislikeButton = findViewById(R.id.dislike_button)
dislikeCount = findViewById(R.id.dislike_count)
commentsButton = findViewById(R.id.comments_button)
shareButton = findViewById(R.id.share_button)
refreshButton = findViewById(R.id.refresh_button)
refreshButtonContainer = findViewById(R.id.refresh_button_container)
qualityButton = findViewById(R.id.quality_button)
playPauseOverlay = findViewById(R.id.play_pause_overlay)
playPauseIcon = findViewById(R.id.play_pause_icon)
overlayLoading = findViewById(R.id.short_view_loading_overlay)
overlayLoadingSpinner = findViewById(R.id.short_view_loader)
player.setOnClickListener {
if (player.activelyPlaying) {
player.pause()
@ -344,6 +262,11 @@ class ShortView : FrameLayout {
channelName.text = it?.author?.name
}
backButton.setOnClickListener {
playSoundEffect(SoundEffectConstants.CLICK)
mainFragment.closeSegment()
}
channelInfo.setOnClickListener {
playSoundEffect(SoundEffectConstants.CLICK)
mainFragment.navigate<ChannelFragment>(video?.author)
@ -378,6 +301,11 @@ class ShortView : FrameLayout {
onResetTriggered.emit()
}
refreshButton.setOnLongClickListener {
UIDialogs.toast(context, "Reload all platform shorts pagers")
false
}
qualityButton.setOnClickListener {
playSoundEffect(SoundEffectConstants.CLICK)
showVideoSettings()
@ -692,12 +620,23 @@ class ShortView : FrameLayout {
this.overlayQualityContainer = overlayQualityContainer
}
fun changeVideo(video: IPlatformVideo) {
fun changeVideo(video: IPlatformVideo, isChannelShortsMode: Boolean) {
if (this.video?.url == video.url) {
return
}
this.video = video
refreshButtonContainer.visibility = if (isChannelShortsMode) {
GONE
} else {
VISIBLE
}
backButtonContainer.visibility = if (isChannelShortsMode) {
VISIBLE
} else {
GONE
}
loadVideo(video.url)
}

View file

@ -14,6 +14,7 @@ import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2
import com.futo.platformplayer.R
import com.futo.platformplayer.UIDialogs
import com.futo.platformplayer.activities.MainActivity
import com.futo.platformplayer.api.media.models.video.IPlatformVideo
import com.futo.platformplayer.api.media.structures.IPager
import com.futo.platformplayer.constructs.Event0
@ -58,6 +59,7 @@ class ShortsFragment : MainFragment() {
// we just completely reset the data structure so we want to tell the adapter that
@SuppressLint("NotifyDataSetChanged")
override fun onShownWithView(parameter: Any?, isBack: Boolean) {
(activity as MainActivity?)?.getFragment<VideoDetailFragment>()?.closeVideoDetails()
super.onShownWithView(parameter, isBack)
if (parameter is Triple<*, *, *>) {
@ -114,7 +116,7 @@ class ShortsFragment : MainFragment() {
Logger.i(TAG, "Creating adapter")
val customViewAdapter =
CustomViewAdapter(currentShorts, layoutInflater, this@ShortsFragment, overlayQualityContainer) {
CustomViewAdapter(currentShorts, layoutInflater, this@ShortsFragment, overlayQualityContainer, { isChannelShortsMode }) {
if (!currentShortsPager!!.hasMorePages()) {
return@CustomViewAdapter
}
@ -288,6 +290,7 @@ class ShortsFragment : MainFragment() {
private val inflater: LayoutInflater,
private val fragment: MainFragment,
private val overlayQualityContainer: FrameLayout,
private val isChannelShortsMode: () -> Boolean,
private val onNearEnd: () -> Unit,
) : RecyclerView.Adapter<CustomViewHolder>() {
val onResetTriggered = Event0()
@ -297,7 +300,8 @@ class ShortsFragment : MainFragment() {
@OptIn(UnstableApi::class)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomViewHolder {
val shortView = ShortView(inflater, fragment, overlayQualityContainer)
val shortView =
ShortView(inflater, fragment, overlayQualityContainer)
shortView.onResetTriggered.subscribe {
onResetTriggered.emit()
}
@ -306,7 +310,7 @@ class ShortsFragment : MainFragment() {
@OptIn(UnstableApi::class)
override fun onBindViewHolder(holder: CustomViewHolder, position: Int) {
holder.shortView.changeVideo(videos[position])
holder.shortView.changeVideo(videos[position], isChannelShortsMode())
if (position == itemCount - 1) {
onNearEnd()

View file

@ -10,6 +10,45 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Back button -->
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:visibility="gone"
android:id="@+id/back_button_container">
<ImageView
android:layout_width="0dp"
android:layout_height="0dp"
android:importantForAccessibility="no"
android:src="@drawable/button_shadow"
app:layout_constraintBottom_toBottomOf="@id/back_button"
app:layout_constraintEnd_toEndOf="@id/back_button"
app:layout_constraintStart_toStartOf="@id/back_button"
app:layout_constraintTop_toTopOf="@id/back_button"
app:tint="@color/black"
tools:ignore="ImageContrastCheck" />
<com.google.android.material.button.MaterialButton
android:id="@+id/back_button"
style="@style/Widget.Material3.Button.IconButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:contentDescription="@string/cd_button_back"
app:backgroundTint="@color/transparent"
app:icon="@drawable/ic_back_nav"
app:iconSize="24dp"
app:iconTint="@android:color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:rippleColor="@color/ripple" />
</androidx.constraintlayout.widget.ConstraintLayout>
<!-- Title section -->
<LinearLayout
android:id="@+id/title_section"
@ -331,6 +370,7 @@
<!-- Refresh button -->
<FrameLayout
android:id="@+id/refresh_button_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"

@ -1 +1 @@
Subproject commit d11543001150f96f3383d83fec3341d9321746b8
Subproject commit 850eb8122dd8348904d55ceb9c3a26b49bcb8a45