Skip to content

Commit f77bfe5

Browse files
Show dropdown menu on long click, make some adjustments
1 parent 66c1f50 commit f77bfe5

File tree

6 files changed

+206
-78
lines changed

6 files changed

+206
-78
lines changed
Lines changed: 46 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package org.schabi.newpipe.compose.stream
22

33
import android.content.res.Configuration
4-
import androidx.compose.foundation.clickable
4+
import androidx.compose.foundation.ExperimentalFoundationApi
5+
import androidx.compose.foundation.combinedClickable
56
import androidx.compose.foundation.layout.Arrangement
7+
import androidx.compose.foundation.layout.Box
68
import androidx.compose.foundation.layout.Column
79
import androidx.compose.foundation.layout.Row
810
import androidx.compose.foundation.layout.fillMaxWidth
@@ -20,39 +22,55 @@ import androidx.compose.ui.unit.dp
2022
import org.schabi.newpipe.compose.theme.AppTheme
2123
import org.schabi.newpipe.extractor.stream.StreamInfoItem
2224

25+
@OptIn(ExperimentalFoundationApi::class)
2326
@Composable
24-
fun StreamCardItem(stream: StreamInfoItem, onClick: (StreamInfoItem) -> Unit) {
25-
Column(
26-
modifier = Modifier
27-
.clickable(onClick = { onClick(stream) })
28-
.padding(top = 12.dp, start = 2.dp, end = 2.dp)
29-
) {
30-
StreamThumbnail(
31-
stream = stream,
32-
modifier = Modifier.fillMaxWidth(),
33-
contentScale = ContentScale.FillWidth
34-
)
35-
36-
Column(modifier = Modifier.padding(10.dp)) {
37-
Text(
38-
text = stream.name,
39-
overflow = TextOverflow.Ellipsis,
40-
style = MaterialTheme.typography.titleSmall,
41-
maxLines = 2
42-
)
43-
44-
Row(
27+
fun StreamCardItem(
28+
stream: StreamInfoItem,
29+
isSelected: Boolean = false,
30+
onClick: (StreamInfoItem) -> Unit = {},
31+
onLongClick: (StreamInfoItem) -> Unit = {},
32+
onDismissPopup: () -> Unit = {}
33+
) {
34+
Box {
35+
Column(
36+
modifier = Modifier
37+
.combinedClickable(
38+
onLongClick = { onLongClick(stream) },
39+
onClick = { onClick(stream) }
40+
)
41+
.padding(top = 12.dp, start = 2.dp, end = 2.dp)
42+
) {
43+
StreamThumbnail(
4544
modifier = Modifier.fillMaxWidth(),
46-
horizontalArrangement = Arrangement.SpaceBetween
47-
) {
48-
Text(text = stream.uploaderName.orEmpty(), style = MaterialTheme.typography.bodySmall)
45+
stream = stream,
46+
contentScale = ContentScale.FillWidth
47+
)
4948

49+
Column(modifier = Modifier.padding(10.dp)) {
5050
Text(
51-
text = getStreamInfoDetail(stream),
52-
style = MaterialTheme.typography.bodySmall
51+
text = stream.name,
52+
overflow = TextOverflow.Ellipsis,
53+
style = MaterialTheme.typography.titleSmall,
54+
maxLines = 2
5355
)
56+
57+
Row(
58+
modifier = Modifier.fillMaxWidth(),
59+
horizontalArrangement = Arrangement.SpaceBetween
60+
) {
61+
Text(text = stream.uploaderName.orEmpty(), style = MaterialTheme.typography.bodySmall)
62+
63+
Text(
64+
text = getStreamInfoDetail(stream),
65+
style = MaterialTheme.typography.bodySmall
66+
)
67+
}
5468
}
5569
}
70+
71+
if (isSelected) {
72+
StreamMenu(onDismissPopup)
73+
}
5674
}
5775
}
5876

@@ -64,7 +82,7 @@ private fun StreamCardItemPreview(
6482
) {
6583
AppTheme {
6684
Surface(color = MaterialTheme.colorScheme.background) {
67-
StreamCardItem(stream) {}
85+
StreamCardItem(stream)
6886
}
6987
}
7088
}
Lines changed: 41 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package org.schabi.newpipe.compose.stream
22

33
import android.content.res.Configuration
4-
import androidx.compose.foundation.clickable
4+
import androidx.compose.foundation.ExperimentalFoundationApi
5+
import androidx.compose.foundation.combinedClickable
6+
import androidx.compose.foundation.layout.Box
57
import androidx.compose.foundation.layout.Column
68
import androidx.compose.foundation.layout.padding
79
import androidx.compose.foundation.layout.size
@@ -17,28 +19,47 @@ import androidx.compose.ui.unit.dp
1719
import org.schabi.newpipe.compose.theme.AppTheme
1820
import org.schabi.newpipe.extractor.stream.StreamInfoItem
1921

22+
@OptIn(ExperimentalFoundationApi::class)
2023
@Composable
21-
fun StreamGridItem(stream: StreamInfoItem, onClick: (StreamInfoItem) -> Unit) {
22-
Column(
23-
modifier = Modifier
24-
.clickable(onClick = { onClick(stream) })
25-
.padding(12.dp)
26-
) {
27-
StreamThumbnail(stream = stream, modifier = Modifier.size(width = 246.dp, height = 138.dp))
24+
fun StreamGridItem(
25+
stream: StreamInfoItem,
26+
isSelected: Boolean = false,
27+
onClick: (StreamInfoItem) -> Unit = {},
28+
onLongClick: (StreamInfoItem) -> Unit = {},
29+
onDismissPopup: () -> Unit = {}
30+
) {
31+
Box {
32+
Column(
33+
modifier = Modifier
34+
.combinedClickable(
35+
onLongClick = { onLongClick(stream) },
36+
onClick = { onClick(stream) }
37+
)
38+
.padding(12.dp)
39+
) {
40+
StreamThumbnail(
41+
modifier = Modifier.size(width = 246.dp, height = 138.dp),
42+
stream = stream
43+
)
44+
45+
Text(
46+
text = stream.name,
47+
overflow = TextOverflow.Ellipsis,
48+
style = MaterialTheme.typography.titleSmall,
49+
maxLines = 2
50+
)
2851

29-
Text(
30-
text = stream.name,
31-
overflow = TextOverflow.Ellipsis,
32-
style = MaterialTheme.typography.titleSmall,
33-
maxLines = 2
34-
)
52+
Text(text = stream.uploaderName.orEmpty(), style = MaterialTheme.typography.bodySmall)
3553

36-
Text(text = stream.uploaderName.orEmpty(), style = MaterialTheme.typography.bodySmall)
54+
Text(
55+
text = getStreamInfoDetail(stream),
56+
style = MaterialTheme.typography.bodySmall
57+
)
58+
}
3759

38-
Text(
39-
text = getStreamInfoDetail(stream),
40-
style = MaterialTheme.typography.bodySmall
41-
)
60+
if (isSelected) {
61+
StreamMenu(onDismissPopup)
62+
}
4263
}
4364
}
4465

@@ -50,7 +71,7 @@ private fun StreamGridItemPreview(
5071
) {
5172
AppTheme {
5273
Surface(color = MaterialTheme.colorScheme.background) {
53-
StreamGridItem(stream, onClick = {})
74+
StreamGridItem(stream)
5475
}
5576
}
5677
}

app/src/main/java/org/schabi/newpipe/compose/stream/StreamList.kt

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
88
import androidx.compose.foundation.lazy.grid.rememberLazyGridState
99
import androidx.compose.foundation.lazy.rememberLazyListState
1010
import androidx.compose.runtime.Composable
11+
import androidx.compose.runtime.getValue
12+
import androidx.compose.runtime.mutableStateOf
1113
import androidx.compose.runtime.remember
14+
import androidx.compose.runtime.setValue
1215
import androidx.compose.ui.platform.LocalContext
1316
import androidx.compose.ui.unit.dp
1417
import androidx.fragment.app.FragmentActivity
@@ -36,7 +39,20 @@ fun StreamList(
3639
)
3740
}
3841
}
39-
// TODO: Handle long-click by showing a dropdown menu instead of a dialog.
42+
43+
// Handle long clicks
44+
// TODO: Adjust the menu display depending on where it was triggered
45+
var selectedStream by remember { mutableStateOf<StreamInfoItem?>(null) }
46+
val onLongClick = remember {
47+
{ stream: StreamInfoItem ->
48+
selectedStream = stream
49+
}
50+
}
51+
val onDismissPopup = remember {
52+
{
53+
selectedStream = null
54+
}
55+
}
4056

4157
if (mode == ItemViewMode.GRID) {
4258
val gridState = rememberLazyGridState()
@@ -46,7 +62,11 @@ fun StreamList(
4662
gridHeader()
4763

4864
items(streams.itemCount) {
49-
StreamGridItem(streams[it]!!, onClick)
65+
val stream = streams[it]!!
66+
StreamGridItem(
67+
stream, selectedStream == stream, onClick, onLongClick,
68+
onDismissPopup
69+
)
5070
}
5171
}
5272
}
@@ -60,10 +80,12 @@ fun StreamList(
6080

6181
items(streams.itemCount) {
6282
val stream = streams[it]!!
83+
val isSelected = selectedStream == stream
84+
6385
if (mode == ItemViewMode.CARD) {
64-
StreamCardItem(stream, onClick)
86+
StreamCardItem(stream, isSelected, onClick, onLongClick, onDismissPopup)
6587
} else {
66-
StreamListItem(stream, onClick)
88+
StreamListItem(stream, isSelected, onClick, onLongClick, onDismissPopup)
6789
}
6890
}
6991
}
Lines changed: 45 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package org.schabi.newpipe.compose.stream
22

33
import android.content.res.Configuration
4-
import androidx.compose.foundation.clickable
4+
import androidx.compose.foundation.ExperimentalFoundationApi
5+
import androidx.compose.foundation.combinedClickable
56
import androidx.compose.foundation.layout.Arrangement
7+
import androidx.compose.foundation.layout.Box
68
import androidx.compose.foundation.layout.Column
79
import androidx.compose.foundation.layout.Row
810
import androidx.compose.foundation.layout.fillMaxWidth
@@ -21,32 +23,51 @@ import androidx.compose.ui.unit.dp
2123
import org.schabi.newpipe.compose.theme.AppTheme
2224
import org.schabi.newpipe.extractor.stream.StreamInfoItem
2325

26+
@OptIn(ExperimentalFoundationApi::class)
2427
@Composable
25-
fun StreamListItem(stream: StreamInfoItem, onClick: (StreamInfoItem) -> Unit) {
26-
Row(
27-
modifier = Modifier
28-
.clickable(onClick = { onClick(stream) })
29-
.fillMaxWidth()
30-
.padding(12.dp),
31-
horizontalArrangement = Arrangement.spacedBy(4.dp),
32-
verticalAlignment = Alignment.CenterVertically
33-
) {
34-
StreamThumbnail(stream = stream, modifier = Modifier.size(width = 98.dp, height = 55.dp))
35-
36-
Column {
37-
Text(
38-
text = stream.name,
39-
overflow = TextOverflow.Ellipsis,
40-
style = MaterialTheme.typography.titleSmall,
41-
maxLines = 1
28+
fun StreamListItem(
29+
stream: StreamInfoItem,
30+
isSelected: Boolean = false,
31+
onClick: (StreamInfoItem) -> Unit = {},
32+
onLongClick: (StreamInfoItem) -> Unit = {},
33+
onDismissPopup: () -> Unit = {}
34+
) {
35+
Box {
36+
Row(
37+
modifier = Modifier
38+
.combinedClickable(
39+
onLongClick = { onLongClick(stream) },
40+
onClick = { onClick(stream) }
41+
)
42+
.fillMaxWidth()
43+
.padding(12.dp),
44+
horizontalArrangement = Arrangement.spacedBy(4.dp),
45+
verticalAlignment = Alignment.CenterVertically
46+
) {
47+
StreamThumbnail(
48+
modifier = Modifier.size(width = 98.dp, height = 55.dp),
49+
stream = stream
4250
)
4351

44-
Text(text = stream.uploaderName.orEmpty(), style = MaterialTheme.typography.bodySmall)
52+
Column {
53+
Text(
54+
text = stream.name,
55+
overflow = TextOverflow.Ellipsis,
56+
style = MaterialTheme.typography.titleSmall,
57+
maxLines = 1
58+
)
4559

46-
Text(
47-
text = getStreamInfoDetail(stream),
48-
style = MaterialTheme.typography.bodySmall
49-
)
60+
Text(text = stream.uploaderName.orEmpty(), style = MaterialTheme.typography.bodySmall)
61+
62+
Text(
63+
text = getStreamInfoDetail(stream),
64+
style = MaterialTheme.typography.bodySmall
65+
)
66+
}
67+
}
68+
69+
if (isSelected) {
70+
StreamMenu(onDismissPopup)
5071
}
5172
}
5273
}
@@ -59,7 +80,7 @@ private fun StreamListItemPreview(
5980
) {
6081
AppTheme {
6182
Surface(color = MaterialTheme.colorScheme.background) {
62-
StreamListItem(stream, onClick = {})
83+
StreamListItem(stream)
6384
}
6485
}
6586
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package org.schabi.newpipe.compose.stream
2+
3+
import androidx.compose.material3.DropdownMenu
4+
import androidx.compose.material3.DropdownMenuItem
5+
import androidx.compose.material3.Text
6+
import androidx.compose.runtime.Composable
7+
import androidx.compose.ui.res.stringResource
8+
import org.schabi.newpipe.R
9+
10+
@Composable
11+
fun StreamMenu(onDismissRequest: () -> Unit) {
12+
DropdownMenu(expanded = true, onDismissRequest = onDismissRequest) {
13+
DropdownMenuItem(
14+
text = { Text(text = stringResource(R.string.start_here_on_background)) },
15+
onClick = onDismissRequest
16+
)
17+
DropdownMenuItem(
18+
text = { Text(text = stringResource(R.string.start_here_on_popup)) },
19+
onClick = onDismissRequest
20+
)
21+
DropdownMenuItem(
22+
text = { Text(text = stringResource(R.string.download)) },
23+
onClick = onDismissRequest
24+
)
25+
DropdownMenuItem(
26+
text = { Text(text = stringResource(R.string.add_to_playlist)) },
27+
onClick = onDismissRequest
28+
)
29+
DropdownMenuItem(
30+
text = { Text(text = stringResource(R.string.share)) },
31+
onClick = onDismissRequest
32+
)
33+
DropdownMenuItem(
34+
text = { Text(text = stringResource(R.string.open_in_browser)) },
35+
onClick = onDismissRequest
36+
)
37+
DropdownMenuItem(
38+
text = { Text(text = stringResource(R.string.mark_as_watched)) },
39+
onClick = onDismissRequest
40+
)
41+
DropdownMenuItem(
42+
text = { Text(text = stringResource(R.string.show_channel_details)) },
43+
onClick = onDismissRequest
44+
)
45+
}
46+
}

0 commit comments

Comments
 (0)