22
33package org.schabi.newpipe.ui.components.menu
44
5+ import android.content.res.Configuration
56import androidx.compose.foundation.basicMarquee
67import androidx.compose.foundation.layout.Arrangement
78import androidx.compose.foundation.layout.Box
89import androidx.compose.foundation.layout.BoxWithConstraints
910import androidx.compose.foundation.layout.Column
1011import androidx.compose.foundation.layout.ExperimentalLayoutApi
1112import androidx.compose.foundation.layout.FlowRow
13+ import androidx.compose.foundation.layout.PaddingValues
1214import androidx.compose.foundation.layout.Row
1315import androidx.compose.foundation.layout.Spacer
1416import androidx.compose.foundation.layout.fillMaxWidth
@@ -18,8 +20,22 @@ import androidx.compose.foundation.layout.size
1820import androidx.compose.foundation.layout.width
1921import androidx.compose.foundation.layout.widthIn
2022import androidx.compose.material.icons.Icons
23+ import androidx.compose.material.icons.automirrored.filled.PlaylistAdd
2124import androidx.compose.material.icons.automirrored.filled.PlaylistPlay
25+ import androidx.compose.material.icons.filled.AddToQueue
26+ import androidx.compose.material.icons.filled.Delete
27+ import androidx.compose.material.icons.filled.Done
28+ import androidx.compose.material.icons.filled.Download
29+ import androidx.compose.material.icons.filled.Headset
30+ import androidx.compose.material.icons.filled.OpenInBrowser
31+ import androidx.compose.material.icons.filled.Person
32+ import androidx.compose.material.icons.filled.PictureInPicture
33+ import androidx.compose.material.icons.filled.PlayArrow
34+ import androidx.compose.material.icons.filled.PlaylistAdd
35+ import androidx.compose.material.icons.filled.QueuePlayNext
36+ import androidx.compose.material.icons.filled.Share
2237import androidx.compose.material3.ExperimentalMaterial3Api
38+ import androidx.compose.material3.FilledTonalButton
2339import androidx.compose.material3.Icon
2440import androidx.compose.material3.MaterialTheme
2541import androidx.compose.material3.ModalBottomSheet
@@ -34,6 +50,7 @@ import androidx.compose.ui.Alignment
3450import androidx.compose.ui.Modifier
3551import androidx.compose.ui.draw.clip
3652import androidx.compose.ui.graphics.Color
53+ import androidx.compose.ui.graphics.vector.ImageVector
3754import androidx.compose.ui.platform.LocalContext
3855import androidx.compose.ui.res.painterResource
3956import androidx.compose.ui.res.stringResource
@@ -48,6 +65,7 @@ import coil3.compose.AsyncImage
4865import org.schabi.newpipe.R
4966import org.schabi.newpipe.player.playqueue.PlayQueue
5067import org.schabi.newpipe.player.playqueue.SinglePlayQueue
68+ import org.schabi.newpipe.ui.theme.AppTheme
5169import org.schabi.newpipe.util.Either
5270import org.schabi.newpipe.util.Localization
5371import java.time.OffsetDateTime
@@ -67,12 +85,12 @@ fun LongPressMenu(
6785 .padding(bottom = 16 .dp)
6886 ) {
6987 val maxContainerWidth = maxWidth
70- val minButtonWidth = 60 .dp
88+ val minButtonWidth = 70 .dp
7189 val buttonHeight = 70 .dp
7290 val padding = 12 .dp
7391 val boxCount = ((maxContainerWidth - padding) / (minButtonWidth + padding)).toInt()
7492 val buttonWidth = (maxContainerWidth - (boxCount + 1 ) * padding) / boxCount
75- val desiredHeaderWidth = buttonWidth * 5 + padding * 4
93+ val desiredHeaderWidth = buttonWidth * 4 + padding * 3
7694
7795 FlowRow (
7896 horizontalArrangement = Arrangement .spacedBy(padding),
@@ -95,9 +113,91 @@ fun LongPressMenu(
95113 }
96114 )
97115
98- for (i in 0 .. 10 ) {
99- LongPressMenuButton (modifier = Modifier .size(buttonWidth, buttonHeight))
100- }
116+ LongPressMenuButton (
117+ icon = Icons .Default .AddToQueue ,
118+ text = stringResource(R .string.enqueue),
119+ onClick = {},
120+ enabled = false ,
121+ modifier = Modifier .size(buttonWidth, buttonHeight),
122+ )
123+
124+ LongPressMenuButton (
125+ icon = Icons .Default .QueuePlayNext ,
126+ text = stringResource(R .string.enqueue_next_stream),
127+ onClick = {},
128+ enabled = false ,
129+ modifier = Modifier .size(buttonWidth, buttonHeight),
130+ )
131+
132+ LongPressMenuButton (
133+ icon = Icons .Default .Headset ,
134+ text = stringResource(R .string.controls_background_title),
135+ onClick = {},
136+ modifier = Modifier .size(buttonWidth, buttonHeight),
137+ )
138+
139+ LongPressMenuButton (
140+ icon = Icons .Default .PictureInPicture ,
141+ text = stringResource(R .string.controls_popup_title),
142+ onClick = {},
143+ modifier = Modifier .size(buttonWidth, buttonHeight),
144+ )
145+
146+ LongPressMenuButton (
147+ icon = Icons .Default .PlayArrow ,
148+ text = stringResource(R .string.play),
149+ onClick = {},
150+ modifier = Modifier .size(buttonWidth, buttonHeight),
151+ )
152+
153+ LongPressMenuButton (
154+ icon = Icons .Default .Download ,
155+ text = stringResource(R .string.download),
156+ onClick = {},
157+ modifier = Modifier .size(buttonWidth, buttonHeight),
158+ )
159+
160+ LongPressMenuButton (
161+ icon = Icons .AutoMirrored .Default .PlaylistAdd ,
162+ text = stringResource(R .string.add_to_playlist),
163+ onClick = {},
164+ modifier = Modifier .size(buttonWidth, buttonHeight),
165+ )
166+
167+ LongPressMenuButton (
168+ icon = Icons .Default .Share ,
169+ text = stringResource(R .string.share),
170+ onClick = {},
171+ modifier = Modifier .size(buttonWidth, buttonHeight),
172+ )
173+
174+ LongPressMenuButton (
175+ icon = Icons .Default .OpenInBrowser ,
176+ text = stringResource(R .string.open_in_browser),
177+ onClick = {},
178+ modifier = Modifier .size(buttonWidth, buttonHeight),
179+ )
180+
181+ LongPressMenuButton (
182+ icon = Icons .Default .Done ,
183+ text = stringResource(R .string.mark_as_watched),
184+ onClick = {},
185+ modifier = Modifier .size(buttonWidth, buttonHeight),
186+ )
187+
188+ LongPressMenuButton (
189+ icon = Icons .Default .Person ,
190+ text = stringResource(R .string.show_channel_details),
191+ onClick = {},
192+ modifier = Modifier .size(buttonWidth, buttonHeight),
193+ )
194+
195+ LongPressMenuButton (
196+ icon = Icons .Default .Delete ,
197+ text = stringResource(R .string.delete),
198+ onClick = {},
199+ modifier = Modifier .size(buttonWidth, buttonHeight),
200+ )
101201 }
102202 }
103203 }
@@ -112,8 +212,8 @@ fun LongPressMenuHeader(
112212 val ctx = LocalContext .current
113213
114214 Surface (
115- color = MaterialTheme .colorScheme.primaryContainer ,
116- contentColor = MaterialTheme .colorScheme.onPrimaryContainer ,
215+ color = MaterialTheme .colorScheme.surfaceVariant ,
216+ contentColor = MaterialTheme .colorScheme.onSurfaceVariant ,
117217 shape = MaterialTheme .shapes.large,
118218 modifier = modifier,
119219 ) {
@@ -237,12 +337,40 @@ fun LongPressMenuHeader(
237337}
238338
239339@Composable
240- fun LongPressMenuButton (modifier : Modifier = Modifier ) {
241- Surface (
242- color = Color .Black ,
243- modifier = modifier,
340+ fun LongPressMenuButton (
341+ icon : ImageVector ,
342+ text : String ,
343+ onClick : () -> Unit ,
344+ enabled : Boolean = true,
345+ modifier : Modifier = Modifier ,
346+ ) {
347+ FilledTonalButton (
348+ onClick = onClick,
349+ enabled = enabled,
244350 shape = MaterialTheme .shapes.large,
245- ) { }
351+ contentPadding = PaddingValues (4 .dp),
352+ modifier = modifier,
353+ ) {
354+ Column (horizontalAlignment = Alignment .CenterHorizontally ) {
355+ Icon (
356+ imageVector = icon,
357+ contentDescription = null ,
358+ modifier = Modifier .size(32 .dp),
359+ )
360+ Text (
361+ text = text,
362+ style = MaterialTheme .typography.bodySmall,
363+ maxLines = 1 ,
364+ // make all text visible with marquee (so new users can learn about the button
365+ // labels), but wait 3 seconds before making many parts of the UI move so that
366+ // normal users are not distracted
367+ modifier = Modifier .basicMarquee(
368+ initialDelayMillis = 3000 ,
369+ iterations = if (enabled) 2 else 0 ,
370+ )
371+ )
372+ }
373+ }
246374}
247375
248376private class LongPressablePreviews : CollectionPreviewParameterProvider <LongPressable >(
@@ -323,6 +451,7 @@ private class LongPressablePreviews : CollectionPreviewParameterProvider<LongPre
323451)
324452
325453@Preview
454+ @Preview(uiMode = Configuration .UI_MODE_NIGHT_YES or Configuration .UI_MODE_TYPE_NORMAL )
326455@Preview(device = " spec:width=1280dp,height=800dp,dpi=240" )
327456@Composable
328457private fun LongPressMenuPreview (
@@ -332,9 +461,11 @@ private fun LongPressMenuPreview(
332461 Localization .initPrettyTime(Localization .resolvePrettyTime())
333462 onDispose {}
334463 }
335- LongPressMenu (
336- longPressable = longPressable,
337- onDismissRequest = {},
338- sheetState = rememberStandardBottomSheetState(), // makes it start out as open
339- )
464+ AppTheme {
465+ LongPressMenu (
466+ longPressable = LongPressablePreviews ().values.first(),
467+ onDismissRequest = {},
468+ sheetState = rememberStandardBottomSheetState(), // makes it start out as open
469+ )
470+ }
340471}
0 commit comments