mirror of
https://github.com/libre-tube/LibreTube.git
synced 2025-04-28 16:00:31 +05:30
Merge pull request #2119 from Bnyro/master
Indicator the the feed got caught up for subscriptions
This commit is contained in:
commit
04a9340eec
@ -5,6 +5,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
|||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class ContentItem(
|
data class ContentItem(
|
||||||
var url: String? = null,
|
var url: String? = null,
|
||||||
|
val type: String? = null,
|
||||||
var thumbnail: String? = null,
|
var thumbnail: String? = null,
|
||||||
var uploaderName: String? = null,
|
var uploaderName: String? = null,
|
||||||
var uploaded: Long? = null,
|
var uploaded: Long? = null,
|
||||||
@ -16,6 +17,7 @@ data class ContentItem(
|
|||||||
var uploadedDate: String? = null,
|
var uploadedDate: String? = null,
|
||||||
var duration: Long? = null,
|
var duration: Long? = null,
|
||||||
var views: Long? = null,
|
var views: Long? = null,
|
||||||
|
var isShort: Boolean? = null,
|
||||||
var uploaderVerified: Boolean? = null,
|
var uploaderVerified: Boolean? = null,
|
||||||
// Channel and Playlist attributes
|
// Channel and Playlist attributes
|
||||||
var name: String? = null,
|
var name: String? = null,
|
||||||
|
@ -5,6 +5,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
|||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class StreamItem(
|
data class StreamItem(
|
||||||
var url: String? = null,
|
var url: String? = null,
|
||||||
|
val type: String? = null,
|
||||||
var title: String? = null,
|
var title: String? = null,
|
||||||
var thumbnail: String? = null,
|
var thumbnail: String? = null,
|
||||||
var uploaderName: String? = null,
|
var uploaderName: String? = null,
|
||||||
@ -15,5 +16,6 @@ data class StreamItem(
|
|||||||
var views: Long? = null,
|
var views: Long? = null,
|
||||||
var uploaderVerified: Boolean? = null,
|
var uploaderVerified: Boolean? = null,
|
||||||
var uploaded: Long? = null,
|
var uploaded: Long? = null,
|
||||||
var shortDescription: String? = null
|
var shortDescription: String? = null,
|
||||||
|
val isShort: Boolean = false
|
||||||
)
|
)
|
||||||
|
@ -100,12 +100,17 @@ object PreferenceKeys {
|
|||||||
const val NOTIFICATION_ENABLED = "notification_toggle"
|
const val NOTIFICATION_ENABLED = "notification_toggle"
|
||||||
const val CHECKING_FREQUENCY = "checking_frequency"
|
const val CHECKING_FREQUENCY = "checking_frequency"
|
||||||
const val REQUIRED_NETWORK = "required_network"
|
const val REQUIRED_NETWORK = "required_network"
|
||||||
const val LAST_STREAM_VIDEO_ID = "last_stream_video_id"
|
|
||||||
const val IGNORED_NOTIFICATION_CHANNELS = "ignored_notification_channels"
|
const val IGNORED_NOTIFICATION_CHANNELS = "ignored_notification_channels"
|
||||||
const val NOTIFICATION_TIME_ENABLED = "notification_time"
|
const val NOTIFICATION_TIME_ENABLED = "notification_time"
|
||||||
const val NOTIFICATION_START_TIME = "notification_start_time"
|
const val NOTIFICATION_START_TIME = "notification_start_time"
|
||||||
const val NOTIFICATION_END_TIME = "notification_end_time"
|
const val NOTIFICATION_END_TIME = "notification_end_time"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subscriptions
|
||||||
|
*/
|
||||||
|
const val LAST_STREAM_VIDEO_ID = "last_stream_video_id"
|
||||||
|
const val LAST_WATCHED_FEED_TIME = "last_watched_feed_time"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Advanced
|
* Advanced
|
||||||
*/
|
*/
|
||||||
|
@ -71,10 +71,10 @@ class SearchAdapter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemViewType(position: Int): Int {
|
override fun getItemViewType(position: Int): Int {
|
||||||
return when {
|
return when (searchItems[position].type) {
|
||||||
searchItems[position].url!!.startsWith("/watch", false) -> 0
|
"stream" -> 0
|
||||||
searchItems[position].url!!.startsWith("/channel", false) -> 1
|
"channel" -> 1
|
||||||
searchItems[position].url!!.startsWith("/playlist", false) -> 2
|
"playlist" -> 2
|
||||||
else -> 3
|
else -> 3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ import androidx.recyclerview.widget.RecyclerView.LayoutManager
|
|||||||
import com.github.libretube.R
|
import com.github.libretube.R
|
||||||
import com.github.libretube.api.obj.StreamItem
|
import com.github.libretube.api.obj.StreamItem
|
||||||
import com.github.libretube.constants.PreferenceKeys
|
import com.github.libretube.constants.PreferenceKeys
|
||||||
|
import com.github.libretube.databinding.AllCaughtUpRowBinding
|
||||||
import com.github.libretube.databinding.TrendingRowBinding
|
import com.github.libretube.databinding.TrendingRowBinding
|
||||||
import com.github.libretube.databinding.VideoRowBinding
|
import com.github.libretube.databinding.VideoRowBinding
|
||||||
import com.github.libretube.extensions.formatShort
|
import com.github.libretube.extensions.formatShort
|
||||||
@ -44,6 +45,10 @@ class VideosAdapter(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getItemViewType(position: Int): Int {
|
||||||
|
return if (streamItems[position].type == "caught") CAUGHT_UP_TYPE else NORMAL_TYPE
|
||||||
|
}
|
||||||
|
|
||||||
fun updateItems() {
|
fun updateItems() {
|
||||||
val oldSize = index
|
val oldSize = index
|
||||||
index += 10
|
index += 10
|
||||||
@ -59,6 +64,7 @@ class VideosAdapter(
|
|||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VideosViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VideosViewHolder {
|
||||||
val layoutInflater = LayoutInflater.from(parent.context)
|
val layoutInflater = LayoutInflater.from(parent.context)
|
||||||
return when {
|
return when {
|
||||||
|
viewType == CAUGHT_UP_TYPE -> VideosViewHolder(AllCaughtUpRowBinding.inflate(layoutInflater, parent, false))
|
||||||
forceMode in listOf(ForceMode.TRENDING, ForceMode.RELATED, ForceMode.HOME) -> VideosViewHolder(TrendingRowBinding.inflate(layoutInflater, parent, false))
|
forceMode in listOf(ForceMode.TRENDING, ForceMode.RELATED, ForceMode.HOME) -> VideosViewHolder(TrendingRowBinding.inflate(layoutInflater, parent, false))
|
||||||
forceMode == ForceMode.CHANNEL -> VideosViewHolder(VideoRowBinding.inflate(layoutInflater, parent, false))
|
forceMode == ForceMode.CHANNEL -> VideosViewHolder(VideoRowBinding.inflate(layoutInflater, parent, false))
|
||||||
PreferenceHelper.getBoolean(
|
PreferenceHelper.getBoolean(
|
||||||
@ -74,7 +80,7 @@ class VideosAdapter(
|
|||||||
val video = streamItems[position]
|
val video = streamItems[position]
|
||||||
|
|
||||||
// hide the item if there was an extractor error
|
// hide the item if there was an extractor error
|
||||||
if (video.title == null) {
|
if (video.title == null && video.type != "caught") {
|
||||||
holder.itemView.visibility = View.GONE
|
holder.itemView.visibility = View.GONE
|
||||||
holder.itemView.layoutParams = RecyclerView.LayoutParams(0, 0)
|
holder.itemView.layoutParams = RecyclerView.LayoutParams(0, 0)
|
||||||
return
|
return
|
||||||
@ -191,5 +197,8 @@ class VideosAdapter(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private const val NORMAL_TYPE = 0
|
||||||
|
private const val CAUGHT_UP_TYPE = 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import androidx.fragment.app.activityViewModels
|
|||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.github.libretube.R
|
import com.github.libretube.R
|
||||||
|
import com.github.libretube.api.obj.StreamItem
|
||||||
import com.github.libretube.constants.PreferenceKeys
|
import com.github.libretube.constants.PreferenceKeys
|
||||||
import com.github.libretube.databinding.FragmentSubscriptionsBinding
|
import com.github.libretube.databinding.FragmentSubscriptionsBinding
|
||||||
import com.github.libretube.ui.adapters.LegacySubscriptionAdapter
|
import com.github.libretube.ui.adapters.LegacySubscriptionAdapter
|
||||||
@ -144,6 +145,15 @@ class SubscriptionsFragment : BaseFragment() {
|
|||||||
4 -> feed.sortedBy { it.uploaderName }
|
4 -> feed.sortedBy { it.uploaderName }
|
||||||
5 -> feed.sortedBy { it.uploaderName }.reversed()
|
5 -> feed.sortedBy { it.uploaderName }.reversed()
|
||||||
else -> feed
|
else -> feed
|
||||||
|
}.toMutableList()
|
||||||
|
|
||||||
|
// add an "all caught up item"
|
||||||
|
if (sortOrder == 0) {
|
||||||
|
val lastCheckedFeedTime = PreferenceHelper.getLastCheckedFeedTime()
|
||||||
|
val caughtUpIndex = feed.indexOfFirst { (it.uploaded ?: 0L) / 1000 < lastCheckedFeedTime }
|
||||||
|
if (caughtUpIndex > 0) {
|
||||||
|
sortedFeed.add(caughtUpIndex, StreamItem(type = "caught"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.subChannelsContainer.visibility = View.GONE
|
binding.subChannelsContainer.visibility = View.GONE
|
||||||
@ -158,6 +168,8 @@ class SubscriptionsFragment : BaseFragment() {
|
|||||||
showAllAtOnce = false
|
showAllAtOnce = false
|
||||||
)
|
)
|
||||||
binding.subFeed.adapter = subscriptionAdapter
|
binding.subFeed.adapter = subscriptionAdapter
|
||||||
|
|
||||||
|
PreferenceHelper.updateLastFeedWatchedTime()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showSubscriptions() {
|
private fun showSubscriptions() {
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
package com.github.libretube.ui.viewholders
|
package com.github.libretube.ui.viewholders
|
||||||
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.github.libretube.databinding.AllCaughtUpRowBinding
|
||||||
import com.github.libretube.databinding.TrendingRowBinding
|
import com.github.libretube.databinding.TrendingRowBinding
|
||||||
import com.github.libretube.databinding.VideoRowBinding
|
import com.github.libretube.databinding.VideoRowBinding
|
||||||
|
|
||||||
class VideosViewHolder : RecyclerView.ViewHolder {
|
class VideosViewHolder : RecyclerView.ViewHolder {
|
||||||
var trendingRowBinding: TrendingRowBinding? = null
|
var trendingRowBinding: TrendingRowBinding? = null
|
||||||
var videoRowBinding: VideoRowBinding? = null
|
var videoRowBinding: VideoRowBinding? = null
|
||||||
|
var allCaughtUpBinding: AllCaughtUpRowBinding? = null
|
||||||
|
|
||||||
constructor(binding: TrendingRowBinding) : super(binding.root) {
|
constructor(binding: TrendingRowBinding) : super(binding.root) {
|
||||||
trendingRowBinding = binding
|
trendingRowBinding = binding
|
||||||
@ -15,4 +17,8 @@ class VideosViewHolder : RecyclerView.ViewHolder {
|
|||||||
constructor(binding: VideoRowBinding) : super(binding.root) {
|
constructor(binding: VideoRowBinding) : super(binding.root) {
|
||||||
videoRowBinding = binding
|
videoRowBinding = binding
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constructor(binding: AllCaughtUpRowBinding) : super(binding.root) {
|
||||||
|
allCaughtUpBinding = binding
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import android.content.Context
|
|||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import com.github.libretube.constants.PreferenceKeys
|
import com.github.libretube.constants.PreferenceKeys
|
||||||
|
import java.time.Instant
|
||||||
|
|
||||||
object PreferenceHelper {
|
object PreferenceHelper {
|
||||||
/**
|
/**
|
||||||
@ -45,6 +46,10 @@ object PreferenceHelper {
|
|||||||
editor.putFloat(key, value).commit()
|
editor.putFloat(key, value).commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun putLong(key: String, value: Long) {
|
||||||
|
editor.putLong(key, value).commit()
|
||||||
|
}
|
||||||
|
|
||||||
fun getString(key: String?, defValue: String): String {
|
fun getString(key: String?, defValue: String): String {
|
||||||
return settings.getString(key, defValue) ?: defValue
|
return settings.getString(key, defValue) ?: defValue
|
||||||
}
|
}
|
||||||
@ -57,6 +62,10 @@ object PreferenceHelper {
|
|||||||
return settings.getInt(key, defValue)
|
return settings.getInt(key, defValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getLong(key: String?, defValue: Long): Long {
|
||||||
|
return settings.getLong(key, defValue)
|
||||||
|
}
|
||||||
|
|
||||||
fun getFloat(key: String?, defValue: Float): Float {
|
fun getFloat(key: String?, defValue: Float): Float {
|
||||||
return settings.getFloat(key, defValue)
|
return settings.getFloat(key, defValue)
|
||||||
}
|
}
|
||||||
@ -89,6 +98,14 @@ object PreferenceHelper {
|
|||||||
return getString(PreferenceKeys.LAST_STREAM_VIDEO_ID, "")
|
return getString(PreferenceKeys.LAST_STREAM_VIDEO_ID, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun updateLastFeedWatchedTime() {
|
||||||
|
putLong(PreferenceKeys.LAST_WATCHED_FEED_TIME, Instant.now().epochSecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getLastCheckedFeedTime(): Long {
|
||||||
|
return getLong(PreferenceKeys.LAST_WATCHED_FEED_TIME, 0)
|
||||||
|
}
|
||||||
|
|
||||||
fun saveErrorLog(log: String) {
|
fun saveErrorLog(log: String) {
|
||||||
editor.putString(PreferenceKeys.ERROR_LOG, log).commit()
|
editor.putString(PreferenceKeys.ERROR_LOG, log).commit()
|
||||||
}
|
}
|
||||||
|
18
app/src/main/res/drawable/ic_done.xml
Normal file
18
app/src/main/res/drawable/ic_done.xml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:aapt="http://schemas.android.com/aapt"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:tint="?attr/colorControlNormal"
|
||||||
|
android:viewportWidth="400"
|
||||||
|
android:viewportHeight="400">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M200,15.89C98.47,15.89 15.89,98.48 15.89,200 15.89,301.52 98.47,384.11 200,384.11 301.52,384.11 384.11,301.52 384.11,200 384.11,98.48 301.52,15.89 200,15.89ZM200,359.97C111.79,359.97 40.03,288.2 40.03,200c0,-88.21 71.76,-159.96 159.96,-159.96 88.21,0 159.97,71.76 159.97,159.96 0,88.2 -71.76,159.97 -159.97,159.97z"
|
||||||
|
android:strokeWidth="27"
|
||||||
|
android:strokeColor="#000000" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="m266.65,139.73 l-94.94,94.93 -38.38,-38.37c-4.72,-4.71 -12.36,-4.71 -17.07,0 -4.72,4.72 -4.72,12.36 0,17.07l46.91,46.91c2.36,2.35 5.45,3.53 8.53,3.53 3.09,0 6.19,-1.18 8.54,-3.54 0.01,-0.01 0.01,-0.02 0.02,-0.03L283.73,156.8c4.72,-4.71 4.72,-12.36 0,-17.07 -4.72,-4.72 -12.36,-4.72 -17.07,0z"
|
||||||
|
android:strokeWidth="27"
|
||||||
|
android:strokeColor="#000000" />
|
||||||
|
</vector>
|
35
app/src/main/res/layout/all_caught_up_row.xml
Normal file
35
app/src/main/res/layout/all_caught_up_row.xml
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingVertical="50dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="80dp"
|
||||||
|
android:layout_height="80dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
|
||||||
|
android:src="@drawable/ic_done"
|
||||||
|
android:tint="?attr/colorPrimary"
|
||||||
|
tools:ignore="UseAppTint" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:text="@string/all_caught_up"
|
||||||
|
android:textColor="?android:attr/textColorPrimary" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:textSize="13sp"
|
||||||
|
android:text="@string/all_caught_up_summary"
|
||||||
|
android:textColor="?attr/colorControlNormal" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
@ -401,6 +401,8 @@
|
|||||||
<string name="captions_size">Captions size</string>
|
<string name="captions_size">Captions size</string>
|
||||||
<string name="double_tap_seek">Double tap to seek</string>
|
<string name="double_tap_seek">Double tap to seek</string>
|
||||||
<string name="double_tap_seek_summary">Tap twice at the left or right to rewind or forward the player position.</string>
|
<string name="double_tap_seek_summary">Tap twice at the left or right to rewind or forward the player position.</string>
|
||||||
|
<string name="all_caught_up">You\'re all caught up</string>
|
||||||
|
<string name="all_caught_up_summary">You\'ve seen all new videos</string>
|
||||||
|
|
||||||
<!-- Notification channel strings -->
|
<!-- Notification channel strings -->
|
||||||
<string name="download_channel_name">Download Service</string>
|
<string name="download_channel_name">Download Service</string>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user