Added historical time bars to videos.

This commit is contained in:
Koen 2023-11-22 14:49:34 +01:00
commit b09d22e479
13 changed files with 97 additions and 17 deletions

View file

@ -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(); var logging = Logging();
@Serializable @Serializable
class Logging { 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(); var announcementSettings = AnnouncementSettings();
@Serializable @Serializable
class AnnouncementSettings { 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(); var notifications = NotificationSettings();
@Serializable @Serializable
class NotificationSettings { class NotificationSettings {
@ -490,7 +510,7 @@ class Settings : FragmentedStorageFileJson() {
var plannedContentNotification: Boolean = true; var plannedContentNotification: Boolean = true;
} }
@FormField(R.string.plugins, FieldForm.GROUP, -1, 12) @FormField(R.string.plugins, FieldForm.GROUP, -1, 13)
@Transient @Transient
var plugins = Plugins(); var plugins = Plugins();
@Serializable @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(); var storage = Storage();
@Serializable @Serializable
class Storage { 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(); var autoUpdate = AutoUpdate();
@Serializable @Serializable
class AutoUpdate { 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(); var backup = Backup();
@Serializable @Serializable
class Backup { 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(); var payment = Payment();
@Serializable @Serializable
class Payment { 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(); var other = Other();
@Serializable @Serializable
class Other { class Other {
@ -722,7 +742,7 @@ class Settings : FragmentedStorageFileJson() {
var bypassRotationPrevention: Boolean = false; var bypassRotationPrevention: Boolean = false;
} }
@FormField(R.string.info, FieldForm.GROUP, -1, 18) @FormField(R.string.info, FieldForm.GROUP, -1, 19)
var info = Info(); var info = Info();
@Serializable @Serializable
class Info { class Info {

View file

@ -893,6 +893,10 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
} else { } else {
if (_fragVideoDetail.state == VideoDetailFragment.State.CLOSED) { if (_fragVideoDetail.state == VideoDetailFragment.State.CLOSED) {
finish(); finish();
} else {
UIDialogs.showConfirmationDialog(this, "There is a video playing, are you sure you want to exit the app?", {
finish();
})
} }
} }
} }

View file

@ -11,6 +11,7 @@ import androidx.recyclerview.widget.RecyclerView
import com.futo.platformplayer.logging.Logger import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.states.StatePlatform import com.futo.platformplayer.states.StatePlatform
import com.futo.platformplayer.R import com.futo.platformplayer.R
import com.futo.platformplayer.Settings
import com.futo.platformplayer.UIDialogs import com.futo.platformplayer.UIDialogs
import com.futo.platformplayer.api.media.models.PlatformAuthorLink import com.futo.platformplayer.api.media.models.PlatformAuthorLink
import com.futo.platformplayer.api.media.models.channels.IPlatformChannel import com.futo.platformplayer.api.media.models.channels.IPlatformChannel
@ -151,7 +152,7 @@ class ChannelContentsFragment : Fragment(), IChannelTabFragment {
_recyclerResults = view.findViewById(R.id.recycler_videos); _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.onContentUrlClicked.subscribe(this@ChannelContentsFragment.onContentUrlClicked::emit);
this.onUrlClicked.subscribe(this@ChannelContentsFragment.onUrlClicked::emit); this.onUrlClicked.subscribe(this@ChannelContentsFragment.onUrlClicked::emit);
this.onContentClicked.subscribe(this@ChannelContentsFragment.onContentClicked::emit); this.onContentClicked.subscribe(this@ChannelContentsFragment.onContentClicked::emit);

View file

@ -37,6 +37,7 @@ abstract class ContentFeedView<TFragment> : FeedView<TFragment, IPlatformContent
override val visibleThreshold: Int get() = if (feedStyle == FeedStyle.PREVIEW) { 5 } else { 10 }; override val visibleThreshold: Int get() = if (feedStyle == FeedStyle.PREVIEW) { 5 } else { 10 };
protected lateinit var headerView: LinearLayout; protected lateinit var headerView: LinearLayout;
private var _videoOptionsOverlay: SlideUpMenuOverlay? = null; 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) { 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; 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); attachAdapterEvents(this);
} }
} }

View file

@ -84,6 +84,7 @@ class ContentSearchResultsFragment : MainFragment() {
private var _channelUrl: String? = null; private var _channelUrl: String? = null;
private val _taskSearch: TaskHandler<String, IPager<IPlatformContent>>; private val _taskSearch: TaskHandler<String, IPager<IPlatformContent>>;
override val shouldShowTimeBar: Boolean get() = Settings.instance.timeBars.search
constructor(fragment: ContentSearchResultsFragment, inflater: LayoutInflater) : super(fragment, inflater) { constructor(fragment: ContentSearchResultsFragment, inflater: LayoutInflater) : super(fragment, inflater) {
_taskSearch = TaskHandler<String, IPager<IPlatformContent>>({fragment.lifecycleScope}, { query -> _taskSearch = TaskHandler<String, IPager<IPlatformContent>>({fragment.lifecycleScope}, { query ->

View file

@ -95,6 +95,7 @@ class HomeFragment : MainFragment() {
private var _announcementsView: AnnouncementView; private var _announcementsView: AnnouncementView;
private val _taskGetPager: TaskHandler<Boolean, IPager<IPlatformContent>>; 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) { 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 { _announcementsView = AnnouncementView(context, null).apply {

View file

@ -93,6 +93,8 @@ class SubscriptionsFeedFragment : MainFragment() {
@SuppressLint("ViewConstructor") @SuppressLint("ViewConstructor")
class SubscriptionsFeedView : ContentFeedView<SubscriptionsFeedFragment> { 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) { 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()"); Logger.i(TAG, "SubscriptionsFeedFragment constructor()");
StateSubscriptions.instance.onGlobalSubscriptionsUpdateProgress.subscribe(this) { progress, total -> StateSubscriptions.instance.onGlobalSubscriptionsUpdateProgress.subscribe(this) { progress, total ->

View file

@ -29,6 +29,7 @@ class PreviewContentListAdapter : InsertedViewAdapterWithLoader<ContentPreviewVi
private val _exoPlayer: PlayerManager?; private val _exoPlayer: PlayerManager?;
private val _feedStyle : FeedStyle; private val _feedStyle : FeedStyle;
private var _paused: Boolean = false; private var _paused: Boolean = false;
private val _shouldShowTimeBar: Boolean
val onUrlClicked = Event1<String>(); val onUrlClicked = Event1<String>();
val onContentUrlClicked = Event2<String, ContentType>(); val onContentUrlClicked = Event2<String, ContentType>();
@ -48,12 +49,13 @@ class PreviewContentListAdapter : InsertedViewAdapterWithLoader<ContentPreviewVi
constructor(context: Context, feedStyle : FeedStyle, dataSet: ArrayList<IPlatformContent>, exoPlayer: PlayerManager? = null, constructor(context: Context, feedStyle : FeedStyle, dataSet: ArrayList<IPlatformContent>, exoPlayer: PlayerManager? = null,
initialPlay: Boolean = false, viewsToPrepend: ArrayList<View> = arrayListOf(), 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._feedStyle = feedStyle;
this._dataSet = dataSet; this._dataSet = dataSet;
this._initialPlay = initialPlay; this._initialPlay = initialPlay;
this._exoPlayer = exoPlayer; this._exoPlayer = exoPlayer;
this._shouldShowTimeBar = shouldShowTimeBar
} }
override fun getChildCount(): Int = _dataSet.size; override fun getChildCount(): Int = _dataSet.size;
@ -97,7 +99,7 @@ class PreviewContentListAdapter : InsertedViewAdapterWithLoader<ContentPreviewVi
}; };
private fun createPlaceholderViewHolder(viewGroup: ViewGroup): PreviewPlaceholderViewHolder private fun createPlaceholderViewHolder(viewGroup: ViewGroup): PreviewPlaceholderViewHolder
= PreviewPlaceholderViewHolder(viewGroup, _feedStyle); = 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.onVideoClicked.subscribe(this@PreviewContentListAdapter.onContentClicked::emit);
this.onChannelClicked.subscribe(this@PreviewContentListAdapter.onChannelClicked::emit); this.onChannelClicked.subscribe(this@PreviewContentListAdapter.onChannelClicked::emit);
this.onAddToClicked.subscribe(this@PreviewContentListAdapter.onAddToClicked::emit); this.onAddToClicked.subscribe(this@PreviewContentListAdapter.onAddToClicked::emit);

View file

@ -27,9 +27,11 @@ import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.polycentric.PolycentricCache import com.futo.platformplayer.polycentric.PolycentricCache
import com.futo.platformplayer.states.StateApp import com.futo.platformplayer.states.StateApp
import com.futo.platformplayer.states.StateDownloads import com.futo.platformplayer.states.StateDownloads
import com.futo.platformplayer.states.StatePlaylists
import com.futo.platformplayer.video.PlayerManager import com.futo.platformplayer.video.PlayerManager
import com.futo.platformplayer.views.others.CreatorThumbnail import com.futo.platformplayer.views.others.CreatorThumbnail
import com.futo.platformplayer.views.FeedStyle 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.platform.PlatformIndicator
import com.futo.platformplayer.views.video.FutoThumbnailPlayer import com.futo.platformplayer.views.video.FutoThumbnailPlayer
import com.futo.polycentric.core.toURLInfoSystemLinkUrl import com.futo.polycentric.core.toURLInfoSystemLinkUrl
@ -67,6 +69,8 @@ open class PreviewVideoView : LinearLayout {
Logger.w(TAG, "Failed to load profile.", it); Logger.w(TAG, "Failed to load profile.", it);
}; };
private val _timeBar: ProgressBar;
val onVideoClicked = Event2<IPlatformVideo, Long>(); val onVideoClicked = Event2<IPlatformVideo, Long>();
val onLongPress = Event1<IPlatformVideo>(); val onLongPress = Event1<IPlatformVideo>();
val onChannelClicked = Event1<PlatformAuthorLink>(); val onChannelClicked = Event1<PlatformAuthorLink>();
@ -77,10 +81,12 @@ open class PreviewVideoView : LinearLayout {
private set private set
val content: IPlatformContent? get() = currentVideo; 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); inflate(feedStyle);
_feedStyle = feedStyle; _feedStyle = feedStyle;
this.shouldShowTimeBar = shouldShowTimeBar
val playerContainer = findViewById<FrameLayout>(R.id.player_container); val playerContainer = findViewById<FrameLayout>(R.id.player_container);
val displayMetrics = Resources.getSystem().displayMetrics; val displayMetrics = Resources.getSystem().displayMetrics;
@ -117,6 +123,7 @@ open class PreviewVideoView : LinearLayout {
_button_add_to = findViewById(R.id.button_add_to); _button_add_to = findViewById(R.id.button_add_to);
_imageNeopassChannel = findViewById(R.id.image_neopass_channel); _imageNeopassChannel = findViewById(R.id.image_neopass_channel);
_layoutDownloaded = findViewById(R.id.layout_downloaded); _layoutDownloaded = findViewById(R.id.layout_downloaded);
_timeBar = findViewById(R.id.time_bar)
this._exoPlayer = exoPlayer this._exoPlayer = exoPlayer
@ -235,13 +242,23 @@ open class PreviewVideoView : LinearLayout {
_containerLive.visibility = GONE; _containerLive.visibility = GONE;
_containerDuration.visibility = VISIBLE; _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 { else {
currentVideo = null; currentVideo = null;
_imageVideo.setImageResource(0); _imageVideo.setImageResource(0);
_containerDuration.visibility = GONE; _containerDuration.visibility = GONE;
_containerLive.visibility = GONE; _containerLive.visibility = GONE;
_timeBar.visibility = GONE;
} }
_textVideoMetadata.text = metadata + timeMeta; _textVideoMetadata.text = metadata + timeMeta;
} }

View file

@ -27,8 +27,8 @@ class PreviewVideoViewHolder : ContentPreviewViewHolder {
private val view: PreviewVideoView get() = itemView as PreviewVideoView; private val view: PreviewVideoView get() = itemView as PreviewVideoView;
constructor(viewGroup: ViewGroup, feedStyle : FeedStyle, exoPlayer: PlayerManager? = null): super( constructor(viewGroup: ViewGroup, feedStyle : FeedStyle, exoPlayer: PlayerManager? = null, shouldShowTimeBar: Boolean = true): super(
PreviewVideoView(viewGroup.context, feedStyle, exoPlayer) PreviewVideoView(viewGroup.context, feedStyle, exoPlayer, shouldShowTimeBar)
) { ) {
view.onVideoClicked.subscribe(onVideoClicked::emit); view.onVideoClicked.subscribe(onVideoClicked::emit);
view.onChannelClicked.subscribe(onChannelClicked::emit); view.onChannelClicked.subscribe(onChannelClicked::emit);

View file

@ -32,6 +32,20 @@
android:scaleType="centerCrop" android:scaleType="centerCrop"
tools:srcCompat="@drawable/placeholder_video_thumbnail" /> 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 <androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">

View file

@ -117,6 +117,20 @@
android:layout_gravity="end" android:layout_gravity="end"
android:layout_marginStart="4dp" android:layout_marginStart="4dp"
android:layout_marginBottom="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> </RelativeLayout>
</FrameLayout> </FrameLayout>

View file

@ -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="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="add_to_queue">Add to queue</string>
<string name="general">General</string> <string name="general">General</string>
<string name="channel">Channel</string>
<string name="home">Home</string> <string name="home">Home</string>
<string name="recommendations">Recommendations</string> <string name="recommendations">Recommendations</string>
<string name="more">More</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_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="clears_in_app_browser_cookies">Clears in-app browser cookies</string>
<string name="configure_browsing_behavior">Configure browsing behavior</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_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_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> <string name="configure_downloading_of_videos">Configure downloading of videos</string>