Skip to content

Commit e412909

Browse files
committed
feat: redesign watch history fragment to match the downloads fragment design
1 parent f132383 commit e412909

5 files changed

Lines changed: 72 additions & 115 deletions

File tree

app/src/main/java/com/github/libretube/constants/PreferenceKeys.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,6 @@ object PreferenceKeys {
135135

136136
// History
137137
const val WATCH_HISTORY_SIZE = "watch_history_size"
138-
const val SELECTED_HISTORY_TYPE_FILTER = "filter_history_type"
139138
const val SELECTED_HISTORY_STATUS_FILTER = "filter_history_status"
140139

141140
// Internally saved data / not a preference

app/src/main/java/com/github/libretube/db/DatabaseHelper.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,9 @@ object DatabaseHelper {
9595
}
9696
}
9797

98+
/**
99+
* @param unfinished If true, only returns unfinished videos. If false, only returns finished videos.
100+
*/
98101
suspend fun filterByWatchStatus(
99102
watchHistoryItem: WatchHistoryItem,
100103
unfinished: Boolean = true

app/src/main/java/com/github/libretube/ui/fragments/WatchHistoryFragment.kt

Lines changed: 15 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ import com.github.libretube.ui.extensions.addOnBottomReachedListener
2828
import com.github.libretube.ui.extensions.setupFragmentAnimation
2929
import com.github.libretube.ui.models.CommonPlayerViewModel
3030
import com.github.libretube.ui.models.WatchHistoryModel
31-
import com.github.libretube.ui.sheets.BaseBottomSheet
3231
import com.github.libretube.util.PlayingQueue
3332
import com.google.android.material.dialog.MaterialAlertDialogBuilder
3433
import kotlinx.coroutines.CoroutineScope
@@ -86,10 +85,8 @@ class WatchHistoryFragment : DynamicLayoutManagerFragment(R.layout.fragment_watc
8685
}
8786
})
8887

89-
binding.filterTypeTV.text =
90-
resources.getStringArray(R.array.filterOptions)[viewModel.selectedTypeFilter]
91-
binding.filterStatusTV.text =
92-
resources.getStringArray(R.array.filterStatusOptions)[viewModel.selectedStatusFilter]
88+
binding.chipContinue.isChecked = viewModel.selectedStatusFilter in arrayOf(0, 1)
89+
binding.chipFinished.isChecked = viewModel.selectedStatusFilter in arrayOf(0, 2)
9390

9491
val watchPositionItem = arrayOf(getString(R.string.also_clear_watch_positions))
9592
val selected = booleanArrayOf(false)
@@ -103,6 +100,9 @@ class WatchHistoryFragment : DynamicLayoutManagerFragment(R.layout.fragment_watc
103100
.setPositiveButton(R.string.okay) { _, _ ->
104101
binding.watchHistoryRecView.isGone = true
105102
binding.historyEmpty.isVisible = true
103+
binding.historyOptions.isGone = true
104+
binding.statusFilterChips.isGone = true
105+
106106
lifecycleScope.launch(Dispatchers.IO) {
107107
Database.withTransaction {
108108
Database.watchHistoryDao().deleteAll()
@@ -114,26 +114,15 @@ class WatchHistoryFragment : DynamicLayoutManagerFragment(R.layout.fragment_watc
114114
.show()
115115
}
116116

117-
binding.filterTypeTV.setOnClickListener {
118-
val filterOptions = resources.getStringArray(R.array.filterOptions)
119-
120-
BaseBottomSheet().apply {
121-
setSimpleItems(filterOptions.toList()) { index ->
122-
binding.filterTypeTV.text = filterOptions[index]
123-
viewModel.selectedTypeFilter = index
124-
}
125-
}.show(childFragmentManager)
126-
}
127-
128-
binding.filterStatusTV.setOnClickListener {
129-
val filterOptions = resources.getStringArray(R.array.filterStatusOptions)
130-
131-
BaseBottomSheet().apply {
132-
setSimpleItems(filterOptions.toList()) { index ->
133-
binding.filterStatusTV.text = filterOptions[index]
134-
viewModel.selectedStatusFilter = index
135-
}
136-
}.show(childFragmentManager)
117+
binding.statusFilterChips.setOnCheckedStateChangeListener { _, checkedIds ->
118+
val continueWatchingEnabled = checkedIds.contains(binding.chipContinue.id)
119+
val finishedEnabled = checkedIds.contains(binding.chipFinished.id)
120+
viewModel.selectedStatusFilter = when {
121+
continueWatchingEnabled && finishedEnabled -> 0
122+
continueWatchingEnabled -> 1
123+
finishedEnabled -> 2
124+
else -> 0
125+
}
137126
}
138127

139128
binding.playAll.setOnClickListener {
@@ -152,8 +141,8 @@ class WatchHistoryFragment : DynamicLayoutManagerFragment(R.layout.fragment_watc
152141

153142
viewModel.filteredWatchHistory.observe(viewLifecycleOwner) { history ->
154143
binding.historyEmpty.isGone = history.isNotEmpty()
155-
binding.playAll.isEnabled = history.isNotEmpty()
156144
binding.watchHistoryRecView.isVisible = history.isNotEmpty()
145+
binding.historyOptions.isVisible = history.isNotEmpty()
157146

158147
watchHistoryAdapter.submitList(history)
159148
}

app/src/main/java/com/github/libretube/ui/models/WatchHistoryModel.kt

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,9 @@ class WatchHistoryModel : ViewModel() {
2727
private val selectedStatus = MutableStateFlow(
2828
PreferenceHelper.getInt(PreferenceKeys.SELECTED_HISTORY_STATUS_FILTER, 0)
2929
)
30-
private val selectedType = MutableStateFlow(
31-
PreferenceHelper.getInt(PreferenceKeys.SELECTED_HISTORY_TYPE_FILTER, 0)
32-
)
3330

3431
val filteredWatchHistory =
35-
combine(watchHistory.asFlow(), selectedStatus, selectedType) { history, _, _ -> history }
32+
combine(watchHistory.asFlow(), selectedStatus) { history, _ -> history }
3633
.flowOn(Dispatchers.IO).map { history -> history.filter { it.shouldIncludeByFilters() } }
3734
.asLiveData()
3835

@@ -43,25 +40,7 @@ class WatchHistoryModel : ViewModel() {
4340
selectedStatus.value = value
4441
}
4542

46-
var selectedTypeFilter
47-
get() = selectedType.value
48-
set(value) {
49-
PreferenceHelper.putInt(PreferenceKeys.SELECTED_HISTORY_TYPE_FILTER, value)
50-
selectedType.value = value
51-
}
52-
5343
private suspend fun WatchHistoryItem.shouldIncludeByFilters(): Boolean {
54-
val isLive = (duration ?: -1L) < 0L
55-
val matchesFilter = when (selectedTypeFilter) {
56-
0 -> true
57-
1 -> !isShort && !isLive
58-
2 -> isShort // where is the StreamItem converted to watchHistoryItem?
59-
3 -> isLive
60-
else -> throw IllegalArgumentException()
61-
}
62-
63-
if (!matchesFilter) return false
64-
6544
// no watch position filter
6645
if (selectedStatusFilter == 0) return true
6746

app/src/main/res/layout/fragment_watch_history.xml

Lines changed: 53 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
33
xmlns:app="http://schemas.android.com/apk/res-auto"
44
android:layout_width="match_parent"
5-
android:layout_height="match_parent">
5+
android:layout_height="match_parent"
6+
xmlns:tools="http://schemas.android.com/tools">
67

78
<LinearLayout
89
android:id="@+id/history_empty"
@@ -45,75 +46,29 @@
4546
app:layout_scrollFlags="scroll"
4647
app:titleCollapseMode="scale">
4748

48-
<LinearLayout
49+
<com.google.android.material.chip.ChipGroup
50+
android:id="@+id/status_filter_chips"
4951
android:layout_width="match_parent"
5052
android:layout_height="wrap_content"
51-
android:orientation="vertical">
52-
53-
<LinearLayout
54-
android:layout_width="match_parent"
53+
tools:checkedChip="@id/chip_continue"
54+
app:selectionRequired="true"
55+
android:paddingHorizontal="12dp">
56+
57+
<com.google.android.material.chip.Chip
58+
style="@style/Widget.Material3.Chip.Filter"
59+
android:id="@+id/chip_continue"
60+
android:layout_width="wrap_content"
5561
android:layout_height="wrap_content"
56-
android:layout_marginBottom="10dp"
57-
android:orientation="horizontal">
58-
59-
<com.google.android.material.button.MaterialButton
60-
android:id="@+id/play_all"
61-
style="@style/Widget.Material3.Button.OutlinedButton"
62-
android:layout_width="0dp"
63-
android:layout_height="wrap_content"
64-
android:layout_marginHorizontal="10dp"
65-
android:layout_weight="1"
66-
android:maxLines="1"
67-
android:text="@string/play_all"
68-
app:icon="@drawable/ic_playlist" />
69-
70-
<com.google.android.material.button.MaterialButton
71-
android:id="@+id/clear"
72-
style="@style/Widget.Material3.Button"
73-
android:layout_width="0dp"
74-
android:layout_height="wrap_content"
75-
android:layout_marginHorizontal="10dp"
76-
android:layout_weight="1"
77-
android:maxLines="1"
78-
android:text="@string/clear_history"
79-
app:icon="@drawable/ic_delete" />
80-
81-
</LinearLayout>
82-
83-
<FrameLayout
84-
android:layout_width="match_parent"
62+
android:text="@string/continue_watching"/>
63+
64+
<com.google.android.material.chip.Chip
65+
style="@style/Widget.Material3.Chip.Filter"
66+
android:id="@+id/chip_finished"
67+
android:layout_width="wrap_content"
8568
android:layout_height="wrap_content"
86-
android:layout_marginBottom="5dp">
87-
88-
<TextView
89-
android:id="@+id/filterTypeTV"
90-
android:layout_width="wrap_content"
91-
android:layout_height="wrap_content"
92-
android:layout_gravity="top"
93-
android:layout_marginStart="5dp"
94-
android:drawablePadding="5dp"
95-
android:paddingHorizontal="10dp"
96-
android:text="@string/all"
97-
android:textSize="16sp"
98-
android:tooltipText="@string/tooltip_filter"
99-
app:drawableEndCompat="@drawable/ic_filter" />
100-
101-
<TextView
102-
android:id="@+id/filterStatusTV"
103-
android:layout_width="wrap_content"
104-
android:layout_height="wrap_content"
105-
android:layout_gravity="end"
106-
android:layout_marginEnd="5dp"
107-
android:drawablePadding="5dp"
108-
android:paddingHorizontal="10dp"
109-
android:text="@string/watched"
110-
android:textSize="16sp"
111-
android:tooltipText="@string/tooltip_filter"
112-
app:drawableEndCompat="@drawable/ic_filter" />
113-
114-
</FrameLayout>
115-
116-
</LinearLayout>
69+
android:text="@string/finished"/>
70+
71+
</com.google.android.material.chip.ChipGroup>
11772

11873
</com.google.android.material.appbar.CollapsingToolbarLayout>
11974

@@ -128,4 +83,36 @@
12883

12984
</androidx.coordinatorlayout.widget.CoordinatorLayout>
13085

86+
<LinearLayout
87+
android:id="@+id/history_options"
88+
android:layout_width="wrap_content"
89+
android:layout_height="wrap_content"
90+
android:orientation="vertical"
91+
android:padding="16dp"
92+
android:layout_gravity="end|bottom">
93+
94+
<com.google.android.material.floatingactionbutton.FloatingActionButton
95+
android:id="@+id/clear"
96+
style="?attr/floatingActionButtonSmallSecondaryStyle"
97+
android:layout_width="wrap_content"
98+
android:layout_height="wrap_content"
99+
android:layout_gravity="end"
100+
android:contentDescription="@string/clear_history"
101+
android:src="@drawable/ic_delete"
102+
android:tooltipText="@string/clear_history"
103+
tools:targetApi="o"
104+
tools:visibility="visible" />
105+
106+
<com.google.android.material.floatingactionbutton.FloatingActionButton
107+
android:id="@+id/play_all"
108+
android:layout_width="wrap_content"
109+
android:layout_height="wrap_content"
110+
android:contentDescription="@string/play_all"
111+
android:src="@drawable/ic_play"
112+
android:layout_marginTop="8dp"
113+
android:tooltipText="@string/play_all"
114+
tools:visibility="visible" />
115+
116+
</LinearLayout>
117+
131118
</FrameLayout>

0 commit comments

Comments
 (0)