From d2d324f2dd006feeac213c67fcb5ab3c56821e44 Mon Sep 17 00:00:00 2001 From: Jared Fantaye Date: Mon, 30 Jan 2023 22:37:24 +0100 Subject: [PATCH 1/6] First draft of the new feature --- .../newpipe/database/feed/dao/FeedDAO.kt | 9 ++++ .../stream/model/StreamStateEntity.java | 2 +- .../newpipe/local/feed/FeedDatabaseManager.kt | 2 + .../schabi/newpipe/local/feed/FeedFragment.kt | 34 ++++++------ .../newpipe/local/feed/FeedViewModel.kt | 54 +++++++++++++------ app/src/main/res/menu/menu_feed_fragment.xml | 21 ++++++-- app/src/main/res/values/settings_keys.xml | 2 +- app/src/main/res/values/strings.xml | 6 ++- gradle/wrapper/gradle-wrapper.properties | 1 - 9 files changed, 87 insertions(+), 44 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/database/feed/dao/FeedDAO.kt b/app/src/main/java/org/schabi/newpipe/database/feed/dao/FeedDAO.kt index 968d0c88f..4faafb2ea 100644 --- a/app/src/main/java/org/schabi/newpipe/database/feed/dao/FeedDAO.kt +++ b/app/src/main/java/org/schabi/newpipe/database/feed/dao/FeedDAO.kt @@ -32,6 +32,7 @@ abstract class FeedDAO { * @return the feed streams filtered according to the conditions provided in the parameters * @see StreamStateEntity.isFinished() * @see StreamStateEntity.PLAYBACK_FINISHED_END_MILLISECONDS + * @see StreamStateEntity.PLAYBACK_SAVE_THRESHOLD_START_MILLISECONDS */ @Query( """ @@ -66,6 +67,13 @@ abstract class FeedDAO { OR s.stream_type = '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 ( :uploadDateBefore IS NULL OR s.upload_date IS NULL @@ -79,6 +87,7 @@ abstract class FeedDAO { abstract fun getStreams( groupId: Long, includePlayed: Boolean, + includePartiallyPlayed: Boolean, uploadDateBefore: OffsetDateTime? ): Maybe> diff --git a/app/src/main/java/org/schabi/newpipe/database/stream/model/StreamStateEntity.java b/app/src/main/java/org/schabi/newpipe/database/stream/model/StreamStateEntity.java index 75766850f..627acea45 100644 --- a/app/src/main/java/org/schabi/newpipe/database/stream/model/StreamStateEntity.java +++ b/app/src/main/java/org/schabi/newpipe/database/stream/model/StreamStateEntity.java @@ -30,7 +30,7 @@ public class StreamStateEntity { /** * 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 diff --git a/app/src/main/java/org/schabi/newpipe/local/feed/FeedDatabaseManager.kt b/app/src/main/java/org/schabi/newpipe/local/feed/FeedDatabaseManager.kt index 07edb0499..ed65d4048 100644 --- a/app/src/main/java/org/schabi/newpipe/local/feed/FeedDatabaseManager.kt +++ b/app/src/main/java/org/schabi/newpipe/local/feed/FeedDatabaseManager.kt @@ -43,11 +43,13 @@ class FeedDatabaseManager(context: Context) { fun getStreams( groupId: Long, includePlayedStreams: Boolean, + includePartiallyPlayedStreams: Boolean, includeFutureStreams: Boolean ): Maybe> { return feedTable.getStreams( groupId, includePlayedStreams, + includePartiallyPlayedStreams, if (includeFutureStreams) null else OffsetDateTime.now() ) } diff --git a/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt b/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt index 2bb2f9986..07421a8ea 100644 --- a/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt +++ b/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt @@ -100,7 +100,7 @@ class FeedFragment : BaseStateFragment() { private var oldestSubscriptionUpdate: OffsetDateTime? = null private lateinit var groupAdapter: GroupieAdapter - @State @JvmField var showPlayedItems: Boolean = true + @State @JvmField var showPlayedItems: ShowItems = ShowItems.DEFAULT @State @JvmField var showFutureItems: Boolean = true private var onSettingsChangeListener: SharedPreferences.OnSharedPreferenceChangeListener? = null @@ -140,7 +140,7 @@ class FeedFragment : BaseStateFragment() { val factory = FeedViewModel.getFactory(requireContext(), groupId) viewModel = ViewModelProvider(this, factory)[FeedViewModel::class.java] - showPlayedItems = viewModel.getShowPlayedItemsFromPreferences() + showPlayedItems = viewModel.getItemsVisibilityFromPreferences() showFutureItems = viewModel.getShowFutureItemsFromPreferences() viewModel.stateLiveData.observe(viewLifecycleOwner) { it?.let(::handleResult) } @@ -242,11 +242,12 @@ class FeedFragment : BaseStateFragment() { .create() .show() return true - } else if (item.itemId == R.id.menu_item_feed_toggle_played_items) { - showPlayedItems = !item.isChecked - updateTogglePlayedItemsButton(item) - viewModel.togglePlayedItems(showPlayedItems) - viewModel.saveShowPlayedItemsToPreferences(showPlayedItems) + } else if (item.itemId == R.id.menu_item_feed_toggle_show_all_items) { + setShowPlayedItemsMethod(item, ShowItems.DEFAULT) + } else if (item.itemId == R.id.menu_item_feed_toggle_show_played_items) { + setShowPlayedItemsMethod(item, ShowItems.WATCHED) + } 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) { showFutureItems = !item.isChecked updateToggleFutureItemsButton(item) @@ -257,6 +258,13 @@ class FeedFragment : BaseStateFragment() { return super.onOptionsItemSelected(item) } + private fun setShowPlayedItemsMethod(item: MenuItem, showItems: ShowItems) { + showPlayedItems = showItems + viewModel.togglePlayedItems(showPlayedItems) + updateTogglePlayedItemsButton(item) + viewModel.saveShowPlayedItemsToPreferences(showPlayedItems) + } + override fun onDestroyOptionsMenu() { super.onDestroyOptionsMenu() activity?.supportActionBar?.subtitle = null @@ -284,19 +292,9 @@ class FeedFragment : BaseStateFragment() { } 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( menuItem, - getString( - if (showPlayedItems) - R.string.feed_toggle_hide_played_items - else - R.string.feed_toggle_show_played_items - ) + getString(R.string.feed_toggle_show_hide_played_items) ) } diff --git a/app/src/main/java/org/schabi/newpipe/local/feed/FeedViewModel.kt b/app/src/main/java/org/schabi/newpipe/local/feed/FeedViewModel.kt index 76d5e9d63..5785c8e3f 100644 --- a/app/src/main/java/org/schabi/newpipe/local/feed/FeedViewModel.kt +++ b/app/src/main/java/org/schabi/newpipe/local/feed/FeedViewModel.kt @@ -28,15 +28,18 @@ import org.schabi.newpipe.util.DEFAULT_THROTTLE_TIMEOUT import java.time.OffsetDateTime import java.util.concurrent.TimeUnit +enum class ShowItems { + WATCHED, PARTIALLY_WATCHED, DEFAULT +} class FeedViewModel( private val application: Application, groupId: Long = FeedGroupEntity.GROUP_ALL_ID, - initialShowPlayedItems: Boolean = true, + initialShowPlayedItems: ShowItems = ShowItems.DEFAULT, initialShowFutureItems: Boolean = true ) : ViewModel() { private val feedDatabaseManager = FeedDatabaseManager(application) - private val toggleShowPlayedItems = BehaviorProcessor.create() + private val toggleShowPlayedItems = BehaviorProcessor.create() private val toggleShowPlayedItemsFlowable = toggleShowPlayedItems .startWithItem(initialShowPlayedItems) .distinctUntilChanged() @@ -57,7 +60,7 @@ class FeedViewModel( feedDatabaseManager.notLoadedCount(groupId), feedDatabaseManager.oldestSubscriptionUpdate(groupId), - Function5 { t1: FeedEventManager.Event, t2: Boolean, t3: Boolean, + Function5 { t1: FeedEventManager.Event, t2: ShowItems, t3: Boolean, t4: Long, t5: List -> return@Function5 CombineResultEventHolder(t1, t2, t3, t4, t5.firstOrNull()) } @@ -66,12 +69,21 @@ class FeedViewModel( .subscribeOn(Schedulers.io()) .observeOn(Schedulers.io()) .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 - .getStreams(groupId, showPlayedItems, showFutureItems) + .getStreams( + groupId, + !( + showPlayedItems == ShowItems.WATCHED || + showPlayedItems == ShowItems.PARTIALLY_WATCHED + ), + showPlayedItems != ShowItems.PARTIALLY_WATCHED, + showFutureItems + ) .blockingGet(arrayListOf()) - else + } else { arrayListOf() + } CombineResultDataHolder(event, streamItems, notLoadedCount, oldestUpdate) } @@ -98,7 +110,7 @@ class FeedViewModel( private data class CombineResultEventHolder( val t1: FeedEventManager.Event, - val t2: Boolean, + val t2: ShowItems, val t3: Boolean, val t4: Long, val t5: OffsetDateTime? @@ -111,17 +123,20 @@ class FeedViewModel( val t4: OffsetDateTime? ) - fun togglePlayedItems(showPlayedItems: Boolean) { - toggleShowPlayedItems.onNext(showPlayedItems) + fun togglePlayedItems(showItems: ShowItems) { + toggleShowPlayedItems.onNext(showItems) } - fun saveShowPlayedItemsToPreferences(showPlayedItems: Boolean) = + fun saveShowPlayedItemsToPreferences(showItems: ShowItems) = 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() } - fun getShowPlayedItemsFromPreferences() = getShowPlayedItemsFromPreferences(application) + fun getItemsVisibilityFromPreferences() = getItemsVisibilityFromPreferences(application) fun toggleFutureItems(showFutureItems: Boolean) { toggleShowFutureItems.onNext(showFutureItems) @@ -136,9 +151,16 @@ class FeedViewModel( fun getShowFutureItemsFromPreferences() = getShowFutureItemsFromPreferences(application) companion object { - private fun getShowPlayedItemsFromPreferences(context: Context) = - PreferenceManager.getDefaultSharedPreferences(context) - .getBoolean(context.getString(R.string.feed_show_played_items_key), true) + + private fun getItemsVisibilityFromPreferences(context: Context): ShowItems { + 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) = PreferenceManager.getDefaultSharedPreferences(context) .getBoolean(context.getString(R.string.feed_show_future_items_key), true) @@ -148,7 +170,7 @@ class FeedViewModel( App.getApp(), groupId, // Read initial value from preferences - getShowPlayedItemsFromPreferences(context.applicationContext), + getItemsVisibilityFromPreferences(context.applicationContext), getShowFutureItemsFromPreferences(context.applicationContext) ) } diff --git a/app/src/main/res/menu/menu_feed_fragment.xml b/app/src/main/res/menu/menu_feed_fragment.xml index 9e5cc862e..fc371b2fe 100644 --- a/app/src/main/res/menu/menu_feed_fragment.xml +++ b/app/src/main/res/menu/menu_feed_fragment.xml @@ -4,12 +4,23 @@ + android:title="@string/feed_toggle_show_hide_played_items" + app:showAsAction="ifRoom"> + + + + + + feed_update_threshold_key 300 - feed_show_played_items + feed_show_items feed_show_future_items show_thumbnail_key diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5a4ce92f2..46a3cad74 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -691,8 +691,7 @@ \nYouTube is an example of a service that offers this fast method with its RSS feed. \n \nSo the choice boils down to what you prefer: speed or precise information. - Show watched items - Hide watched items + Show/hide watched items This content is not yet supported by NewPipe.\n\nIt will hopefully be supported in a future version. Channel\'s avatar thumbnail Created by %s @@ -760,5 +759,8 @@ Unknown quality Show future items Hide future items + Hide Watched and Partially Watched + Hide Watched + Show All Sort \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 5116c5b18..ae04661ee 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip -distributionSha256Sum=f6b8596b10cce501591e92f229816aa4046424f3b24d771751b06779d58c8ec4 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 3d36eb5bafb5945f3a649746d437358f22701f81 Mon Sep 17 00:00:00 2001 From: Jared Fantaye Date: Mon, 30 Jan 2023 22:39:16 +0100 Subject: [PATCH 2/6] Fixed a small commit mistake --- gradle/wrapper/gradle-wrapper.properties | 1 + 1 file changed, 1 insertion(+) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ae04661ee..5116c5b18 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip +distributionSha256Sum=f6b8596b10cce501591e92f229816aa4046424f3b24d771751b06779d58c8ec4 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 9c82441c1911a3c0e45020464bbaca8005599764 Mon Sep 17 00:00:00 2001 From: Jared Fantaye Date: Wed, 1 Feb 2023 23:10:31 +0100 Subject: [PATCH 3/6] Implemented the feature and fixed some small issues --- .../newpipe/database/feed/dao/FeedDAO.kt | 4 +- .../schabi/newpipe/local/feed/FeedFragment.kt | 56 ++++++++++++++----- .../newpipe/local/feed/FeedViewModel.kt | 47 ++++++++-------- .../local/feed/StreamVisibilityStatus.kt | 5 ++ .../local/history/HistoryRecordManager.java | 2 +- app/src/main/res/menu/menu_feed_fragment.xml | 8 +-- app/src/main/res/values/settings_keys.xml | 2 +- app/src/main/res/values/strings.xml | 8 +-- 8 files changed, 82 insertions(+), 50 deletions(-) create mode 100644 app/src/main/java/org/schabi/newpipe/local/feed/StreamVisibilityStatus.kt diff --git a/app/src/main/java/org/schabi/newpipe/database/feed/dao/FeedDAO.kt b/app/src/main/java/org/schabi/newpipe/database/feed/dao/FeedDAO.kt index 4faafb2ea..a53e5cac1 100644 --- a/app/src/main/java/org/schabi/newpipe/database/feed/dao/FeedDAO.kt +++ b/app/src/main/java/org/schabi/newpipe/database/feed/dao/FeedDAO.kt @@ -71,8 +71,8 @@ abstract class FeedDAO { :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) + OR (sst.progress_time <= ${StreamStateEntity.PLAYBACK_SAVE_THRESHOLD_START_MILLISECONDS} + AND sst.progress_time <= s.duration * 1000 / 4) ) AND ( :uploadDateBefore IS NULL diff --git a/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt b/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt index 07421a8ea..9358c1654 100644 --- a/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt +++ b/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt @@ -100,9 +100,13 @@ class FeedFragment : BaseStateFragment() { private var oldestSubscriptionUpdate: OffsetDateTime? = null private lateinit var groupAdapter: GroupieAdapter - @State @JvmField var showPlayedItems: ShowItems = ShowItems.DEFAULT + @State @JvmField var feedVisibilityStatus: StreamVisibilityStatus = StreamVisibilityStatus.DEFAULT @State @JvmField var showFutureItems: Boolean = true + private lateinit var showAllMenuItem: MenuItem + private lateinit var hideWatchedMenuItem: MenuItem + private lateinit var hidePartiallyWatchedMenuItem: MenuItem + private var onSettingsChangeListener: SharedPreferences.OnSharedPreferenceChangeListener? = null private var updateListViewModeOnResume = false private var isRefreshing = false @@ -140,7 +144,7 @@ class FeedFragment : BaseStateFragment() { val factory = FeedViewModel.getFactory(requireContext(), groupId) viewModel = ViewModelProvider(this, factory)[FeedViewModel::class.java] - showPlayedItems = viewModel.getItemsVisibilityFromPreferences() + feedVisibilityStatus = viewModel.getItemsVisibilityFromPreferences() showFutureItems = viewModel.getShowFutureItemsFromPreferences() viewModel.stateLiveData.observe(viewLifecycleOwner) { it?.let(::handleResult) } @@ -216,7 +220,15 @@ class FeedFragment : BaseStateFragment() { activity.supportActionBar?.subtitle = groupName inflater.inflate(R.menu.menu_feed_fragment, menu) - updateTogglePlayedItemsButton(menu.findItem(R.id.menu_item_feed_toggle_played_items)) + + val itemVisibilityMenu = menu.findItem(R.id.menu_item_feed_toggle_played_items).subMenu + if (itemVisibilityMenu != null) { + showAllMenuItem = itemVisibilityMenu.findItem(R.id.menu_item_feed_toggle_show_all_items) + hideWatchedMenuItem = itemVisibilityMenu.findItem(R.id.menu_item_feed_toggle_show_played_items) + hidePartiallyWatchedMenuItem = itemVisibilityMenu.findItem(R.id.menu_item_feed_toggle_partially_played_items) + } + + updateItemVisibilityMenu(menu.findItem(R.id.menu_item_feed_toggle_played_items)) updateToggleFutureItemsButton(menu.findItem(R.id.menu_item_feed_toggle_future_items)) } @@ -243,11 +255,11 @@ class FeedFragment : BaseStateFragment() { .show() return true } else if (item.itemId == R.id.menu_item_feed_toggle_show_all_items) { - setShowPlayedItemsMethod(item, ShowItems.DEFAULT) + changeItemsVisibilityStatus(item, StreamVisibilityStatus.DEFAULT) } else if (item.itemId == R.id.menu_item_feed_toggle_show_played_items) { - setShowPlayedItemsMethod(item, ShowItems.WATCHED) + changeItemsVisibilityStatus(item, StreamVisibilityStatus.HIDE_WATCHED) } else if (item.itemId == R.id.menu_item_feed_toggle_partially_played_items) { - setShowPlayedItemsMethod(item, ShowItems.PARTIALLY_WATCHED) + changeItemsVisibilityStatus(item, StreamVisibilityStatus.HIDE_PARTIALLY_WATCHED) } else if (item.itemId == R.id.menu_item_feed_toggle_future_items) { showFutureItems = !item.isChecked updateToggleFutureItemsButton(item) @@ -258,11 +270,11 @@ class FeedFragment : BaseStateFragment() { return super.onOptionsItemSelected(item) } - private fun setShowPlayedItemsMethod(item: MenuItem, showItems: ShowItems) { - showPlayedItems = showItems - viewModel.togglePlayedItems(showPlayedItems) - updateTogglePlayedItemsButton(item) - viewModel.saveShowPlayedItemsToPreferences(showPlayedItems) + private fun changeItemsVisibilityStatus(item: MenuItem, streamVisibilityStatus: StreamVisibilityStatus) { + feedVisibilityStatus = streamVisibilityStatus + viewModel.changeVisibilityState(feedVisibilityStatus) + updateItemVisibilityMenu(item) + viewModel.saveStreamVisibilityStateToPreferences(feedVisibilityStatus) } override fun onDestroyOptionsMenu() { @@ -291,10 +303,28 @@ class FeedFragment : BaseStateFragment() { super.onDestroyView() } - private fun updateTogglePlayedItemsButton(menuItem: MenuItem) { + private fun updateItemVisibilityMenu(menuItem: MenuItem) { + when (feedVisibilityStatus) { + StreamVisibilityStatus.DEFAULT -> { + showAllMenuItem.isVisible = false + hideWatchedMenuItem.isVisible = true + hidePartiallyWatchedMenuItem.isVisible = true + } + StreamVisibilityStatus.HIDE_WATCHED -> { + showAllMenuItem.isVisible = true + hideWatchedMenuItem.isVisible = false + hidePartiallyWatchedMenuItem.isVisible = true + } + else -> { + showAllMenuItem.isVisible = true + hideWatchedMenuItem.isVisible = true + hidePartiallyWatchedMenuItem.isVisible = false + } + } + MenuItemCompat.setTooltipText( menuItem, - getString(R.string.feed_toggle_show_hide_played_items) + getString(R.string.feed_change_stream_visibility_state) ) } diff --git a/app/src/main/java/org/schabi/newpipe/local/feed/FeedViewModel.kt b/app/src/main/java/org/schabi/newpipe/local/feed/FeedViewModel.kt index 5785c8e3f..46c3443a8 100644 --- a/app/src/main/java/org/schabi/newpipe/local/feed/FeedViewModel.kt +++ b/app/src/main/java/org/schabi/newpipe/local/feed/FeedViewModel.kt @@ -28,20 +28,17 @@ import org.schabi.newpipe.util.DEFAULT_THROTTLE_TIMEOUT import java.time.OffsetDateTime import java.util.concurrent.TimeUnit -enum class ShowItems { - WATCHED, PARTIALLY_WATCHED, DEFAULT -} class FeedViewModel( private val application: Application, groupId: Long = FeedGroupEntity.GROUP_ALL_ID, - initialShowPlayedItems: ShowItems = ShowItems.DEFAULT, + initialStreamVisibility: StreamVisibilityStatus = StreamVisibilityStatus.DEFAULT, initialShowFutureItems: Boolean = true ) : ViewModel() { private val feedDatabaseManager = FeedDatabaseManager(application) - private val toggleShowPlayedItems = BehaviorProcessor.create() - private val toggleShowPlayedItemsFlowable = toggleShowPlayedItems - .startWithItem(initialShowPlayedItems) + private val streamVisibilityState = BehaviorProcessor.create() + private val streamVisibilityStateFlowable = streamVisibilityState + .startWithItem(initialStreamVisibility) .distinctUntilChanged() private val toggleShowFutureItems = BehaviorProcessor.create() @@ -55,12 +52,12 @@ class FeedViewModel( private var combineDisposable = Flowable .combineLatest( FeedEventManager.events(), - toggleShowPlayedItemsFlowable, + streamVisibilityStateFlowable, toggleShowFutureItemsFlowable, feedDatabaseManager.notLoadedCount(groupId), feedDatabaseManager.oldestSubscriptionUpdate(groupId), - Function5 { t1: FeedEventManager.Event, t2: ShowItems, t3: Boolean, + Function5 { t1: FeedEventManager.Event, t2: StreamVisibilityStatus, t3: Boolean, t4: Long, t5: List -> return@Function5 CombineResultEventHolder(t1, t2, t3, t4, t5.firstOrNull()) } @@ -74,10 +71,10 @@ class FeedViewModel( .getStreams( groupId, !( - showPlayedItems == ShowItems.WATCHED || - showPlayedItems == ShowItems.PARTIALLY_WATCHED + showPlayedItems == StreamVisibilityStatus.HIDE_WATCHED || + showPlayedItems == StreamVisibilityStatus.HIDE_PARTIALLY_WATCHED ), - showPlayedItems != ShowItems.PARTIALLY_WATCHED, + showPlayedItems != StreamVisibilityStatus.HIDE_PARTIALLY_WATCHED, showFutureItems ) .blockingGet(arrayListOf()) @@ -110,7 +107,7 @@ class FeedViewModel( private data class CombineResultEventHolder( val t1: FeedEventManager.Event, - val t2: ShowItems, + val t2: StreamVisibilityStatus, val t3: Boolean, val t4: Long, val t5: OffsetDateTime? @@ -123,20 +120,20 @@ class FeedViewModel( val t4: OffsetDateTime? ) - fun togglePlayedItems(showItems: ShowItems) { - toggleShowPlayedItems.onNext(showItems) + fun changeVisibilityState(streamVisibilityStatus: StreamVisibilityStatus) { + streamVisibilityState.onNext(streamVisibilityStatus) } - fun saveShowPlayedItemsToPreferences(showItems: ShowItems) = + fun saveStreamVisibilityStateToPreferences(streamVisibilityStatus: StreamVisibilityStatus) = PreferenceManager.getDefaultSharedPreferences(application).edit { this.putString( - application.getString(R.string.feed_show_played_items_key), - showItems.toString() + application.getString(R.string.feed_stream_visibility_state_key), + streamVisibilityStatus.toString() ) this.apply() } - fun getItemsVisibilityFromPreferences() = getItemsVisibilityFromPreferences(application) + fun getItemsVisibilityFromPreferences() = getStreamVisibilityStateFromPreferences(application) fun toggleFutureItems(showFutureItems: Boolean) { toggleShowFutureItems.onNext(showFutureItems) @@ -152,13 +149,13 @@ class FeedViewModel( companion object { - private fun getItemsVisibilityFromPreferences(context: Context): ShowItems { + private fun getStreamVisibilityStateFromPreferences(context: Context): StreamVisibilityStatus { 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) + context.getString(R.string.feed_stream_visibility_state_key), + StreamVisibilityStatus.DEFAULT.toString() + ) ?: StreamVisibilityStatus.DEFAULT.toString() + return StreamVisibilityStatus.valueOf(s) } private fun getShowFutureItemsFromPreferences(context: Context) = @@ -170,7 +167,7 @@ class FeedViewModel( App.getApp(), groupId, // Read initial value from preferences - getItemsVisibilityFromPreferences(context.applicationContext), + getStreamVisibilityStateFromPreferences(context.applicationContext), getShowFutureItemsFromPreferences(context.applicationContext) ) } diff --git a/app/src/main/java/org/schabi/newpipe/local/feed/StreamVisibilityStatus.kt b/app/src/main/java/org/schabi/newpipe/local/feed/StreamVisibilityStatus.kt new file mode 100644 index 000000000..956594ef3 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/local/feed/StreamVisibilityStatus.kt @@ -0,0 +1,5 @@ +package org.schabi.newpipe.local.feed + +enum class StreamVisibilityStatus { + DEFAULT, HIDE_WATCHED, HIDE_PARTIALLY_WATCHED +} diff --git a/app/src/main/java/org/schabi/newpipe/local/history/HistoryRecordManager.java b/app/src/main/java/org/schabi/newpipe/local/history/HistoryRecordManager.java index b8d2eae2d..be3ab3674 100644 --- a/app/src/main/java/org/schabi/newpipe/local/history/HistoryRecordManager.java +++ b/app/src/main/java/org/schabi/newpipe/local/history/HistoryRecordManager.java @@ -87,7 +87,7 @@ public class HistoryRecordManager { * Marks a stream item as watched such that it is hidden from the feed if watched videos are * hidden. Adds a history entry and updates the stream progress to 100%. * - * @see FeedViewModel#togglePlayedItems + * @see FeedViewModel#changeVisibilityState * @param info the item to mark as watched * @return a Maybe containing the ID of the item if successful */ diff --git a/app/src/main/res/menu/menu_feed_fragment.xml b/app/src/main/res/menu/menu_feed_fragment.xml index fc371b2fe..303d27b6b 100644 --- a/app/src/main/res/menu/menu_feed_fragment.xml +++ b/app/src/main/res/menu/menu_feed_fragment.xml @@ -7,18 +7,18 @@ android:checkable="false" android:checked="false" android:icon="@drawable/ic_visibility_on" - android:title="@string/feed_toggle_show_hide_played_items" + android:title="@string/feed_change_stream_visibility_state" app:showAsAction="ifRoom"> + android:title="@string/feed_stream_visibility_show_all"/> + android:title="@string/feed_stream_visibility_hide_watched"/> + android:title="@string/feed_stream_visibility_hide_partially_watched"/> diff --git a/app/src/main/res/values/settings_keys.xml b/app/src/main/res/values/settings_keys.xml index 83f85b934..0bb9b21c2 100644 --- a/app/src/main/res/values/settings_keys.xml +++ b/app/src/main/res/values/settings_keys.xml @@ -283,7 +283,7 @@ feed_update_threshold_key 300 - feed_show_items + feed_stream_visibility_state feed_show_future_items show_thumbnail_key diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 46a3cad74..854e0db54 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -691,7 +691,7 @@ \nYouTube is an example of a service that offers this fast method with its RSS feed. \n \nSo the choice boils down to what you prefer: speed or precise information. - Show/hide watched items + Show/hide watched streams This content is not yet supported by NewPipe.\n\nIt will hopefully be supported in a future version. Channel\'s avatar thumbnail Created by %s @@ -759,8 +759,8 @@ Unknown quality Show future items Hide future items - Hide Watched and Partially Watched - Hide Watched - Show All + Hide Watched + Hide Fully Watched + Show All Sort \ No newline at end of file From cd8d57040cfaeea1cc97ad4dba9023ff599e16bb Mon Sep 17 00:00:00 2001 From: Jared Fantaye Date: Sat, 4 Feb 2023 18:48:27 +0100 Subject: [PATCH 4/6] Implemented the feature using multiple checkboxes --- .../newpipe/database/feed/dao/FeedDAO.kt | 2 + .../schabi/newpipe/local/feed/FeedFragment.kt | 116 +++++++----------- .../newpipe/local/feed/FeedViewModel.kt | 102 +++++++-------- .../local/feed/StreamVisibilityStatus.kt | 5 - .../local/history/HistoryRecordManager.java | 2 +- app/src/main/res/menu/menu_feed_fragment.xml | 26 +--- app/src/main/res/values/settings_keys.xml | 3 +- app/src/main/res/values/strings.xml | 9 +- 8 files changed, 107 insertions(+), 158 deletions(-) delete mode 100644 app/src/main/java/org/schabi/newpipe/local/feed/StreamVisibilityStatus.kt diff --git a/app/src/main/java/org/schabi/newpipe/database/feed/dao/FeedDAO.kt b/app/src/main/java/org/schabi/newpipe/database/feed/dao/FeedDAO.kt index a53e5cac1..42a248ca5 100644 --- a/app/src/main/java/org/schabi/newpipe/database/feed/dao/FeedDAO.kt +++ b/app/src/main/java/org/schabi/newpipe/database/feed/dao/FeedDAO.kt @@ -73,6 +73,8 @@ abstract class FeedDAO { OR sst.stream_id IS NULL OR (sst.progress_time <= ${StreamStateEntity.PLAYBACK_SAVE_THRESHOLD_START_MILLISECONDS} AND sst.progress_time <= s.duration * 1000 / 4) + OR (sst.progress_time >= s.duration * 1000 - ${StreamStateEntity.PLAYBACK_FINISHED_END_MILLISECONDS} + OR sst.progress_time >= s.duration * 1000 * 3 / 4) ) AND ( :uploadDateBefore IS NULL diff --git a/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt b/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt index 9358c1654..d2c361662 100644 --- a/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt +++ b/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt @@ -37,7 +37,6 @@ import android.view.View import android.view.ViewGroup import android.widget.Button import androidx.appcompat.app.AlertDialog -import androidx.appcompat.content.res.AppCompatResources import androidx.core.content.edit import androidx.core.math.MathUtils import androidx.core.os.bundleOf @@ -100,13 +99,10 @@ class FeedFragment : BaseStateFragment() { private var oldestSubscriptionUpdate: OffsetDateTime? = null private lateinit var groupAdapter: GroupieAdapter - @State @JvmField var feedVisibilityStatus: StreamVisibilityStatus = StreamVisibilityStatus.DEFAULT + @State @JvmField var showPlayedItems: Boolean = true + @State @JvmField var showPartiallyPlayedItems: Boolean = true @State @JvmField var showFutureItems: Boolean = true - private lateinit var showAllMenuItem: MenuItem - private lateinit var hideWatchedMenuItem: MenuItem - private lateinit var hidePartiallyWatchedMenuItem: MenuItem - private var onSettingsChangeListener: SharedPreferences.OnSharedPreferenceChangeListener? = null private var updateListViewModeOnResume = false private var isRefreshing = false @@ -144,7 +140,8 @@ class FeedFragment : BaseStateFragment() { val factory = FeedViewModel.getFactory(requireContext(), groupId) viewModel = ViewModelProvider(this, factory)[FeedViewModel::class.java] - feedVisibilityStatus = viewModel.getItemsVisibilityFromPreferences() + showPlayedItems = viewModel.getShowPlayedItemsFromPreferences() + showPartiallyPlayedItems = viewModel.getShowPartiallyPlayedItemsFromPreferences() showFutureItems = viewModel.getShowFutureItemsFromPreferences() viewModel.stateLiveData.observe(viewLifecycleOwner) { it?.let(::handleResult) } @@ -220,16 +217,10 @@ class FeedFragment : BaseStateFragment() { activity.supportActionBar?.subtitle = groupName inflater.inflate(R.menu.menu_feed_fragment, menu) - - val itemVisibilityMenu = menu.findItem(R.id.menu_item_feed_toggle_played_items).subMenu - if (itemVisibilityMenu != null) { - showAllMenuItem = itemVisibilityMenu.findItem(R.id.menu_item_feed_toggle_show_all_items) - hideWatchedMenuItem = itemVisibilityMenu.findItem(R.id.menu_item_feed_toggle_show_played_items) - hidePartiallyWatchedMenuItem = itemVisibilityMenu.findItem(R.id.menu_item_feed_toggle_partially_played_items) - } - - updateItemVisibilityMenu(menu.findItem(R.id.menu_item_feed_toggle_played_items)) - updateToggleFutureItemsButton(menu.findItem(R.id.menu_item_feed_toggle_future_items)) + MenuItemCompat.setTooltipText( + menu.findItem(R.id.menu_item_feed_toggle_played_items), + getString(R.string.feed_show_hide_streams) + ) } override fun onOptionsItemSelected(item: MenuItem): Boolean { @@ -254,27 +245,44 @@ class FeedFragment : BaseStateFragment() { .create() .show() return true - } else if (item.itemId == R.id.menu_item_feed_toggle_show_all_items) { - changeItemsVisibilityStatus(item, StreamVisibilityStatus.DEFAULT) - } else if (item.itemId == R.id.menu_item_feed_toggle_show_played_items) { - changeItemsVisibilityStatus(item, StreamVisibilityStatus.HIDE_WATCHED) - } else if (item.itemId == R.id.menu_item_feed_toggle_partially_played_items) { - changeItemsVisibilityStatus(item, StreamVisibilityStatus.HIDE_PARTIALLY_WATCHED) - } else if (item.itemId == R.id.menu_item_feed_toggle_future_items) { - showFutureItems = !item.isChecked - updateToggleFutureItemsButton(item) - viewModel.toggleFutureItems(showFutureItems) - viewModel.saveShowFutureItemsToPreferences(showFutureItems) + } else if (item.itemId == R.id.menu_item_feed_toggle_played_items) { + showStreamVisibilityDialog() } return super.onOptionsItemSelected(item) } - private fun changeItemsVisibilityStatus(item: MenuItem, streamVisibilityStatus: StreamVisibilityStatus) { - feedVisibilityStatus = streamVisibilityStatus - viewModel.changeVisibilityState(feedVisibilityStatus) - updateItemVisibilityMenu(item) - viewModel.saveStreamVisibilityStateToPreferences(feedVisibilityStatus) + private fun showStreamVisibilityDialog() { + val dialogItems = arrayOf( + getString(R.string.feed_show_watched), + getString(R.string.feed_show_partially_watched), + getString(R.string.feed_show_upcoming) + ) + + val checkedDialogItems = booleanArrayOf(!showPlayedItems, !showPartiallyPlayedItems, !showFutureItems) + + val builder = AlertDialog.Builder(context!!) + builder.setTitle(R.string.feed_hide_streams_title) + builder.setMultiChoiceItems(dialogItems, checkedDialogItems) { _, which, isChecked -> + checkedDialogItems[which] = isChecked + } + + builder.setPositiveButton(R.string.ok) { _, _ -> + showPlayedItems = !checkedDialogItems[0] + viewModel.setShowPlayedItems(showPlayedItems) + viewModel.saveShowPlayedItemsToPreferences(showPlayedItems) + + showPartiallyPlayedItems = !checkedDialogItems[1] + viewModel.setShowPartiallyPlayedItems(showPartiallyPlayedItems) + viewModel.saveShowPartiallyPlayedItemsToPreferences(showPartiallyPlayedItems) + + showFutureItems = !checkedDialogItems[2] + viewModel.setShowFutureItems(showFutureItems) + viewModel.saveShowFutureItemsToPreferences(showFutureItems) + } + builder.setNegativeButton(R.string.cancel, null) + + builder.create().show() } override fun onDestroyOptionsMenu() { @@ -303,48 +311,6 @@ class FeedFragment : BaseStateFragment() { super.onDestroyView() } - private fun updateItemVisibilityMenu(menuItem: MenuItem) { - when (feedVisibilityStatus) { - StreamVisibilityStatus.DEFAULT -> { - showAllMenuItem.isVisible = false - hideWatchedMenuItem.isVisible = true - hidePartiallyWatchedMenuItem.isVisible = true - } - StreamVisibilityStatus.HIDE_WATCHED -> { - showAllMenuItem.isVisible = true - hideWatchedMenuItem.isVisible = false - hidePartiallyWatchedMenuItem.isVisible = true - } - else -> { - showAllMenuItem.isVisible = true - hideWatchedMenuItem.isVisible = true - hidePartiallyWatchedMenuItem.isVisible = false - } - } - - MenuItemCompat.setTooltipText( - menuItem, - getString(R.string.feed_change_stream_visibility_state) - ) - } - - private fun updateToggleFutureItemsButton(menuItem: MenuItem) { - menuItem.isChecked = showFutureItems - menuItem.icon = AppCompatResources.getDrawable( - requireContext(), - if (showFutureItems) R.drawable.ic_history_future else R.drawable.ic_history - ) - MenuItemCompat.setTooltipText( - menuItem, - getString( - if (showFutureItems) - R.string.feed_toggle_hide_future_items - else - R.string.feed_toggle_show_future_items - ) - ) - } - // ////////////////////////////////////////////////////////////////////////// // Handling // ////////////////////////////////////////////////////////////////////////// diff --git a/app/src/main/java/org/schabi/newpipe/local/feed/FeedViewModel.kt b/app/src/main/java/org/schabi/newpipe/local/feed/FeedViewModel.kt index 46c3443a8..2e85a65cb 100644 --- a/app/src/main/java/org/schabi/newpipe/local/feed/FeedViewModel.kt +++ b/app/src/main/java/org/schabi/newpipe/local/feed/FeedViewModel.kt @@ -11,7 +11,7 @@ import androidx.lifecycle.viewmodel.viewModelFactory import androidx.preference.PreferenceManager import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.core.Flowable -import io.reactivex.rxjava3.functions.Function5 +import io.reactivex.rxjava3.functions.Function6 import io.reactivex.rxjava3.processors.BehaviorProcessor import io.reactivex.rxjava3.schedulers.Schedulers import org.schabi.newpipe.App @@ -31,18 +31,24 @@ import java.util.concurrent.TimeUnit class FeedViewModel( private val application: Application, groupId: Long = FeedGroupEntity.GROUP_ALL_ID, - initialStreamVisibility: StreamVisibilityStatus = StreamVisibilityStatus.DEFAULT, + initialShowPlayedItems: Boolean = true, + initialShowPartiallyPlayedItems: Boolean = true, initialShowFutureItems: Boolean = true ) : ViewModel() { private val feedDatabaseManager = FeedDatabaseManager(application) - private val streamVisibilityState = BehaviorProcessor.create() - private val streamVisibilityStateFlowable = streamVisibilityState - .startWithItem(initialStreamVisibility) + private val showPlayedItems = BehaviorProcessor.create() + private val showPlayedItemsFlowable = showPlayedItems + .startWithItem(initialShowPlayedItems) .distinctUntilChanged() - private val toggleShowFutureItems = BehaviorProcessor.create() - private val toggleShowFutureItemsFlowable = toggleShowFutureItems + private val showPartiallyPlayedItems = BehaviorProcessor.create() + private val showPartiallyPlayedItemsFlowable = showPartiallyPlayedItems + .startWithItem(initialShowPartiallyPlayedItems) + .distinctUntilChanged() + + private val showFutureItems = BehaviorProcessor.create() + private val showFutureItemsFlowable = showFutureItems .startWithItem(initialShowFutureItems) .distinctUntilChanged() @@ -52,35 +58,27 @@ class FeedViewModel( private var combineDisposable = Flowable .combineLatest( FeedEventManager.events(), - streamVisibilityStateFlowable, - toggleShowFutureItemsFlowable, + showPlayedItemsFlowable, + showPartiallyPlayedItemsFlowable, + showFutureItemsFlowable, feedDatabaseManager.notLoadedCount(groupId), feedDatabaseManager.oldestSubscriptionUpdate(groupId), - Function5 { t1: FeedEventManager.Event, t2: StreamVisibilityStatus, t3: Boolean, - t4: Long, t5: List -> - return@Function5 CombineResultEventHolder(t1, t2, t3, t4, t5.firstOrNull()) + Function6 { t1: FeedEventManager.Event, t2: Boolean, t3: Boolean, t4: Boolean, + t5: Long, t6: List -> + return@Function6 CombineResultEventHolder(t1, t2, t3, t4, t5, t6.firstOrNull()) } ) .throttleLatest(DEFAULT_THROTTLE_TIMEOUT, TimeUnit.MILLISECONDS) .subscribeOn(Schedulers.io()) .observeOn(Schedulers.io()) - .map { (event, showPlayedItems, showFutureItems, notLoadedCount, oldestUpdate) -> - val streamItems = if (event is SuccessResultEvent || event is IdleEvent) { + .map { (event, showPlayedItems, showPartiallyPlayedItems, showFutureItems, notLoadedCount, oldestUpdate) -> + val streamItems = if (event is SuccessResultEvent || event is IdleEvent) feedDatabaseManager - .getStreams( - groupId, - !( - showPlayedItems == StreamVisibilityStatus.HIDE_WATCHED || - showPlayedItems == StreamVisibilityStatus.HIDE_PARTIALLY_WATCHED - ), - showPlayedItems != StreamVisibilityStatus.HIDE_PARTIALLY_WATCHED, - showFutureItems - ) + .getStreams(groupId, showPlayedItems, showPartiallyPlayedItems, showFutureItems) .blockingGet(arrayListOf()) - } else { + else arrayListOf() - } CombineResultDataHolder(event, streamItems, notLoadedCount, oldestUpdate) } @@ -107,10 +105,11 @@ class FeedViewModel( private data class CombineResultEventHolder( val t1: FeedEventManager.Event, - val t2: StreamVisibilityStatus, + val t2: Boolean, val t3: Boolean, - val t4: Long, - val t5: OffsetDateTime? + val t4: Boolean, + val t5: Long, + val t6: OffsetDateTime? ) private data class CombineResultDataHolder( @@ -120,23 +119,32 @@ class FeedViewModel( val t4: OffsetDateTime? ) - fun changeVisibilityState(streamVisibilityStatus: StreamVisibilityStatus) { - streamVisibilityState.onNext(streamVisibilityStatus) + fun setShowPlayedItems(showPlayedItems: Boolean) { + this.showPlayedItems.onNext(showPlayedItems) } - fun saveStreamVisibilityStateToPreferences(streamVisibilityStatus: StreamVisibilityStatus) = + fun saveShowPlayedItemsToPreferences(showPlayedItems: Boolean) = PreferenceManager.getDefaultSharedPreferences(application).edit { - this.putString( - application.getString(R.string.feed_stream_visibility_state_key), - streamVisibilityStatus.toString() - ) + this.putBoolean(application.getString(R.string.feed_show_watched_items_key), showPlayedItems) this.apply() } - fun getItemsVisibilityFromPreferences() = getStreamVisibilityStateFromPreferences(application) + fun getShowPlayedItemsFromPreferences() = getShowPlayedItemsFromPreferences(application) - fun toggleFutureItems(showFutureItems: Boolean) { - toggleShowFutureItems.onNext(showFutureItems) + fun setShowPartiallyPlayedItems(showPartiallyPlayedItems: Boolean) { + this.showPartiallyPlayedItems.onNext(showPartiallyPlayedItems) + } + + fun saveShowPartiallyPlayedItemsToPreferences(showPartiallyPlayedItems: Boolean) = + PreferenceManager.getDefaultSharedPreferences(application).edit { + this.putBoolean(application.getString(R.string.feed_show_partially_watched_items_key), showPartiallyPlayedItems) + this.apply() + } + + fun getShowPartiallyPlayedItemsFromPreferences() = getShowPartiallyPlayedItemsFromPreferences(application) + + fun setShowFutureItems(showFutureItems: Boolean) { + this.showFutureItems.onNext(showFutureItems) } fun saveShowFutureItemsToPreferences(showFutureItems: Boolean) = @@ -148,16 +156,13 @@ class FeedViewModel( fun getShowFutureItemsFromPreferences() = getShowFutureItemsFromPreferences(application) companion object { + private fun getShowPlayedItemsFromPreferences(context: Context) = + PreferenceManager.getDefaultSharedPreferences(context) + .getBoolean(context.getString(R.string.feed_show_watched_items_key), true) - private fun getStreamVisibilityStateFromPreferences(context: Context): StreamVisibilityStatus { - val s = PreferenceManager.getDefaultSharedPreferences(context) - .getString( - context.getString(R.string.feed_stream_visibility_state_key), - StreamVisibilityStatus.DEFAULT.toString() - ) ?: StreamVisibilityStatus.DEFAULT.toString() - return StreamVisibilityStatus.valueOf(s) - } - + private fun getShowPartiallyPlayedItemsFromPreferences(context: Context) = + PreferenceManager.getDefaultSharedPreferences(context) + .getBoolean(context.getString(R.string.feed_show_partially_watched_items_key), true) private fun getShowFutureItemsFromPreferences(context: Context) = PreferenceManager.getDefaultSharedPreferences(context) .getBoolean(context.getString(R.string.feed_show_future_items_key), true) @@ -167,7 +172,8 @@ class FeedViewModel( App.getApp(), groupId, // Read initial value from preferences - getStreamVisibilityStateFromPreferences(context.applicationContext), + getShowPlayedItemsFromPreferences(context.applicationContext), + getShowPartiallyPlayedItemsFromPreferences(context.applicationContext), getShowFutureItemsFromPreferences(context.applicationContext) ) } diff --git a/app/src/main/java/org/schabi/newpipe/local/feed/StreamVisibilityStatus.kt b/app/src/main/java/org/schabi/newpipe/local/feed/StreamVisibilityStatus.kt deleted file mode 100644 index 956594ef3..000000000 --- a/app/src/main/java/org/schabi/newpipe/local/feed/StreamVisibilityStatus.kt +++ /dev/null @@ -1,5 +0,0 @@ -package org.schabi.newpipe.local.feed - -enum class StreamVisibilityStatus { - DEFAULT, HIDE_WATCHED, HIDE_PARTIALLY_WATCHED -} diff --git a/app/src/main/java/org/schabi/newpipe/local/history/HistoryRecordManager.java b/app/src/main/java/org/schabi/newpipe/local/history/HistoryRecordManager.java index be3ab3674..340b22278 100644 --- a/app/src/main/java/org/schabi/newpipe/local/history/HistoryRecordManager.java +++ b/app/src/main/java/org/schabi/newpipe/local/history/HistoryRecordManager.java @@ -87,7 +87,7 @@ public class HistoryRecordManager { * Marks a stream item as watched such that it is hidden from the feed if watched videos are * hidden. Adds a history entry and updates the stream progress to 100%. * - * @see FeedViewModel#changeVisibilityState + * @see FeedViewModel#setShowPlayedItems * @param info the item to mark as watched * @return a Maybe containing the ID of the item if successful */ diff --git a/app/src/main/res/menu/menu_feed_fragment.xml b/app/src/main/res/menu/menu_feed_fragment.xml index 303d27b6b..2365c30e4 100644 --- a/app/src/main/res/menu/menu_feed_fragment.xml +++ b/app/src/main/res/menu/menu_feed_fragment.xml @@ -4,31 +4,9 @@ - - - - - - - - feed_update_threshold_key 300 - feed_stream_visibility_state + feed_show_watched_items + feed_show_partially_watched_items feed_show_future_items show_thumbnail_key diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 854e0db54..e01d3ed72 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -691,7 +691,8 @@ \nYouTube is an example of a service that offers this fast method with its RSS feed. \n \nSo the choice boils down to what you prefer: speed or precise information. - Show/hide watched streams + Hide the following streams + Show/Hide streams This content is not yet supported by NewPipe.\n\nIt will hopefully be supported in a future version. Channel\'s avatar thumbnail Created by %s @@ -759,8 +760,8 @@ Unknown quality Show future items Hide future items - Hide Watched - Hide Fully Watched - Show All + Fully Watched + Partially Watched + Upcoming Sort \ No newline at end of file From bc29f40d6940f0bea180d7cb948350202193d48d Mon Sep 17 00:00:00 2001 From: Jared Fantaye Date: Thu, 9 Feb 2023 21:18:21 +0100 Subject: [PATCH 5/6] Implemented the suggested changes --- .../newpipe/database/feed/dao/FeedDAO.kt | 2 +- .../schabi/newpipe/local/feed/FeedFragment.kt | 17 ++++++------- .../newpipe/local/feed/FeedViewModel.kt | 24 +++++++------------ .../local/history/HistoryRecordManager.java | 2 +- app/src/main/res/values/strings.xml | 6 ++--- 5 files changed, 21 insertions(+), 30 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/database/feed/dao/FeedDAO.kt b/app/src/main/java/org/schabi/newpipe/database/feed/dao/FeedDAO.kt index 42a248ca5..6947f66af 100644 --- a/app/src/main/java/org/schabi/newpipe/database/feed/dao/FeedDAO.kt +++ b/app/src/main/java/org/schabi/newpipe/database/feed/dao/FeedDAO.kt @@ -74,7 +74,7 @@ abstract class FeedDAO { OR (sst.progress_time <= ${StreamStateEntity.PLAYBACK_SAVE_THRESHOLD_START_MILLISECONDS} AND sst.progress_time <= s.duration * 1000 / 4) OR (sst.progress_time >= s.duration * 1000 - ${StreamStateEntity.PLAYBACK_FINISHED_END_MILLISECONDS} - OR sst.progress_time >= s.duration * 1000 * 3 / 4) + AND sst.progress_time >= s.duration * 1000 * 3 / 4) ) AND ( :uploadDateBefore IS NULL diff --git a/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt b/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt index d2c361662..3ca3bd320 100644 --- a/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt +++ b/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt @@ -259,7 +259,7 @@ class FeedFragment : BaseStateFragment() { getString(R.string.feed_show_upcoming) ) - val checkedDialogItems = booleanArrayOf(!showPlayedItems, !showPartiallyPlayedItems, !showFutureItems) + val checkedDialogItems = booleanArrayOf(showPlayedItems, showPartiallyPlayedItems, showFutureItems) val builder = AlertDialog.Builder(context!!) builder.setTitle(R.string.feed_hide_streams_title) @@ -268,17 +268,14 @@ class FeedFragment : BaseStateFragment() { } builder.setPositiveButton(R.string.ok) { _, _ -> - showPlayedItems = !checkedDialogItems[0] - viewModel.setShowPlayedItems(showPlayedItems) - viewModel.saveShowPlayedItemsToPreferences(showPlayedItems) + showPlayedItems = checkedDialogItems[0] + viewModel.setSaveShowPlayedItems(showPlayedItems) - showPartiallyPlayedItems = !checkedDialogItems[1] - viewModel.setShowPartiallyPlayedItems(showPartiallyPlayedItems) - viewModel.saveShowPartiallyPlayedItemsToPreferences(showPartiallyPlayedItems) + showPartiallyPlayedItems = checkedDialogItems[1] + viewModel.setSaveShowPartiallyPlayedItems(showPartiallyPlayedItems) - showFutureItems = !checkedDialogItems[2] - viewModel.setShowFutureItems(showFutureItems) - viewModel.saveShowFutureItemsToPreferences(showFutureItems) + showFutureItems = checkedDialogItems[2] + viewModel.setSaveShowFutureItems(showFutureItems) } builder.setNegativeButton(R.string.cancel, null) diff --git a/app/src/main/java/org/schabi/newpipe/local/feed/FeedViewModel.kt b/app/src/main/java/org/schabi/newpipe/local/feed/FeedViewModel.kt index 2e85a65cb..015b72160 100644 --- a/app/src/main/java/org/schabi/newpipe/local/feed/FeedViewModel.kt +++ b/app/src/main/java/org/schabi/newpipe/local/feed/FeedViewModel.kt @@ -31,9 +31,9 @@ import java.util.concurrent.TimeUnit class FeedViewModel( private val application: Application, groupId: Long = FeedGroupEntity.GROUP_ALL_ID, - initialShowPlayedItems: Boolean = true, - initialShowPartiallyPlayedItems: Boolean = true, - initialShowFutureItems: Boolean = true + initialShowPlayedItems: Boolean, + initialShowPartiallyPlayedItems: Boolean, + initialShowFutureItems: Boolean ) : ViewModel() { private val feedDatabaseManager = FeedDatabaseManager(application) @@ -119,39 +119,33 @@ class FeedViewModel( val t4: OffsetDateTime? ) - fun setShowPlayedItems(showPlayedItems: Boolean) { + fun setSaveShowPlayedItems(showPlayedItems: Boolean) { this.showPlayedItems.onNext(showPlayedItems) - } - - fun saveShowPlayedItemsToPreferences(showPlayedItems: Boolean) = PreferenceManager.getDefaultSharedPreferences(application).edit { this.putBoolean(application.getString(R.string.feed_show_watched_items_key), showPlayedItems) this.apply() } + } fun getShowPlayedItemsFromPreferences() = getShowPlayedItemsFromPreferences(application) - fun setShowPartiallyPlayedItems(showPartiallyPlayedItems: Boolean) { + fun setSaveShowPartiallyPlayedItems(showPartiallyPlayedItems: Boolean) { this.showPartiallyPlayedItems.onNext(showPartiallyPlayedItems) - } - - fun saveShowPartiallyPlayedItemsToPreferences(showPartiallyPlayedItems: Boolean) = PreferenceManager.getDefaultSharedPreferences(application).edit { this.putBoolean(application.getString(R.string.feed_show_partially_watched_items_key), showPartiallyPlayedItems) this.apply() } + } fun getShowPartiallyPlayedItemsFromPreferences() = getShowPartiallyPlayedItemsFromPreferences(application) - fun setShowFutureItems(showFutureItems: Boolean) { + fun setSaveShowFutureItems(showFutureItems: Boolean) { this.showFutureItems.onNext(showFutureItems) - } - - fun saveShowFutureItemsToPreferences(showFutureItems: Boolean) = PreferenceManager.getDefaultSharedPreferences(application).edit { this.putBoolean(application.getString(R.string.feed_show_future_items_key), showFutureItems) this.apply() } + } fun getShowFutureItemsFromPreferences() = getShowFutureItemsFromPreferences(application) diff --git a/app/src/main/java/org/schabi/newpipe/local/history/HistoryRecordManager.java b/app/src/main/java/org/schabi/newpipe/local/history/HistoryRecordManager.java index 340b22278..ed3cf548f 100644 --- a/app/src/main/java/org/schabi/newpipe/local/history/HistoryRecordManager.java +++ b/app/src/main/java/org/schabi/newpipe/local/history/HistoryRecordManager.java @@ -87,7 +87,7 @@ public class HistoryRecordManager { * Marks a stream item as watched such that it is hidden from the feed if watched videos are * hidden. Adds a history entry and updates the stream progress to 100%. * - * @see FeedViewModel#setShowPlayedItems + * @see FeedViewModel#setSaveShowPlayedItems * @param info the item to mark as watched * @return a Maybe containing the ID of the item if successful */ diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e01d3ed72..ee388ce13 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -691,7 +691,7 @@ \nYouTube is an example of a service that offers this fast method with its RSS feed. \n \nSo the choice boils down to what you prefer: speed or precise information. - Hide the following streams + Show the following streams Show/Hide streams This content is not yet supported by NewPipe.\n\nIt will hopefully be supported in a future version. Channel\'s avatar thumbnail @@ -760,8 +760,8 @@ Unknown quality Show future items Hide future items - Fully Watched - Partially Watched + Fully watched + Partially watched Upcoming Sort \ No newline at end of file From 1dd0930b835ae4bc7182f4f05ee3a69060f5db4b Mon Sep 17 00:00:00 2001 From: Jared Fantaye Date: Tue, 28 Feb 2023 17:30:17 +0100 Subject: [PATCH 6/6] Fixed some small issues --- .../schabi/newpipe/local/feed/FeedFragment.kt | 26 ++++++------------- .../newpipe/local/feed/FeedViewModel.kt | 2 ++ app/src/main/res/values/settings_keys.xml | 2 +- 3 files changed, 11 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt b/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt index 3ca3bd320..9fe90969f 100644 --- a/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt +++ b/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt @@ -40,7 +40,6 @@ import androidx.appcompat.app.AlertDialog import androidx.core.content.edit import androidx.core.math.MathUtils import androidx.core.os.bundleOf -import androidx.core.view.MenuItemCompat import androidx.core.view.isVisible import androidx.lifecycle.ViewModelProvider import androidx.preference.PreferenceManager @@ -99,9 +98,6 @@ class FeedFragment : BaseStateFragment() { private var oldestSubscriptionUpdate: OffsetDateTime? = null private lateinit var groupAdapter: GroupieAdapter - @State @JvmField var showPlayedItems: Boolean = true - @State @JvmField var showPartiallyPlayedItems: Boolean = true - @State @JvmField var showFutureItems: Boolean = true private var onSettingsChangeListener: SharedPreferences.OnSharedPreferenceChangeListener? = null private var updateListViewModeOnResume = false @@ -140,9 +136,6 @@ class FeedFragment : BaseStateFragment() { val factory = FeedViewModel.getFactory(requireContext(), groupId) viewModel = ViewModelProvider(this, factory)[FeedViewModel::class.java] - showPlayedItems = viewModel.getShowPlayedItemsFromPreferences() - showPartiallyPlayedItems = viewModel.getShowPartiallyPlayedItemsFromPreferences() - showFutureItems = viewModel.getShowFutureItemsFromPreferences() viewModel.stateLiveData.observe(viewLifecycleOwner) { it?.let(::handleResult) } groupAdapter = GroupieAdapter().apply { @@ -217,10 +210,6 @@ class FeedFragment : BaseStateFragment() { activity.supportActionBar?.subtitle = groupName inflater.inflate(R.menu.menu_feed_fragment, menu) - MenuItemCompat.setTooltipText( - menu.findItem(R.id.menu_item_feed_toggle_played_items), - getString(R.string.feed_show_hide_streams) - ) } override fun onOptionsItemSelected(item: MenuItem): Boolean { @@ -259,7 +248,11 @@ class FeedFragment : BaseStateFragment() { getString(R.string.feed_show_upcoming) ) - val checkedDialogItems = booleanArrayOf(showPlayedItems, showPartiallyPlayedItems, showFutureItems) + val checkedDialogItems = booleanArrayOf( + viewModel.getShowPlayedItemsFromPreferences(), + viewModel.getShowPartiallyPlayedItemsFromPreferences(), + viewModel.getShowFutureItemsFromPreferences() + ) val builder = AlertDialog.Builder(context!!) builder.setTitle(R.string.feed_hide_streams_title) @@ -268,14 +261,11 @@ class FeedFragment : BaseStateFragment() { } builder.setPositiveButton(R.string.ok) { _, _ -> - showPlayedItems = checkedDialogItems[0] - viewModel.setSaveShowPlayedItems(showPlayedItems) + viewModel.setSaveShowPlayedItems(checkedDialogItems[0]) - showPartiallyPlayedItems = checkedDialogItems[1] - viewModel.setSaveShowPartiallyPlayedItems(showPartiallyPlayedItems) + viewModel.setSaveShowPartiallyPlayedItems(checkedDialogItems[1]) - showFutureItems = checkedDialogItems[2] - viewModel.setSaveShowFutureItems(showFutureItems) + viewModel.setSaveShowFutureItems(checkedDialogItems[2]) } builder.setNegativeButton(R.string.cancel, null) diff --git a/app/src/main/java/org/schabi/newpipe/local/feed/FeedViewModel.kt b/app/src/main/java/org/schabi/newpipe/local/feed/FeedViewModel.kt index 015b72160..58f9e9edc 100644 --- a/app/src/main/java/org/schabi/newpipe/local/feed/FeedViewModel.kt +++ b/app/src/main/java/org/schabi/newpipe/local/feed/FeedViewModel.kt @@ -157,9 +157,11 @@ class FeedViewModel( private fun getShowPartiallyPlayedItemsFromPreferences(context: Context) = PreferenceManager.getDefaultSharedPreferences(context) .getBoolean(context.getString(R.string.feed_show_partially_watched_items_key), true) + private fun getShowFutureItemsFromPreferences(context: Context) = PreferenceManager.getDefaultSharedPreferences(context) .getBoolean(context.getString(R.string.feed_show_future_items_key), true) + fun getFactory(context: Context, groupId: Long) = viewModelFactory { initializer { FeedViewModel( diff --git a/app/src/main/res/values/settings_keys.xml b/app/src/main/res/values/settings_keys.xml index 281d3bf40..57d1abc5c 100644 --- a/app/src/main/res/values/settings_keys.xml +++ b/app/src/main/res/values/settings_keys.xml @@ -283,7 +283,7 @@ feed_update_threshold_key 300 - feed_show_watched_items + feed_show_played_items feed_show_partially_watched_items feed_show_future_items