Skip to content

Commit 2e3490b

Browse files
authored
Merge pull request #9747 from Jared234/9126_remove_partially_watched_from_feed
Added option to remove partially watched videos from the 'Whats new' feed
2 parents 73aebc1 + 1dd0930 commit 2e3490b

File tree

9 files changed

+102
-94
lines changed

9 files changed

+102
-94
lines changed

app/src/main/java/org/schabi/newpipe/database/feed/dao/FeedDAO.kt

+11
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ abstract class FeedDAO {
3232
* @return the feed streams filtered according to the conditions provided in the parameters
3333
* @see StreamStateEntity.isFinished()
3434
* @see StreamStateEntity.PLAYBACK_FINISHED_END_MILLISECONDS
35+
* @see StreamStateEntity.PLAYBACK_SAVE_THRESHOLD_START_MILLISECONDS
3536
*/
3637
@Query(
3738
"""
@@ -66,6 +67,15 @@ abstract class FeedDAO {
6667
OR s.stream_type = 'LIVE_STREAM'
6768
OR s.stream_type = 'AUDIO_LIVE_STREAM'
6869
)
70+
AND (
71+
:includePartiallyPlayed
72+
OR sh.stream_id IS NULL
73+
OR sst.stream_id IS NULL
74+
OR (sst.progress_time <= ${StreamStateEntity.PLAYBACK_SAVE_THRESHOLD_START_MILLISECONDS}
75+
AND sst.progress_time <= s.duration * 1000 / 4)
76+
OR (sst.progress_time >= s.duration * 1000 - ${StreamStateEntity.PLAYBACK_FINISHED_END_MILLISECONDS}
77+
AND sst.progress_time >= s.duration * 1000 * 3 / 4)
78+
)
6979
AND (
7080
:uploadDateBefore IS NULL
7181
OR s.upload_date IS NULL
@@ -79,6 +89,7 @@ abstract class FeedDAO {
7989
abstract fun getStreams(
8090
groupId: Long,
8191
includePlayed: Boolean,
92+
includePartiallyPlayed: Boolean,
8293
uploadDateBefore: OffsetDateTime?
8394
): Maybe<List<StreamWithState>>
8495

app/src/main/java/org/schabi/newpipe/database/stream/model/StreamStateEntity.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public class StreamStateEntity {
3030
/**
3131
* Playback state will not be saved, if playback time is less than this threshold (5000ms = 5s).
3232
*/
33-
private static final long PLAYBACK_SAVE_THRESHOLD_START_MILLISECONDS = 5000;
33+
public static final long PLAYBACK_SAVE_THRESHOLD_START_MILLISECONDS = 5000;
3434

3535
/**
3636
* Stream will be considered finished if the playback time left exceeds this threshold

app/src/main/java/org/schabi/newpipe/local/feed/FeedDatabaseManager.kt

+2
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,13 @@ class FeedDatabaseManager(context: Context) {
4343
fun getStreams(
4444
groupId: Long,
4545
includePlayedStreams: Boolean,
46+
includePartiallyPlayedStreams: Boolean,
4647
includeFutureStreams: Boolean
4748
): Maybe<List<StreamWithState>> {
4849
return feedTable.getStreams(
4950
groupId,
5051
includePlayedStreams,
52+
includePartiallyPlayedStreams,
5153
if (includeFutureStreams) null else OffsetDateTime.now()
5254
)
5355
}

app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt

+32-51
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,9 @@ import android.view.View
3737
import android.view.ViewGroup
3838
import android.widget.Button
3939
import androidx.appcompat.app.AlertDialog
40-
import androidx.appcompat.content.res.AppCompatResources
4140
import androidx.core.content.edit
4241
import androidx.core.math.MathUtils
4342
import androidx.core.os.bundleOf
44-
import androidx.core.view.MenuItemCompat
4543
import androidx.core.view.isVisible
4644
import androidx.lifecycle.ViewModelProvider
4745
import androidx.preference.PreferenceManager
@@ -100,8 +98,6 @@ class FeedFragment : BaseStateFragment<FeedState>() {
10098
private var oldestSubscriptionUpdate: OffsetDateTime? = null
10199

102100
private lateinit var groupAdapter: GroupieAdapter
103-
@State @JvmField var showPlayedItems: Boolean = true
104-
@State @JvmField var showFutureItems: Boolean = true
105101

106102
private var onSettingsChangeListener: SharedPreferences.OnSharedPreferenceChangeListener? = null
107103
private var updateListViewModeOnResume = false
@@ -140,8 +136,6 @@ class FeedFragment : BaseStateFragment<FeedState>() {
140136

141137
val factory = FeedViewModel.getFactory(requireContext(), groupId)
142138
viewModel = ViewModelProvider(this, factory)[FeedViewModel::class.java]
143-
showPlayedItems = viewModel.getShowPlayedItemsFromPreferences()
144-
showFutureItems = viewModel.getShowFutureItemsFromPreferences()
145139
viewModel.stateLiveData.observe(viewLifecycleOwner) { it?.let(::handleResult) }
146140

147141
groupAdapter = GroupieAdapter().apply {
@@ -216,8 +210,6 @@ class FeedFragment : BaseStateFragment<FeedState>() {
216210
activity.supportActionBar?.subtitle = groupName
217211

218212
inflater.inflate(R.menu.menu_feed_fragment, menu)
219-
updateTogglePlayedItemsButton(menu.findItem(R.id.menu_item_feed_toggle_played_items))
220-
updateToggleFutureItemsButton(menu.findItem(R.id.menu_item_feed_toggle_future_items))
221213
}
222214

223215
override fun onOptionsItemSelected(item: MenuItem): Boolean {
@@ -243,20 +235,43 @@ class FeedFragment : BaseStateFragment<FeedState>() {
243235
.show()
244236
return true
245237
} else if (item.itemId == R.id.menu_item_feed_toggle_played_items) {
246-
showPlayedItems = !item.isChecked
247-
updateTogglePlayedItemsButton(item)
248-
viewModel.togglePlayedItems(showPlayedItems)
249-
viewModel.saveShowPlayedItemsToPreferences(showPlayedItems)
250-
} else if (item.itemId == R.id.menu_item_feed_toggle_future_items) {
251-
showFutureItems = !item.isChecked
252-
updateToggleFutureItemsButton(item)
253-
viewModel.toggleFutureItems(showFutureItems)
254-
viewModel.saveShowFutureItemsToPreferences(showFutureItems)
238+
showStreamVisibilityDialog()
255239
}
256240

257241
return super.onOptionsItemSelected(item)
258242
}
259243

244+
private fun showStreamVisibilityDialog() {
245+
val dialogItems = arrayOf(
246+
getString(R.string.feed_show_watched),
247+
getString(R.string.feed_show_partially_watched),
248+
getString(R.string.feed_show_upcoming)
249+
)
250+
251+
val checkedDialogItems = booleanArrayOf(
252+
viewModel.getShowPlayedItemsFromPreferences(),
253+
viewModel.getShowPartiallyPlayedItemsFromPreferences(),
254+
viewModel.getShowFutureItemsFromPreferences()
255+
)
256+
257+
val builder = AlertDialog.Builder(context!!)
258+
builder.setTitle(R.string.feed_hide_streams_title)
259+
builder.setMultiChoiceItems(dialogItems, checkedDialogItems) { _, which, isChecked ->
260+
checkedDialogItems[which] = isChecked
261+
}
262+
263+
builder.setPositiveButton(R.string.ok) { _, _ ->
264+
viewModel.setSaveShowPlayedItems(checkedDialogItems[0])
265+
266+
viewModel.setSaveShowPartiallyPlayedItems(checkedDialogItems[1])
267+
268+
viewModel.setSaveShowFutureItems(checkedDialogItems[2])
269+
}
270+
builder.setNegativeButton(R.string.cancel, null)
271+
272+
builder.create().show()
273+
}
274+
260275
override fun onDestroyOptionsMenu() {
261276
super.onDestroyOptionsMenu()
262277
activity?.supportActionBar?.subtitle = null
@@ -283,40 +298,6 @@ class FeedFragment : BaseStateFragment<FeedState>() {
283298
super.onDestroyView()
284299
}
285300

286-
private fun updateTogglePlayedItemsButton(menuItem: MenuItem) {
287-
menuItem.isChecked = showPlayedItems
288-
menuItem.icon = AppCompatResources.getDrawable(
289-
requireContext(),
290-
if (showPlayedItems) R.drawable.ic_visibility_on else R.drawable.ic_visibility_off
291-
)
292-
MenuItemCompat.setTooltipText(
293-
menuItem,
294-
getString(
295-
if (showPlayedItems)
296-
R.string.feed_toggle_hide_played_items
297-
else
298-
R.string.feed_toggle_show_played_items
299-
)
300-
)
301-
}
302-
303-
private fun updateToggleFutureItemsButton(menuItem: MenuItem) {
304-
menuItem.isChecked = showFutureItems
305-
menuItem.icon = AppCompatResources.getDrawable(
306-
requireContext(),
307-
if (showFutureItems) R.drawable.ic_history_future else R.drawable.ic_history
308-
)
309-
MenuItemCompat.setTooltipText(
310-
menuItem,
311-
getString(
312-
if (showFutureItems)
313-
R.string.feed_toggle_hide_future_items
314-
else
315-
R.string.feed_toggle_show_future_items
316-
)
317-
)
318-
}
319-
320301
// //////////////////////////////////////////////////////////////////////////
321302
// Handling
322303
// //////////////////////////////////////////////////////////////////////////

app/src/main/java/org/schabi/newpipe/local/feed/FeedViewModel.kt

+47-26
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import androidx.lifecycle.viewmodel.viewModelFactory
1111
import androidx.preference.PreferenceManager
1212
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
1313
import io.reactivex.rxjava3.core.Flowable
14-
import io.reactivex.rxjava3.functions.Function5
14+
import io.reactivex.rxjava3.functions.Function6
1515
import io.reactivex.rxjava3.processors.BehaviorProcessor
1616
import io.reactivex.rxjava3.schedulers.Schedulers
1717
import org.schabi.newpipe.App
@@ -31,18 +31,24 @@ import java.util.concurrent.TimeUnit
3131
class FeedViewModel(
3232
private val application: Application,
3333
groupId: Long = FeedGroupEntity.GROUP_ALL_ID,
34-
initialShowPlayedItems: Boolean = true,
35-
initialShowFutureItems: Boolean = true
34+
initialShowPlayedItems: Boolean,
35+
initialShowPartiallyPlayedItems: Boolean,
36+
initialShowFutureItems: Boolean
3637
) : ViewModel() {
3738
private val feedDatabaseManager = FeedDatabaseManager(application)
3839

39-
private val toggleShowPlayedItems = BehaviorProcessor.create<Boolean>()
40-
private val toggleShowPlayedItemsFlowable = toggleShowPlayedItems
40+
private val showPlayedItems = BehaviorProcessor.create<Boolean>()
41+
private val showPlayedItemsFlowable = showPlayedItems
4142
.startWithItem(initialShowPlayedItems)
4243
.distinctUntilChanged()
4344

44-
private val toggleShowFutureItems = BehaviorProcessor.create<Boolean>()
45-
private val toggleShowFutureItemsFlowable = toggleShowFutureItems
45+
private val showPartiallyPlayedItems = BehaviorProcessor.create<Boolean>()
46+
private val showPartiallyPlayedItemsFlowable = showPartiallyPlayedItems
47+
.startWithItem(initialShowPartiallyPlayedItems)
48+
.distinctUntilChanged()
49+
50+
private val showFutureItems = BehaviorProcessor.create<Boolean>()
51+
private val showFutureItemsFlowable = showFutureItems
4652
.startWithItem(initialShowFutureItems)
4753
.distinctUntilChanged()
4854

@@ -52,23 +58,24 @@ class FeedViewModel(
5258
private var combineDisposable = Flowable
5359
.combineLatest(
5460
FeedEventManager.events(),
55-
toggleShowPlayedItemsFlowable,
56-
toggleShowFutureItemsFlowable,
61+
showPlayedItemsFlowable,
62+
showPartiallyPlayedItemsFlowable,
63+
showFutureItemsFlowable,
5764
feedDatabaseManager.notLoadedCount(groupId),
5865
feedDatabaseManager.oldestSubscriptionUpdate(groupId),
5966

60-
Function5 { t1: FeedEventManager.Event, t2: Boolean, t3: Boolean,
61-
t4: Long, t5: List<OffsetDateTime> ->
62-
return@Function5 CombineResultEventHolder(t1, t2, t3, t4, t5.firstOrNull())
67+
Function6 { t1: FeedEventManager.Event, t2: Boolean, t3: Boolean, t4: Boolean,
68+
t5: Long, t6: List<OffsetDateTime> ->
69+
return@Function6 CombineResultEventHolder(t1, t2, t3, t4, t5, t6.firstOrNull())
6370
}
6471
)
6572
.throttleLatest(DEFAULT_THROTTLE_TIMEOUT, TimeUnit.MILLISECONDS)
6673
.subscribeOn(Schedulers.io())
6774
.observeOn(Schedulers.io())
68-
.map { (event, showPlayedItems, showFutureItems, notLoadedCount, oldestUpdate) ->
75+
.map { (event, showPlayedItems, showPartiallyPlayedItems, showFutureItems, notLoadedCount, oldestUpdate) ->
6976
val streamItems = if (event is SuccessResultEvent || event is IdleEvent)
7077
feedDatabaseManager
71-
.getStreams(groupId, showPlayedItems, showFutureItems)
78+
.getStreams(groupId, showPlayedItems, showPartiallyPlayedItems, showFutureItems)
7279
.blockingGet(arrayListOf())
7380
else
7481
arrayListOf()
@@ -100,8 +107,9 @@ class FeedViewModel(
100107
val t1: FeedEventManager.Event,
101108
val t2: Boolean,
102109
val t3: Boolean,
103-
val t4: Long,
104-
val t5: OffsetDateTime?
110+
val t4: Boolean,
111+
val t5: Long,
112+
val t6: OffsetDateTime?
105113
)
106114

107115
private data class CombineResultDataHolder(
@@ -111,44 +119,57 @@ class FeedViewModel(
111119
val t4: OffsetDateTime?
112120
)
113121

114-
fun togglePlayedItems(showPlayedItems: Boolean) {
115-
toggleShowPlayedItems.onNext(showPlayedItems)
116-
}
117-
118-
fun saveShowPlayedItemsToPreferences(showPlayedItems: Boolean) =
122+
fun setSaveShowPlayedItems(showPlayedItems: Boolean) {
123+
this.showPlayedItems.onNext(showPlayedItems)
119124
PreferenceManager.getDefaultSharedPreferences(application).edit {
120-
this.putBoolean(application.getString(R.string.feed_show_played_items_key), showPlayedItems)
125+
this.putBoolean(application.getString(R.string.feed_show_watched_items_key), showPlayedItems)
121126
this.apply()
122127
}
128+
}
123129

124130
fun getShowPlayedItemsFromPreferences() = getShowPlayedItemsFromPreferences(application)
125131

126-
fun toggleFutureItems(showFutureItems: Boolean) {
127-
toggleShowFutureItems.onNext(showFutureItems)
132+
fun setSaveShowPartiallyPlayedItems(showPartiallyPlayedItems: Boolean) {
133+
this.showPartiallyPlayedItems.onNext(showPartiallyPlayedItems)
134+
PreferenceManager.getDefaultSharedPreferences(application).edit {
135+
this.putBoolean(application.getString(R.string.feed_show_partially_watched_items_key), showPartiallyPlayedItems)
136+
this.apply()
137+
}
128138
}
129139

130-
fun saveShowFutureItemsToPreferences(showFutureItems: Boolean) =
140+
fun getShowPartiallyPlayedItemsFromPreferences() = getShowPartiallyPlayedItemsFromPreferences(application)
141+
142+
fun setSaveShowFutureItems(showFutureItems: Boolean) {
143+
this.showFutureItems.onNext(showFutureItems)
131144
PreferenceManager.getDefaultSharedPreferences(application).edit {
132145
this.putBoolean(application.getString(R.string.feed_show_future_items_key), showFutureItems)
133146
this.apply()
134147
}
148+
}
135149

136150
fun getShowFutureItemsFromPreferences() = getShowFutureItemsFromPreferences(application)
137151

138152
companion object {
139153
private fun getShowPlayedItemsFromPreferences(context: Context) =
140154
PreferenceManager.getDefaultSharedPreferences(context)
141-
.getBoolean(context.getString(R.string.feed_show_played_items_key), true)
155+
.getBoolean(context.getString(R.string.feed_show_watched_items_key), true)
156+
157+
private fun getShowPartiallyPlayedItemsFromPreferences(context: Context) =
158+
PreferenceManager.getDefaultSharedPreferences(context)
159+
.getBoolean(context.getString(R.string.feed_show_partially_watched_items_key), true)
160+
142161
private fun getShowFutureItemsFromPreferences(context: Context) =
143162
PreferenceManager.getDefaultSharedPreferences(context)
144163
.getBoolean(context.getString(R.string.feed_show_future_items_key), true)
164+
145165
fun getFactory(context: Context, groupId: Long) = viewModelFactory {
146166
initializer {
147167
FeedViewModel(
148168
App.getApp(),
149169
groupId,
150170
// Read initial value from preferences
151171
getShowPlayedItemsFromPreferences(context.applicationContext),
172+
getShowPartiallyPlayedItemsFromPreferences(context.applicationContext),
152173
getShowFutureItemsFromPreferences(context.applicationContext)
153174
)
154175
}

app/src/main/java/org/schabi/newpipe/local/history/HistoryRecordManager.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ public HistoryRecordManager(final Context context) {
8787
* Marks a stream item as watched such that it is hidden from the feed if watched videos are
8888
* hidden. Adds a history entry and updates the stream progress to 100%.
8989
*
90-
* @see FeedViewModel#togglePlayedItems
90+
* @see FeedViewModel#setSaveShowPlayedItems
9191
* @param info the item to mark as watched
9292
* @return a Maybe containing the ID of the item if successful
9393
*/

app/src/main/res/menu/menu_feed_fragment.xml

+1-12
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,8 @@
55
<item
66
android:id="@+id/menu_item_feed_toggle_played_items"
77
android:orderInCategory="2"
8-
android:checkable="true"
9-
android:checked="true"
108
android:icon="@drawable/ic_visibility_on"
11-
android:title="@string/feed_toggle_show_played_items"
12-
app:showAsAction="ifRoom" />
13-
14-
<item
15-
android:id="@+id/menu_item_feed_toggle_future_items"
16-
android:orderInCategory="3"
17-
android:checkable="true"
18-
android:checked="true"
19-
android:icon="@drawable/ic_history_future"
20-
android:title="@string/feed_toggle_show_future_items"
9+
android:title="@string/feed_show_hide_streams"
2110
app:showAsAction="ifRoom" />
2211

2312
<item

app/src/main/res/values/settings_keys.xml

+2-1
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,8 @@
284284

285285
<string name="feed_update_threshold_key">feed_update_threshold_key</string>
286286
<string name="feed_update_threshold_default_value">300</string>
287-
<string name="feed_show_played_items_key">feed_show_played_items</string>
287+
<string name="feed_show_watched_items_key">feed_show_played_items</string>
288+
<string name="feed_show_partially_watched_items_key">feed_show_partially_watched_items</string>
288289
<string name="feed_show_future_items_key">feed_show_future_items</string>
289290

290291
<string name="show_thumbnail_key">show_thumbnail_key</string>

0 commit comments

Comments
 (0)