From b09d22e479312b539db96ac8a8465b30b930a024 Mon Sep 17 00:00:00 2001 From: Koen Date: Wed, 22 Nov 2023 14:49:34 +0100 Subject: [PATCH] Added historical time bars to videos. --- .../java/com/futo/platformplayer/Settings.kt | 40 ++++++++++++++----- .../platformplayer/activities/MainActivity.kt | 4 ++ .../channel/tab/ChannelContentsFragment.kt | 3 +- .../mainactivity/main/ContentFeedView.kt | 3 +- .../main/ContentSearchResultsFragment.kt | 1 + .../mainactivity/main/HomeFragment.kt | 1 + .../main/SubscriptionsFeedFragment.kt | 2 + .../feedtypes/PreviewContentListAdapter.kt | 6 ++- .../adapters/feedtypes/PreviewVideoView.kt | 19 ++++++++- .../feedtypes/PreviewVideoViewHolder.kt | 4 +- .../main/res/layout/list_video_preview.xml | 14 +++++++ .../main/res/layout/list_video_thumbnail.xml | 14 +++++++ app/src/main/res/values/strings.xml | 3 ++ 13 files changed, 97 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/com/futo/platformplayer/Settings.kt b/app/src/main/java/com/futo/platformplayer/Settings.kt index fc4b1fb7..9ef64a86 100644 --- a/app/src/main/java/com/futo/platformplayer/Settings.kt +++ b/app/src/main/java/com/futo/platformplayer/Settings.kt @@ -446,8 +446,28 @@ class Settings : FragmentedStorageFileJson() { }*/ } + @FormField(R.string.time_bar, "group", R.string.configure_if_historical_time_bar_should_be_shown, 8) + var timeBars = TimeBars(); + @Serializable + class TimeBars { + @FormField(R.string.home, FieldForm.TOGGLE, -1, 0) + @Serializable(with = FlexibleBooleanSerializer::class) + var home: Boolean = true; - @FormField(R.string.logging, FieldForm.GROUP, -1, 8) + @FormField(R.string.subscriptions, FieldForm.TOGGLE, -1, 1) + @Serializable(with = FlexibleBooleanSerializer::class) + var subscriptions: Boolean = true; + + @FormField(R.string.search, FieldForm.TOGGLE, -1, 2) + @Serializable(with = FlexibleBooleanSerializer::class) + var search: Boolean = true; + + @FormField(R.string.channel, FieldForm.TOGGLE, -1, 3) + @Serializable(with = FlexibleBooleanSerializer::class) + var channel: Boolean = true; + } + + @FormField(R.string.logging, FieldForm.GROUP, -1, 9) var logging = Logging(); @Serializable class Logging { @@ -471,7 +491,7 @@ class Settings : FragmentedStorageFileJson() { } } - @FormField(R.string.announcement, FieldForm.GROUP, -1, 10) + @FormField(R.string.announcement, FieldForm.GROUP, -1, 11) var announcementSettings = AnnouncementSettings(); @Serializable class AnnouncementSettings { @@ -482,7 +502,7 @@ class Settings : FragmentedStorageFileJson() { } } - @FormField(R.string.notifications, FieldForm.GROUP, -1, 11) + @FormField(R.string.notifications, FieldForm.GROUP, -1, 12) var notifications = NotificationSettings(); @Serializable class NotificationSettings { @@ -490,7 +510,7 @@ class Settings : FragmentedStorageFileJson() { var plannedContentNotification: Boolean = true; } - @FormField(R.string.plugins, FieldForm.GROUP, -1, 12) + @FormField(R.string.plugins, FieldForm.GROUP, -1, 13) @Transient var plugins = Plugins(); @Serializable @@ -527,7 +547,7 @@ class Settings : FragmentedStorageFileJson() { } - @FormField(R.string.external_storage, FieldForm.GROUP, -1, 13) + @FormField(R.string.external_storage, FieldForm.GROUP, -1, 14) var storage = Storage(); @Serializable class Storage { @@ -561,7 +581,7 @@ class Settings : FragmentedStorageFileJson() { } - @FormField(R.string.auto_update, "group", R.string.configure_the_auto_updater, 14) + @FormField(R.string.auto_update, "group", R.string.configure_the_auto_updater, 15) var autoUpdate = AutoUpdate(); @Serializable class AutoUpdate { @@ -643,7 +663,7 @@ class Settings : FragmentedStorageFileJson() { } } - @FormField(R.string.backup, FieldForm.GROUP, -1, 15) + @FormField(R.string.backup, FieldForm.GROUP, -1, 16) var backup = Backup(); @Serializable class Backup { @@ -696,7 +716,7 @@ class Settings : FragmentedStorageFileJson() { }*/ } - @FormField(R.string.payment, FieldForm.GROUP, -1, 16) + @FormField(R.string.payment, FieldForm.GROUP, -1, 17) var payment = Payment(); @Serializable class Payment { @@ -713,7 +733,7 @@ class Settings : FragmentedStorageFileJson() { } } - @FormField(R.string.other, FieldForm.GROUP, -1, 17) + @FormField(R.string.other, FieldForm.GROUP, -1, 18) var other = Other(); @Serializable class Other { @@ -722,7 +742,7 @@ class Settings : FragmentedStorageFileJson() { var bypassRotationPrevention: Boolean = false; } - @FormField(R.string.info, FieldForm.GROUP, -1, 18) + @FormField(R.string.info, FieldForm.GROUP, -1, 19) var info = Info(); @Serializable class Info { diff --git a/app/src/main/java/com/futo/platformplayer/activities/MainActivity.kt b/app/src/main/java/com/futo/platformplayer/activities/MainActivity.kt index a9839361..c1d849ef 100644 --- a/app/src/main/java/com/futo/platformplayer/activities/MainActivity.kt +++ b/app/src/main/java/com/futo/platformplayer/activities/MainActivity.kt @@ -893,6 +893,10 @@ class MainActivity : AppCompatActivity, IWithResultLauncher { } else { if (_fragVideoDetail.state == VideoDetailFragment.State.CLOSED) { finish(); + } else { + UIDialogs.showConfirmationDialog(this, "There is a video playing, are you sure you want to exit the app?", { + finish(); + }) } } } diff --git a/app/src/main/java/com/futo/platformplayer/fragment/channel/tab/ChannelContentsFragment.kt b/app/src/main/java/com/futo/platformplayer/fragment/channel/tab/ChannelContentsFragment.kt index 0d92eec8..9ac89b82 100644 --- a/app/src/main/java/com/futo/platformplayer/fragment/channel/tab/ChannelContentsFragment.kt +++ b/app/src/main/java/com/futo/platformplayer/fragment/channel/tab/ChannelContentsFragment.kt @@ -11,6 +11,7 @@ import androidx.recyclerview.widget.RecyclerView import com.futo.platformplayer.logging.Logger import com.futo.platformplayer.states.StatePlatform import com.futo.platformplayer.R +import com.futo.platformplayer.Settings import com.futo.platformplayer.UIDialogs import com.futo.platformplayer.api.media.models.PlatformAuthorLink import com.futo.platformplayer.api.media.models.channels.IPlatformChannel @@ -151,7 +152,7 @@ class ChannelContentsFragment : Fragment(), IChannelTabFragment { _recyclerResults = view.findViewById(R.id.recycler_videos); - _adapterResults = PreviewContentListAdapter(view.context, FeedStyle.THUMBNAIL, _results).apply { + _adapterResults = PreviewContentListAdapter(view.context, FeedStyle.THUMBNAIL, _results, null, Settings.instance.timeBars.channel).apply { this.onContentUrlClicked.subscribe(this@ChannelContentsFragment.onContentUrlClicked::emit); this.onUrlClicked.subscribe(this@ChannelContentsFragment.onUrlClicked::emit); this.onContentClicked.subscribe(this@ChannelContentsFragment.onContentClicked::emit); diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/ContentFeedView.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/ContentFeedView.kt index 686c54e5..2986eb20 100644 --- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/ContentFeedView.kt +++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/ContentFeedView.kt @@ -37,6 +37,7 @@ abstract class ContentFeedView : FeedView, LinearLayoutManager, IPager, IPlatformContent, IPlatformContent, InsertedViewHolder>? = null) : super(fragment, inflater, cachedRecyclerData) { @@ -57,7 +58,7 @@ abstract class ContentFeedView : FeedView>; + override val shouldShowTimeBar: Boolean get() = Settings.instance.timeBars.search constructor(fragment: ContentSearchResultsFragment, inflater: LayoutInflater) : super(fragment, inflater) { _taskSearch = TaskHandler>({fragment.lifecycleScope}, { query -> diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/HomeFragment.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/HomeFragment.kt index ebf5d56e..ee1944e9 100644 --- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/HomeFragment.kt +++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/HomeFragment.kt @@ -95,6 +95,7 @@ class HomeFragment : MainFragment() { private var _announcementsView: AnnouncementView; private val _taskGetPager: TaskHandler>; + override val shouldShowTimeBar: Boolean get() = Settings.instance.timeBars.home constructor(fragment: HomeFragment, inflater: LayoutInflater, cachedRecyclerData: RecyclerData, LinearLayoutManager, IPager, IPlatformContent, IPlatformContent, InsertedViewHolder>? = null) : super(fragment, inflater, cachedRecyclerData) { _announcementsView = AnnouncementView(context, null).apply { diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/SubscriptionsFeedFragment.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/SubscriptionsFeedFragment.kt index adeb0390..7317cb95 100644 --- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/SubscriptionsFeedFragment.kt +++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/SubscriptionsFeedFragment.kt @@ -93,6 +93,8 @@ class SubscriptionsFeedFragment : MainFragment() { @SuppressLint("ViewConstructor") class SubscriptionsFeedView : ContentFeedView { + override val shouldShowTimeBar: Boolean get() = Settings.instance.timeBars.subscriptions + constructor(fragment: SubscriptionsFeedFragment, inflater: LayoutInflater, cachedRecyclerData: RecyclerData, LinearLayoutManager, IPager, IPlatformContent, IPlatformContent, InsertedViewHolder>? = null) : super(fragment, inflater, cachedRecyclerData) { Logger.i(TAG, "SubscriptionsFeedFragment constructor()"); StateSubscriptions.instance.onGlobalSubscriptionsUpdateProgress.subscribe(this) { progress, total -> diff --git a/app/src/main/java/com/futo/platformplayer/views/adapters/feedtypes/PreviewContentListAdapter.kt b/app/src/main/java/com/futo/platformplayer/views/adapters/feedtypes/PreviewContentListAdapter.kt index 503a26c2..112fab64 100644 --- a/app/src/main/java/com/futo/platformplayer/views/adapters/feedtypes/PreviewContentListAdapter.kt +++ b/app/src/main/java/com/futo/platformplayer/views/adapters/feedtypes/PreviewContentListAdapter.kt @@ -29,6 +29,7 @@ class PreviewContentListAdapter : InsertedViewAdapterWithLoader(); val onContentUrlClicked = Event2(); @@ -48,12 +49,13 @@ class PreviewContentListAdapter : InsertedViewAdapterWithLoader, exoPlayer: PlayerManager? = null, initialPlay: Boolean = false, viewsToPrepend: ArrayList = arrayListOf(), - viewsToAppend: ArrayList = arrayListOf()) : super(context, viewsToPrepend, viewsToAppend) { + viewsToAppend: ArrayList = arrayListOf(), shouldShowTimeBar: Boolean = true) : super(context, viewsToPrepend, viewsToAppend) { this._feedStyle = feedStyle; this._dataSet = dataSet; this._initialPlay = initialPlay; this._exoPlayer = exoPlayer; + this._shouldShowTimeBar = shouldShowTimeBar } override fun getChildCount(): Int = _dataSet.size; @@ -97,7 +99,7 @@ class PreviewContentListAdapter : InsertedViewAdapterWithLoader(); val onLongPress = Event1(); val onChannelClicked = Event1(); @@ -77,10 +81,12 @@ open class PreviewVideoView : LinearLayout { private set val content: IPlatformContent? get() = currentVideo; + val shouldShowTimeBar: Boolean - constructor(context: Context, feedStyle : FeedStyle, exoPlayer: PlayerManager? = null) : super(context) { + constructor(context: Context, feedStyle : FeedStyle, exoPlayer: PlayerManager? = null, shouldShowTimeBar: Boolean = true) : super(context) { inflate(feedStyle); _feedStyle = feedStyle; + this.shouldShowTimeBar = shouldShowTimeBar val playerContainer = findViewById(R.id.player_container); val displayMetrics = Resources.getSystem().displayMetrics; @@ -117,6 +123,7 @@ open class PreviewVideoView : LinearLayout { _button_add_to = findViewById(R.id.button_add_to); _imageNeopassChannel = findViewById(R.id.image_neopass_channel); _layoutDownloaded = findViewById(R.id.layout_downloaded); + _timeBar = findViewById(R.id.time_bar) this._exoPlayer = exoPlayer @@ -235,13 +242,23 @@ open class PreviewVideoView : LinearLayout { _containerLive.visibility = GONE; _containerDuration.visibility = VISIBLE; } + + if (shouldShowTimeBar) { + val historyPosition = StatePlaylists.instance.getHistoryPosition(video.url) + _timeBar.visibility = if (historyPosition > 0) VISIBLE else GONE + _timeBar.progress = historyPosition.toFloat() / video.duration.toFloat() + } else { + _timeBar.visibility = GONE + } } else { currentVideo = null; _imageVideo.setImageResource(0); _containerDuration.visibility = GONE; _containerLive.visibility = GONE; + _timeBar.visibility = GONE; } + _textVideoMetadata.text = metadata + timeMeta; } diff --git a/app/src/main/java/com/futo/platformplayer/views/adapters/feedtypes/PreviewVideoViewHolder.kt b/app/src/main/java/com/futo/platformplayer/views/adapters/feedtypes/PreviewVideoViewHolder.kt index e3793ff4..8f998365 100644 --- a/app/src/main/java/com/futo/platformplayer/views/adapters/feedtypes/PreviewVideoViewHolder.kt +++ b/app/src/main/java/com/futo/platformplayer/views/adapters/feedtypes/PreviewVideoViewHolder.kt @@ -27,8 +27,8 @@ class PreviewVideoViewHolder : ContentPreviewViewHolder { private val view: PreviewVideoView get() = itemView as PreviewVideoView; - constructor(viewGroup: ViewGroup, feedStyle : FeedStyle, exoPlayer: PlayerManager? = null): super( - PreviewVideoView(viewGroup.context, feedStyle, exoPlayer) + constructor(viewGroup: ViewGroup, feedStyle : FeedStyle, exoPlayer: PlayerManager? = null, shouldShowTimeBar: Boolean = true): super( + PreviewVideoView(viewGroup.context, feedStyle, exoPlayer, shouldShowTimeBar) ) { view.onVideoClicked.subscribe(onVideoClicked::emit); view.onChannelClicked.subscribe(onChannelClicked::emit); diff --git a/app/src/main/res/layout/list_video_preview.xml b/app/src/main/res/layout/list_video_preview.xml index 0f067668..ac93a071 100644 --- a/app/src/main/res/layout/list_video_preview.xml +++ b/app/src/main/res/layout/list_video_preview.xml @@ -32,6 +32,20 @@ android:scaleType="centerCrop" tools:srcCompat="@drawable/placeholder_video_thumbnail" /> + + diff --git a/app/src/main/res/layout/list_video_thumbnail.xml b/app/src/main/res/layout/list_video_thumbnail.xml index 33115dcb..bc69e9da 100644 --- a/app/src/main/res/layout/list_video_thumbnail.xml +++ b/app/src/main/res/layout/list_video_thumbnail.xml @@ -117,6 +117,20 @@ android:layout_gravity="end" android:layout_marginStart="4dp" android:layout_marginBottom="4dp" /> + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c6514a13..dda12fc9 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -8,6 +8,7 @@ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Add to queue General + Channel Home Recommendations More @@ -299,6 +300,8 @@ Clears cookies when you log out Clears in-app browser cookies Configure browsing behavior + Time bar + Configure if historical time bars should be shown Configure casting Configure daily backup in case of catastrophic failure Configure downloading of videos