mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2025-04-20 03:24:50 +00:00
Added historical time bars to videos.
This commit is contained in:
parent
01787b6229
commit
b09d22e479
13 changed files with 97 additions and 17 deletions
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -37,6 +37,7 @@ abstract class ContentFeedView<TFragment> : FeedView<TFragment, IPlatformContent
|
|||
override val visibleThreshold: Int get() = if (feedStyle == FeedStyle.PREVIEW) { 5 } else { 10 };
|
||||
protected lateinit var headerView: LinearLayout;
|
||||
private var _videoOptionsOverlay: SlideUpMenuOverlay? = null;
|
||||
protected open val shouldShowTimeBar: Boolean get() = true
|
||||
|
||||
constructor(fragment: TFragment, inflater: LayoutInflater, cachedRecyclerData: RecyclerData<InsertedViewAdapterWithLoader<ContentPreviewViewHolder>, LinearLayoutManager, IPager<IPlatformContent>, IPlatformContent, IPlatformContent, InsertedViewHolder<ContentPreviewViewHolder>>? = null) : super(fragment, inflater, cachedRecyclerData) {
|
||||
|
||||
|
@ -57,7 +58,7 @@ abstract class ContentFeedView<TFragment> : FeedView<TFragment, IPlatformContent
|
|||
};
|
||||
headerView = v;
|
||||
|
||||
return PreviewContentListAdapter(context, feedStyle, dataset, player, _previewsEnabled, arrayListOf(v)).apply {
|
||||
return PreviewContentListAdapter(context, feedStyle, dataset, player, _previewsEnabled, arrayListOf(v), arrayListOf(), shouldShowTimeBar).apply {
|
||||
attachAdapterEvents(this);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,6 +84,7 @@ class ContentSearchResultsFragment : MainFragment() {
|
|||
private var _channelUrl: String? = null;
|
||||
|
||||
private val _taskSearch: TaskHandler<String, IPager<IPlatformContent>>;
|
||||
override val shouldShowTimeBar: Boolean get() = Settings.instance.timeBars.search
|
||||
|
||||
constructor(fragment: ContentSearchResultsFragment, inflater: LayoutInflater) : super(fragment, inflater) {
|
||||
_taskSearch = TaskHandler<String, IPager<IPlatformContent>>({fragment.lifecycleScope}, { query ->
|
||||
|
|
|
@ -95,6 +95,7 @@ class HomeFragment : MainFragment() {
|
|||
private var _announcementsView: AnnouncementView;
|
||||
|
||||
private val _taskGetPager: TaskHandler<Boolean, IPager<IPlatformContent>>;
|
||||
override val shouldShowTimeBar: Boolean get() = Settings.instance.timeBars.home
|
||||
|
||||
constructor(fragment: HomeFragment, inflater: LayoutInflater, cachedRecyclerData: RecyclerData<InsertedViewAdapterWithLoader<ContentPreviewViewHolder>, LinearLayoutManager, IPager<IPlatformContent>, IPlatformContent, IPlatformContent, InsertedViewHolder<ContentPreviewViewHolder>>? = null) : super(fragment, inflater, cachedRecyclerData) {
|
||||
_announcementsView = AnnouncementView(context, null).apply {
|
||||
|
|
|
@ -93,6 +93,8 @@ class SubscriptionsFeedFragment : MainFragment() {
|
|||
|
||||
@SuppressLint("ViewConstructor")
|
||||
class SubscriptionsFeedView : ContentFeedView<SubscriptionsFeedFragment> {
|
||||
override val shouldShowTimeBar: Boolean get() = Settings.instance.timeBars.subscriptions
|
||||
|
||||
constructor(fragment: SubscriptionsFeedFragment, inflater: LayoutInflater, cachedRecyclerData: RecyclerData<InsertedViewAdapterWithLoader<ContentPreviewViewHolder>, LinearLayoutManager, IPager<IPlatformContent>, IPlatformContent, IPlatformContent, InsertedViewHolder<ContentPreviewViewHolder>>? = null) : super(fragment, inflater, cachedRecyclerData) {
|
||||
Logger.i(TAG, "SubscriptionsFeedFragment constructor()");
|
||||
StateSubscriptions.instance.onGlobalSubscriptionsUpdateProgress.subscribe(this) { progress, total ->
|
||||
|
|
|
@ -29,6 +29,7 @@ class PreviewContentListAdapter : InsertedViewAdapterWithLoader<ContentPreviewVi
|
|||
private val _exoPlayer: PlayerManager?;
|
||||
private val _feedStyle : FeedStyle;
|
||||
private var _paused: Boolean = false;
|
||||
private val _shouldShowTimeBar: Boolean
|
||||
|
||||
val onUrlClicked = Event1<String>();
|
||||
val onContentUrlClicked = Event2<String, ContentType>();
|
||||
|
@ -48,12 +49,13 @@ class PreviewContentListAdapter : InsertedViewAdapterWithLoader<ContentPreviewVi
|
|||
|
||||
constructor(context: Context, feedStyle : FeedStyle, dataSet: ArrayList<IPlatformContent>, exoPlayer: PlayerManager? = null,
|
||||
initialPlay: Boolean = false, viewsToPrepend: ArrayList<View> = arrayListOf(),
|
||||
viewsToAppend: ArrayList<View> = arrayListOf()) : super(context, viewsToPrepend, viewsToAppend) {
|
||||
viewsToAppend: ArrayList<View> = 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<ContentPreviewVi
|
|||
};
|
||||
private fun createPlaceholderViewHolder(viewGroup: ViewGroup): PreviewPlaceholderViewHolder
|
||||
= PreviewPlaceholderViewHolder(viewGroup, _feedStyle);
|
||||
private fun createVideoPreviewViewHolder(viewGroup: ViewGroup): PreviewVideoViewHolder = PreviewVideoViewHolder(viewGroup, _feedStyle, _exoPlayer).apply {
|
||||
private fun createVideoPreviewViewHolder(viewGroup: ViewGroup): PreviewVideoViewHolder = PreviewVideoViewHolder(viewGroup, _feedStyle, _exoPlayer, _shouldShowTimeBar).apply {
|
||||
this.onVideoClicked.subscribe(this@PreviewContentListAdapter.onContentClicked::emit);
|
||||
this.onChannelClicked.subscribe(this@PreviewContentListAdapter.onChannelClicked::emit);
|
||||
this.onAddToClicked.subscribe(this@PreviewContentListAdapter.onAddToClicked::emit);
|
||||
|
|
|
@ -27,9 +27,11 @@ import com.futo.platformplayer.logging.Logger
|
|||
import com.futo.platformplayer.polycentric.PolycentricCache
|
||||
import com.futo.platformplayer.states.StateApp
|
||||
import com.futo.platformplayer.states.StateDownloads
|
||||
import com.futo.platformplayer.states.StatePlaylists
|
||||
import com.futo.platformplayer.video.PlayerManager
|
||||
import com.futo.platformplayer.views.others.CreatorThumbnail
|
||||
import com.futo.platformplayer.views.FeedStyle
|
||||
import com.futo.platformplayer.views.others.ProgressBar
|
||||
import com.futo.platformplayer.views.platform.PlatformIndicator
|
||||
import com.futo.platformplayer.views.video.FutoThumbnailPlayer
|
||||
import com.futo.polycentric.core.toURLInfoSystemLinkUrl
|
||||
|
@ -67,6 +69,8 @@ open class PreviewVideoView : LinearLayout {
|
|||
Logger.w(TAG, "Failed to load profile.", it);
|
||||
};
|
||||
|
||||
private val _timeBar: ProgressBar;
|
||||
|
||||
val onVideoClicked = Event2<IPlatformVideo, Long>();
|
||||
val onLongPress = Event1<IPlatformVideo>();
|
||||
val onChannelClicked = Event1<PlatformAuthorLink>();
|
||||
|
@ -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<FrameLayout>(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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -32,6 +32,20 @@
|
|||
android:scaleType="centerCrop"
|
||||
tools:srcCompat="@drawable/placeholder_video_thumbnail" />
|
||||
|
||||
<com.futo.platformplayer.views.others.ProgressBar
|
||||
android:id="@+id/time_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="2dp"
|
||||
android:layout_gravity="bottom"
|
||||
android:layout_marginBottom="6dp"
|
||||
app:progress="60%"
|
||||
app:inactiveColor="#55EEEEEE"
|
||||
app:radiusBottomLeft="0dp"
|
||||
app:radiusBottomRight="0dp"
|
||||
app:radiusTopLeft="0dp"
|
||||
app:radiusTopRight="0dp"
|
||||
android:visibility="visible"/>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
|
|
@ -117,6 +117,20 @@
|
|||
android:layout_gravity="end"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginBottom="4dp" />
|
||||
|
||||
<com.futo.platformplayer.views.others.ProgressBar
|
||||
android:id="@+id/time_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="2dp"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
app:progress="60%"
|
||||
app:inactiveColor="#55EEEEEE"
|
||||
app:radiusBottomLeft="4dp"
|
||||
app:radiusBottomRight="4dp"
|
||||
app:radiusTopLeft="0dp"
|
||||
app:radiusTopRight="0dp"
|
||||
android:visibility="visible"/>
|
||||
</RelativeLayout>
|
||||
</FrameLayout>
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
<string name="lorem_ipsum" translatable="false">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.</string>
|
||||
<string name="add_to_queue">Add to queue</string>
|
||||
<string name="general">General</string>
|
||||
<string name="channel">Channel</string>
|
||||
<string name="home">Home</string>
|
||||
<string name="recommendations">Recommendations</string>
|
||||
<string name="more">More</string>
|
||||
|
@ -299,6 +300,8 @@
|
|||
<string name="clears_cookies_when_you_log_out">Clears cookies when you log out</string>
|
||||
<string name="clears_in_app_browser_cookies">Clears in-app browser cookies</string>
|
||||
<string name="configure_browsing_behavior">Configure browsing behavior</string>
|
||||
<string name="time_bar">Time bar</string>
|
||||
<string name="configure_if_historical_time_bar_should_be_shown">Configure if historical time bars should be shown</string>
|
||||
<string name="configure_casting">Configure casting</string>
|
||||
<string name="configure_daily_backup_in_case_of_catastrophic_failure">Configure daily backup in case of catastrophic failure</string>
|
||||
<string name="configure_downloading_of_videos">Configure downloading of videos</string>
|
||||
|
|
Loading…
Add table
Reference in a new issue