First draft of the new feature

This commit is contained in:
Jared Fantaye 2023-01-30 22:37:24 +01:00
parent fceec71ad3
commit d2d324f2dd
9 changed files with 87 additions and 44 deletions

View File

@ -32,6 +32,7 @@ abstract class FeedDAO {
* @return the feed streams filtered according to the conditions provided in the parameters * @return the feed streams filtered according to the conditions provided in the parameters
* @see StreamStateEntity.isFinished() * @see StreamStateEntity.isFinished()
* @see StreamStateEntity.PLAYBACK_FINISHED_END_MILLISECONDS * @see StreamStateEntity.PLAYBACK_FINISHED_END_MILLISECONDS
* @see StreamStateEntity.PLAYBACK_SAVE_THRESHOLD_START_MILLISECONDS
*/ */
@Query( @Query(
""" """
@ -66,6 +67,13 @@ abstract class FeedDAO {
OR s.stream_type = 'LIVE_STREAM' OR s.stream_type = 'LIVE_STREAM'
OR s.stream_type = 'AUDIO_LIVE_STREAM' OR s.stream_type = 'AUDIO_LIVE_STREAM'
) )
AND (
:includePartiallyPlayed
OR sh.stream_id IS NULL
OR sst.stream_id IS NULL
OR (sst.progress_time < ${StreamStateEntity.PLAYBACK_SAVE_THRESHOLD_START_MILLISECONDS}
AND sst.progress_time < s.duration * 1000 / 4)
)
AND ( AND (
:uploadDateBefore IS NULL :uploadDateBefore IS NULL
OR s.upload_date IS NULL OR s.upload_date IS NULL
@ -79,6 +87,7 @@ abstract class FeedDAO {
abstract fun getStreams( abstract fun getStreams(
groupId: Long, groupId: Long,
includePlayed: Boolean, includePlayed: Boolean,
includePartiallyPlayed: Boolean,
uploadDateBefore: OffsetDateTime? uploadDateBefore: OffsetDateTime?
): Maybe<List<StreamWithState>> ): Maybe<List<StreamWithState>>

View File

@ -30,7 +30,7 @@ public class StreamStateEntity {
/** /**
* Playback state will not be saved, if playback time is less than this threshold (5000ms = 5s). * Playback state will not be saved, if playback time is less than this threshold (5000ms = 5s).
*/ */
private static final long PLAYBACK_SAVE_THRESHOLD_START_MILLISECONDS = 5000; public static final long PLAYBACK_SAVE_THRESHOLD_START_MILLISECONDS = 5000;
/** /**
* Stream will be considered finished if the playback time left exceeds this threshold * Stream will be considered finished if the playback time left exceeds this threshold

View File

@ -43,11 +43,13 @@ class FeedDatabaseManager(context: Context) {
fun getStreams( fun getStreams(
groupId: Long, groupId: Long,
includePlayedStreams: Boolean, includePlayedStreams: Boolean,
includePartiallyPlayedStreams: Boolean,
includeFutureStreams: Boolean includeFutureStreams: Boolean
): Maybe<List<StreamWithState>> { ): Maybe<List<StreamWithState>> {
return feedTable.getStreams( return feedTable.getStreams(
groupId, groupId,
includePlayedStreams, includePlayedStreams,
includePartiallyPlayedStreams,
if (includeFutureStreams) null else OffsetDateTime.now() if (includeFutureStreams) null else OffsetDateTime.now()
) )
} }

View File

@ -100,7 +100,7 @@ class FeedFragment : BaseStateFragment<FeedState>() {
private var oldestSubscriptionUpdate: OffsetDateTime? = null private var oldestSubscriptionUpdate: OffsetDateTime? = null
private lateinit var groupAdapter: GroupieAdapter private lateinit var groupAdapter: GroupieAdapter
@State @JvmField var showPlayedItems: Boolean = true @State @JvmField var showPlayedItems: ShowItems = ShowItems.DEFAULT
@State @JvmField var showFutureItems: Boolean = true @State @JvmField var showFutureItems: Boolean = true
private var onSettingsChangeListener: SharedPreferences.OnSharedPreferenceChangeListener? = null private var onSettingsChangeListener: SharedPreferences.OnSharedPreferenceChangeListener? = null
@ -140,7 +140,7 @@ class FeedFragment : BaseStateFragment<FeedState>() {
val factory = FeedViewModel.getFactory(requireContext(), groupId) val factory = FeedViewModel.getFactory(requireContext(), groupId)
viewModel = ViewModelProvider(this, factory)[FeedViewModel::class.java] viewModel = ViewModelProvider(this, factory)[FeedViewModel::class.java]
showPlayedItems = viewModel.getShowPlayedItemsFromPreferences() showPlayedItems = viewModel.getItemsVisibilityFromPreferences()
showFutureItems = viewModel.getShowFutureItemsFromPreferences() showFutureItems = viewModel.getShowFutureItemsFromPreferences()
viewModel.stateLiveData.observe(viewLifecycleOwner) { it?.let(::handleResult) } viewModel.stateLiveData.observe(viewLifecycleOwner) { it?.let(::handleResult) }
@ -242,11 +242,12 @@ class FeedFragment : BaseStateFragment<FeedState>() {
.create() .create()
.show() .show()
return true return true
} else if (item.itemId == R.id.menu_item_feed_toggle_played_items) { } else if (item.itemId == R.id.menu_item_feed_toggle_show_all_items) {
showPlayedItems = !item.isChecked setShowPlayedItemsMethod(item, ShowItems.DEFAULT)
updateTogglePlayedItemsButton(item) } else if (item.itemId == R.id.menu_item_feed_toggle_show_played_items) {
viewModel.togglePlayedItems(showPlayedItems) setShowPlayedItemsMethod(item, ShowItems.WATCHED)
viewModel.saveShowPlayedItemsToPreferences(showPlayedItems) } else if (item.itemId == R.id.menu_item_feed_toggle_partially_played_items) {
setShowPlayedItemsMethod(item, ShowItems.PARTIALLY_WATCHED)
} else if (item.itemId == R.id.menu_item_feed_toggle_future_items) { } else if (item.itemId == R.id.menu_item_feed_toggle_future_items) {
showFutureItems = !item.isChecked showFutureItems = !item.isChecked
updateToggleFutureItemsButton(item) updateToggleFutureItemsButton(item)
@ -257,6 +258,13 @@ class FeedFragment : BaseStateFragment<FeedState>() {
return super.onOptionsItemSelected(item) return super.onOptionsItemSelected(item)
} }
private fun setShowPlayedItemsMethod(item: MenuItem, showItems: ShowItems) {
showPlayedItems = showItems
viewModel.togglePlayedItems(showPlayedItems)
updateTogglePlayedItemsButton(item)
viewModel.saveShowPlayedItemsToPreferences(showPlayedItems)
}
override fun onDestroyOptionsMenu() { override fun onDestroyOptionsMenu() {
super.onDestroyOptionsMenu() super.onDestroyOptionsMenu()
activity?.supportActionBar?.subtitle = null activity?.supportActionBar?.subtitle = null
@ -284,19 +292,9 @@ class FeedFragment : BaseStateFragment<FeedState>() {
} }
private fun updateTogglePlayedItemsButton(menuItem: MenuItem) { private fun updateTogglePlayedItemsButton(menuItem: MenuItem) {
menuItem.isChecked = showPlayedItems
menuItem.icon = AppCompatResources.getDrawable(
requireContext(),
if (showPlayedItems) R.drawable.ic_visibility_on else R.drawable.ic_visibility_off
)
MenuItemCompat.setTooltipText( MenuItemCompat.setTooltipText(
menuItem, menuItem,
getString( getString(R.string.feed_toggle_show_hide_played_items)
if (showPlayedItems)
R.string.feed_toggle_hide_played_items
else
R.string.feed_toggle_show_played_items
)
) )
} }

View File

@ -28,15 +28,18 @@ import org.schabi.newpipe.util.DEFAULT_THROTTLE_TIMEOUT
import java.time.OffsetDateTime import java.time.OffsetDateTime
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
enum class ShowItems {
WATCHED, PARTIALLY_WATCHED, DEFAULT
}
class FeedViewModel( class FeedViewModel(
private val application: Application, private val application: Application,
groupId: Long = FeedGroupEntity.GROUP_ALL_ID, groupId: Long = FeedGroupEntity.GROUP_ALL_ID,
initialShowPlayedItems: Boolean = true, initialShowPlayedItems: ShowItems = ShowItems.DEFAULT,
initialShowFutureItems: Boolean = true initialShowFutureItems: Boolean = true
) : ViewModel() { ) : ViewModel() {
private val feedDatabaseManager = FeedDatabaseManager(application) private val feedDatabaseManager = FeedDatabaseManager(application)
private val toggleShowPlayedItems = BehaviorProcessor.create<Boolean>() private val toggleShowPlayedItems = BehaviorProcessor.create<ShowItems>()
private val toggleShowPlayedItemsFlowable = toggleShowPlayedItems private val toggleShowPlayedItemsFlowable = toggleShowPlayedItems
.startWithItem(initialShowPlayedItems) .startWithItem(initialShowPlayedItems)
.distinctUntilChanged() .distinctUntilChanged()
@ -57,7 +60,7 @@ class FeedViewModel(
feedDatabaseManager.notLoadedCount(groupId), feedDatabaseManager.notLoadedCount(groupId),
feedDatabaseManager.oldestSubscriptionUpdate(groupId), feedDatabaseManager.oldestSubscriptionUpdate(groupId),
Function5 { t1: FeedEventManager.Event, t2: Boolean, t3: Boolean, Function5 { t1: FeedEventManager.Event, t2: ShowItems, t3: Boolean,
t4: Long, t5: List<OffsetDateTime> -> t4: Long, t5: List<OffsetDateTime> ->
return@Function5 CombineResultEventHolder(t1, t2, t3, t4, t5.firstOrNull()) return@Function5 CombineResultEventHolder(t1, t2, t3, t4, t5.firstOrNull())
} }
@ -66,12 +69,21 @@ class FeedViewModel(
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(Schedulers.io()) .observeOn(Schedulers.io())
.map { (event, showPlayedItems, showFutureItems, notLoadedCount, oldestUpdate) -> .map { (event, showPlayedItems, showFutureItems, notLoadedCount, oldestUpdate) ->
val streamItems = if (event is SuccessResultEvent || event is IdleEvent) val streamItems = if (event is SuccessResultEvent || event is IdleEvent) {
feedDatabaseManager feedDatabaseManager
.getStreams(groupId, showPlayedItems, showFutureItems) .getStreams(
groupId,
!(
showPlayedItems == ShowItems.WATCHED ||
showPlayedItems == ShowItems.PARTIALLY_WATCHED
),
showPlayedItems != ShowItems.PARTIALLY_WATCHED,
showFutureItems
)
.blockingGet(arrayListOf()) .blockingGet(arrayListOf())
else } else {
arrayListOf() arrayListOf()
}
CombineResultDataHolder(event, streamItems, notLoadedCount, oldestUpdate) CombineResultDataHolder(event, streamItems, notLoadedCount, oldestUpdate)
} }
@ -98,7 +110,7 @@ class FeedViewModel(
private data class CombineResultEventHolder( private data class CombineResultEventHolder(
val t1: FeedEventManager.Event, val t1: FeedEventManager.Event,
val t2: Boolean, val t2: ShowItems,
val t3: Boolean, val t3: Boolean,
val t4: Long, val t4: Long,
val t5: OffsetDateTime? val t5: OffsetDateTime?
@ -111,17 +123,20 @@ class FeedViewModel(
val t4: OffsetDateTime? val t4: OffsetDateTime?
) )
fun togglePlayedItems(showPlayedItems: Boolean) { fun togglePlayedItems(showItems: ShowItems) {
toggleShowPlayedItems.onNext(showPlayedItems) toggleShowPlayedItems.onNext(showItems)
} }
fun saveShowPlayedItemsToPreferences(showPlayedItems: Boolean) = fun saveShowPlayedItemsToPreferences(showItems: ShowItems) =
PreferenceManager.getDefaultSharedPreferences(application).edit { PreferenceManager.getDefaultSharedPreferences(application).edit {
this.putBoolean(application.getString(R.string.feed_show_played_items_key), showPlayedItems) this.putString(
application.getString(R.string.feed_show_played_items_key),
showItems.toString()
)
this.apply() this.apply()
} }
fun getShowPlayedItemsFromPreferences() = getShowPlayedItemsFromPreferences(application) fun getItemsVisibilityFromPreferences() = getItemsVisibilityFromPreferences(application)
fun toggleFutureItems(showFutureItems: Boolean) { fun toggleFutureItems(showFutureItems: Boolean) {
toggleShowFutureItems.onNext(showFutureItems) toggleShowFutureItems.onNext(showFutureItems)
@ -136,9 +151,16 @@ class FeedViewModel(
fun getShowFutureItemsFromPreferences() = getShowFutureItemsFromPreferences(application) fun getShowFutureItemsFromPreferences() = getShowFutureItemsFromPreferences(application)
companion object { companion object {
private fun getShowPlayedItemsFromPreferences(context: Context) =
PreferenceManager.getDefaultSharedPreferences(context) private fun getItemsVisibilityFromPreferences(context: Context): ShowItems {
.getBoolean(context.getString(R.string.feed_show_played_items_key), true) val s = PreferenceManager.getDefaultSharedPreferences(context)
.getString(
context.getString(R.string.feed_show_played_items_key),
ShowItems.DEFAULT.toString()
) ?: ShowItems.DEFAULT.toString()
return ShowItems.valueOf(s)
}
private fun getShowFutureItemsFromPreferences(context: Context) = private fun getShowFutureItemsFromPreferences(context: Context) =
PreferenceManager.getDefaultSharedPreferences(context) PreferenceManager.getDefaultSharedPreferences(context)
.getBoolean(context.getString(R.string.feed_show_future_items_key), true) .getBoolean(context.getString(R.string.feed_show_future_items_key), true)
@ -148,7 +170,7 @@ class FeedViewModel(
App.getApp(), App.getApp(),
groupId, groupId,
// Read initial value from preferences // Read initial value from preferences
getShowPlayedItemsFromPreferences(context.applicationContext), getItemsVisibilityFromPreferences(context.applicationContext),
getShowFutureItemsFromPreferences(context.applicationContext) getShowFutureItemsFromPreferences(context.applicationContext)
) )
} }

View File

@ -4,12 +4,23 @@
<item <item
android:id="@+id/menu_item_feed_toggle_played_items" android:id="@+id/menu_item_feed_toggle_played_items"
android:orderInCategory="2" android:checkable="false"
android:checkable="true" android:checked="false"
android:checked="true"
android:icon="@drawable/ic_visibility_on" android:icon="@drawable/ic_visibility_on"
android:title="@string/feed_toggle_show_played_items" android:title="@string/feed_toggle_show_hide_played_items"
app:showAsAction="ifRoom" /> app:showAsAction="ifRoom">
<menu>
<item
android:id="@+id/menu_item_feed_toggle_show_all_items"
android:title="@string/feed_toggle_show_items"/>
<item
android:id="@+id/menu_item_feed_toggle_show_played_items"
android:title="@string/feed_toggle_show_watched_items"/>
<item
android:id="@+id/menu_item_feed_toggle_partially_played_items"
android:title="@string/feed_toggle_show_partially_watched_items"/>
</menu>
</item>
<item <item
android:id="@+id/menu_item_feed_toggle_future_items" android:id="@+id/menu_item_feed_toggle_future_items"

View File

@ -283,7 +283,7 @@
<string name="feed_update_threshold_key">feed_update_threshold_key</string> <string name="feed_update_threshold_key">feed_update_threshold_key</string>
<string name="feed_update_threshold_default_value">300</string> <string name="feed_update_threshold_default_value">300</string>
<string name="feed_show_played_items_key">feed_show_played_items</string> <string name="feed_show_played_items_key">feed_show_items</string>
<string name="feed_show_future_items_key">feed_show_future_items</string> <string name="feed_show_future_items_key">feed_show_future_items</string>
<string name="show_thumbnail_key">show_thumbnail_key</string> <string name="show_thumbnail_key">show_thumbnail_key</string>

View File

@ -691,8 +691,7 @@
\nYouTube is an example of a service that offers this fast method with its RSS feed. \nYouTube is an example of a service that offers this fast method with its RSS feed.
\n \n
\nSo the choice boils down to what you prefer: speed or precise information.</string> \nSo the choice boils down to what you prefer: speed or precise information.</string>
<string name="feed_toggle_show_played_items">Show watched items</string> <string name="feed_toggle_show_hide_played_items">Show/hide watched items</string>
<string name="feed_toggle_hide_played_items">Hide watched items</string>
<string name="content_not_supported">This content is not yet supported by NewPipe.\n\nIt will hopefully be supported in a future version.</string> <string name="content_not_supported">This content is not yet supported by NewPipe.\n\nIt will hopefully be supported in a future version.</string>
<string name="detail_sub_channel_thumbnail_view_description">Channel\'s avatar thumbnail</string> <string name="detail_sub_channel_thumbnail_view_description">Channel\'s avatar thumbnail</string>
<string name="channel_created_by">Created by %s</string> <string name="channel_created_by">Created by %s</string>
@ -760,5 +759,8 @@
<string name="unknown_quality">Unknown quality</string> <string name="unknown_quality">Unknown quality</string>
<string name="feed_toggle_show_future_items">Show future items</string> <string name="feed_toggle_show_future_items">Show future items</string>
<string name="feed_toggle_hide_future_items">Hide future items</string> <string name="feed_toggle_hide_future_items">Hide future items</string>
<string name="feed_toggle_show_partially_watched_items">Hide Watched and Partially Watched </string>
<string name="feed_toggle_show_watched_items">Hide Watched</string>
<string name="feed_toggle_show_items">Show All</string>
<string name="sort">Sort</string> <string name="sort">Sort</string>
</resources> </resources>

View File

@ -1,6 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
distributionSha256Sum=f6b8596b10cce501591e92f229816aa4046424f3b24d771751b06779d58c8ec4
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists