Skip to content

Commit fd7cd9e

Browse files
committed
Load settings in LongPressMenu too
1 parent 8214cdd commit fd7cd9e

3 files changed

Lines changed: 98 additions & 26 deletions

File tree

app/src/main/java/org/schabi/newpipe/ui/components/menu/LongPressAction.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.schabi.newpipe.ui.components.menu
22

33
import android.content.Context
4+
import android.net.Uri
45
import android.widget.Toast
56
import androidx.annotation.StringRes
67
import androidx.compose.material.icons.Icons
@@ -21,6 +22,7 @@ import androidx.compose.material.icons.filled.PlayArrow
2122
import androidx.compose.material.icons.filled.QueuePlayNext
2223
import androidx.compose.material.icons.filled.Share
2324
import androidx.compose.ui.graphics.vector.ImageVector
25+
import androidx.core.net.toUri
2426
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
2527
import org.schabi.newpipe.R
2628
import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry
@@ -49,6 +51,7 @@ import org.schabi.newpipe.ui.components.menu.icons.PlayFromHere
4951
import org.schabi.newpipe.ui.components.menu.icons.PopupFromHere
5052
import org.schabi.newpipe.util.NavigationHelper
5153
import org.schabi.newpipe.util.SparseItemUtil
54+
import org.schabi.newpipe.util.external_communication.KoreUtils
5255
import org.schabi.newpipe.util.external_communication.ShareUtils
5356

5457
data class LongPressAction(
@@ -228,13 +231,10 @@ data class LongPressAction(
228231
.observeOn(AndroidSchedulers.mainThread())
229232
.subscribe()
230233
},
234+
Type.PlayWithKodi.buildAction { context ->
235+
KoreUtils.playWithKore(context, item.url.toUri())
236+
},
231237
)
232-
/* TODO handle kodi
233-
+ if (isKodiEnabled) listOf(
234-
Type.PlayWithKodi.buildAction { context ->
235-
KoreUtils.playWithKore(context, Uri.parse(item.url))
236-
},
237-
) else listOf()*/
238238
}
239239

240240
@JvmStatic

app/src/main/java/org/schabi/newpipe/ui/components/menu/LongPressMenu.kt

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ import androidx.compose.material3.Text
4343
import androidx.compose.material3.rememberModalBottomSheetState
4444
import androidx.compose.runtime.Composable
4545
import androidx.compose.runtime.DisposableEffect
46+
import androidx.compose.runtime.collectAsState
47+
import androidx.compose.runtime.derivedStateOf
4648
import androidx.compose.runtime.getValue
4749
import androidx.compose.runtime.mutableStateOf
4850
import androidx.compose.runtime.remember
@@ -70,10 +72,10 @@ import androidx.compose.ui.tooling.preview.datasource.LoremIpsum
7072
import androidx.compose.ui.unit.dp
7173
import androidx.compose.ui.window.Dialog
7274
import androidx.compose.ui.window.DialogProperties
75+
import androidx.lifecycle.viewmodel.compose.viewModel
7376
import coil3.compose.AsyncImage
7477
import org.schabi.newpipe.R
7578
import org.schabi.newpipe.extractor.stream.StreamType
76-
import org.schabi.newpipe.ktx.popFirst
7779
import org.schabi.newpipe.ui.components.common.ScaffoldWithToolbar
7880
import org.schabi.newpipe.ui.components.menu.LongPressAction.Type.EnqueueNext
7981
import org.schabi.newpipe.ui.components.menu.LongPressAction.Type.ShowChannelDetails
@@ -123,6 +125,9 @@ fun LongPressMenu(
123125
longPressActions: List<LongPressAction>,
124126
onDismissRequest: () -> Unit,
125127
) {
128+
val viewModel: LongPressMenuViewModel = viewModel()
129+
val isHeaderEnabled by viewModel.isHeaderEnabled.collectAsState()
130+
val actionArrangement by viewModel.actionArrangement.collectAsState()
126131
var showEditor by rememberSaveable { mutableStateOf(false) }
127132
val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
128133

@@ -140,14 +145,39 @@ fun LongPressMenu(
140145
}
141146
}
142147
} else {
148+
val enabledLongPressActions by remember {
149+
derivedStateOf {
150+
actionArrangement.mapNotNull { type ->
151+
longPressActions.firstOrNull { it.type == type }
152+
}
153+
}
154+
}
155+
156+
// show a clickable uploader in the header if an uploader action is available and the
157+
// "show channel details" action is not enabled as a standalone action
158+
val ctx = LocalContext.current
159+
val onUploaderClick by remember {
160+
derivedStateOf {
161+
longPressActions.firstOrNull { it.type == ShowChannelDetails }
162+
?.takeIf { !actionArrangement.contains(ShowChannelDetails) }
163+
?.let { showChannelDetailsAction ->
164+
{
165+
showChannelDetailsAction.action(ctx)
166+
onDismissRequest()
167+
}
168+
}
169+
}
170+
}
171+
143172
ModalBottomSheet(
144173
sheetState = sheetState,
145174
onDismissRequest = onDismissRequest,
146175
dragHandle = { LongPressMenuDragHandle(onEditActions = { showEditor = true }) },
147176
) {
148177
LongPressMenuContent(
149-
longPressable = longPressable,
150-
longPressActions = longPressActions,
178+
header = longPressable.takeIf { isHeaderEnabled },
179+
onUploaderClick = onUploaderClick,
180+
actions = enabledLongPressActions,
151181
onDismissRequest = onDismissRequest,
152182
)
153183
}
@@ -156,8 +186,9 @@ fun LongPressMenu(
156186

157187
@Composable
158188
private fun LongPressMenuContent(
159-
longPressable: LongPressable,
160-
longPressActions: List<LongPressAction>,
189+
header: LongPressable?,
190+
onUploaderClick: (() -> Unit)?,
191+
actions: List<LongPressAction>,
161192
onDismissRequest: () -> Unit,
162193
) {
163194
BoxWithConstraints(
@@ -172,20 +203,10 @@ private fun LongPressMenuContent(
172203
// width for the landscape/reduced header, measured in button widths
173204
val headerWidthInButtonsReducedSpan = 4
174205
val buttonsPerRow = (this.maxWidth / MinButtonWidth).toInt()
175-
176-
// the channel icon goes in the menu header, so do not show a button for it
177-
val actions = longPressActions.toMutableList()
178206
val ctx = LocalContext.current
179-
val onUploaderClick = actions.popFirst { it.type == ShowChannelDetails }
180-
?.let { showChannelDetailsAction ->
181-
{
182-
showChannelDetailsAction.action(ctx)
183-
onDismissRequest()
184-
}
185-
}
186207

187208
Column {
188-
var actionIndex = -1 // -1 indicates the header
209+
var actionIndex = if (header != null) -1 else 0 // -1 indicates the header
189210
while (actionIndex < actions.size) {
190211
Row(
191212
verticalAlignment = Alignment.CenterVertically,
@@ -224,7 +245,7 @@ private fun LongPressMenuContent(
224245
// this branch is taken if the full-span header is going to fit on one
225246
// line (i.e. on phones in portrait)
226247
LongPressMenuHeader(
227-
item = longPressable,
248+
item = header!!, // surely not null since actionIndex < 0
228249
onUploaderClick = onUploaderClick,
229250
modifier = Modifier
230251
.padding(start = 6.dp, end = 6.dp, bottom = 6.dp)
@@ -241,7 +262,7 @@ private fun LongPressMenuContent(
241262
// branch is taken, at least two buttons will be on the right side of
242263
// the header (just one button would look off).
243264
LongPressMenuHeader(
244-
item = longPressable,
265+
item = header!!, // surely not null since actionIndex < 0
245266
onUploaderClick = onUploaderClick,
246267
modifier = Modifier
247268
.padding(start = 8.dp, top = 11.dp, bottom = 11.dp)
@@ -667,8 +688,9 @@ private fun LongPressMenuPreview(
667688
// longPressable is null when running the preview in an emulator for some reason...
668689
@Suppress("USELESS_ELVIS")
669690
LongPressMenuContent(
670-
longPressable = longPressable ?: LongPressablePreviews().values.first(),
671-
longPressActions = LongPressAction.Type.entries
691+
header = longPressable ?: LongPressablePreviews().values.first(),
692+
onUploaderClick = {},
693+
actions = LongPressAction.Type.entries
672694
// disable Enqueue actions just to show it off
673695
.map { t -> t.buildAction({ t != EnqueueNext }) { } },
674696
onDismissRequest = {},
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package org.schabi.newpipe.ui.components.menu
2+
3+
import android.content.Context
4+
import android.content.SharedPreferences
5+
import androidx.lifecycle.ViewModel
6+
import androidx.preference.PreferenceManager
7+
import kotlinx.coroutines.flow.MutableStateFlow
8+
import kotlinx.coroutines.flow.StateFlow
9+
import kotlinx.coroutines.flow.asStateFlow
10+
import org.schabi.newpipe.App
11+
import org.schabi.newpipe.R
12+
13+
/**
14+
* Since view models can't have access to the UI's Context, we use [App.instance] instead to fetch
15+
* shared preferences. This is not the best but won't be needed anyway once we will have a Hilt
16+
* injected repository that provides access to a modern alternative to shared preferences. The whole
17+
* thing with the shared preference listener will not be necessary with the modern alternative.
18+
*/
19+
class LongPressMenuViewModel : ViewModel() {
20+
private val _isHeaderEnabled = MutableStateFlow(
21+
loadIsHeaderEnabledFromSettings(App.instance)
22+
)
23+
val isHeaderEnabled: StateFlow<Boolean> = _isHeaderEnabled.asStateFlow()
24+
25+
private val _actionArrangement = MutableStateFlow(
26+
loadLongPressActionArrangementFromSettings(App.instance)
27+
)
28+
val actionArrangement: StateFlow<List<LongPressAction.Type>> = _actionArrangement.asStateFlow()
29+
30+
private val prefs = PreferenceManager.getDefaultSharedPreferences(App.instance)
31+
private val isHeaderEnabledKey =
32+
App.instance.getString(R.string.long_press_menu_is_header_enabled_key)
33+
private val actionArrangementKey =
34+
App.instance.getString(R.string.long_press_menu_action_arrangement_key)
35+
private val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, key ->
36+
if (key == isHeaderEnabledKey) {
37+
_isHeaderEnabled.value = loadIsHeaderEnabledFromSettings(App.instance)
38+
} else if (key == actionArrangementKey) {
39+
_actionArrangement.value = loadLongPressActionArrangementFromSettings(App.instance)
40+
}
41+
}
42+
43+
init {
44+
prefs.registerOnSharedPreferenceChangeListener(listener)
45+
}
46+
47+
override fun onCleared() {
48+
prefs.unregisterOnSharedPreferenceChangeListener(listener)
49+
}
50+
}

0 commit comments

Comments
 (0)