mirror of
https://github.com/TeamNewPipe/NewPipe
synced 2025-02-03 12:49:14 +00:00
Show dropdown menu on long click, make some adjustments
This commit is contained in:
parent
5e33b69316
commit
bbdff4b093
@ -1,8 +1,10 @@
|
|||||||
package org.schabi.newpipe.compose.stream
|
package org.schabi.newpipe.compose.stream
|
||||||
|
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
|
import androidx.compose.foundation.combinedClickable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
@ -20,39 +22,55 @@ import androidx.compose.ui.unit.dp
|
|||||||
import org.schabi.newpipe.compose.theme.AppTheme
|
import org.schabi.newpipe.compose.theme.AppTheme
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem
|
import org.schabi.newpipe.extractor.stream.StreamInfoItem
|
||||||
|
|
||||||
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun StreamCardItem(stream: StreamInfoItem, onClick: (StreamInfoItem) -> Unit) {
|
fun StreamCardItem(
|
||||||
Column(
|
stream: StreamInfoItem,
|
||||||
modifier = Modifier
|
isSelected: Boolean = false,
|
||||||
.clickable(onClick = { onClick(stream) })
|
onClick: (StreamInfoItem) -> Unit = {},
|
||||||
.padding(top = 12.dp, start = 2.dp, end = 2.dp)
|
onLongClick: (StreamInfoItem) -> Unit = {},
|
||||||
) {
|
onDismissPopup: () -> Unit = {}
|
||||||
StreamThumbnail(
|
) {
|
||||||
stream = stream,
|
Box {
|
||||||
modifier = Modifier.fillMaxWidth(),
|
Column(
|
||||||
contentScale = ContentScale.FillWidth
|
modifier = Modifier
|
||||||
)
|
.combinedClickable(
|
||||||
|
onLongClick = { onLongClick(stream) },
|
||||||
Column(modifier = Modifier.padding(10.dp)) {
|
onClick = { onClick(stream) }
|
||||||
Text(
|
)
|
||||||
text = stream.name,
|
.padding(top = 12.dp, start = 2.dp, end = 2.dp)
|
||||||
overflow = TextOverflow.Ellipsis,
|
) {
|
||||||
style = MaterialTheme.typography.titleSmall,
|
StreamThumbnail(
|
||||||
maxLines = 2
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
stream = stream,
|
||||||
|
contentScale = ContentScale.FillWidth
|
||||||
)
|
)
|
||||||
|
|
||||||
Row(
|
Column(modifier = Modifier.padding(10.dp)) {
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
horizontalArrangement = Arrangement.SpaceBetween
|
|
||||||
) {
|
|
||||||
Text(text = stream.uploaderName.orEmpty(), style = MaterialTheme.typography.bodySmall)
|
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = getStreamInfoDetail(stream),
|
text = stream.name,
|
||||||
style = MaterialTheme.typography.bodySmall
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
style = MaterialTheme.typography.titleSmall,
|
||||||
|
maxLines = 2
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween
|
||||||
|
) {
|
||||||
|
Text(text = stream.uploaderName.orEmpty(), style = MaterialTheme.typography.bodySmall)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = getStreamInfoDetail(stream),
|
||||||
|
style = MaterialTheme.typography.bodySmall
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isSelected) {
|
||||||
|
StreamMenu(onDismissPopup)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,7 +82,7 @@ private fun StreamCardItemPreview(
|
|||||||
) {
|
) {
|
||||||
AppTheme {
|
AppTheme {
|
||||||
Surface(color = MaterialTheme.colorScheme.background) {
|
Surface(color = MaterialTheme.colorScheme.background) {
|
||||||
StreamCardItem(stream) {}
|
StreamCardItem(stream)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package org.schabi.newpipe.compose.stream
|
package org.schabi.newpipe.compose.stream
|
||||||
|
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
|
import androidx.compose.foundation.combinedClickable
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
@ -17,28 +19,47 @@ import androidx.compose.ui.unit.dp
|
|||||||
import org.schabi.newpipe.compose.theme.AppTheme
|
import org.schabi.newpipe.compose.theme.AppTheme
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem
|
import org.schabi.newpipe.extractor.stream.StreamInfoItem
|
||||||
|
|
||||||
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun StreamGridItem(stream: StreamInfoItem, onClick: (StreamInfoItem) -> Unit) {
|
fun StreamGridItem(
|
||||||
Column(
|
stream: StreamInfoItem,
|
||||||
modifier = Modifier
|
isSelected: Boolean = false,
|
||||||
.clickable(onClick = { onClick(stream) })
|
onClick: (StreamInfoItem) -> Unit = {},
|
||||||
.padding(12.dp)
|
onLongClick: (StreamInfoItem) -> Unit = {},
|
||||||
) {
|
onDismissPopup: () -> Unit = {}
|
||||||
StreamThumbnail(stream = stream, modifier = Modifier.size(width = 246.dp, height = 138.dp))
|
) {
|
||||||
|
Box {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.combinedClickable(
|
||||||
|
onLongClick = { onLongClick(stream) },
|
||||||
|
onClick = { onClick(stream) }
|
||||||
|
)
|
||||||
|
.padding(12.dp)
|
||||||
|
) {
|
||||||
|
StreamThumbnail(
|
||||||
|
modifier = Modifier.size(width = 246.dp, height = 138.dp),
|
||||||
|
stream = stream
|
||||||
|
)
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = stream.name,
|
text = stream.name,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
style = MaterialTheme.typography.titleSmall,
|
style = MaterialTheme.typography.titleSmall,
|
||||||
maxLines = 2
|
maxLines = 2
|
||||||
)
|
)
|
||||||
|
|
||||||
Text(text = stream.uploaderName.orEmpty(), style = MaterialTheme.typography.bodySmall)
|
Text(text = stream.uploaderName.orEmpty(), style = MaterialTheme.typography.bodySmall)
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = getStreamInfoDetail(stream),
|
text = getStreamInfoDetail(stream),
|
||||||
style = MaterialTheme.typography.bodySmall
|
style = MaterialTheme.typography.bodySmall
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isSelected) {
|
||||||
|
StreamMenu(onDismissPopup)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,7 +71,7 @@ private fun StreamGridItemPreview(
|
|||||||
) {
|
) {
|
||||||
AppTheme {
|
AppTheme {
|
||||||
Surface(color = MaterialTheme.colorScheme.background) {
|
Surface(color = MaterialTheme.colorScheme.background) {
|
||||||
StreamGridItem(stream, onClick = {})
|
StreamGridItem(stream)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,10 @@ import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
|||||||
import androidx.compose.foundation.lazy.grid.rememberLazyGridState
|
import androidx.compose.foundation.lazy.grid.rememberLazyGridState
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
@ -36,7 +39,20 @@ fun StreamList(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: Handle long-click by showing a dropdown menu instead of a dialog.
|
|
||||||
|
// Handle long clicks
|
||||||
|
// TODO: Adjust the menu display depending on where it was triggered
|
||||||
|
var selectedStream by remember { mutableStateOf<StreamInfoItem?>(null) }
|
||||||
|
val onLongClick = remember {
|
||||||
|
{ stream: StreamInfoItem ->
|
||||||
|
selectedStream = stream
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val onDismissPopup = remember {
|
||||||
|
{
|
||||||
|
selectedStream = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (mode == ItemViewMode.GRID) {
|
if (mode == ItemViewMode.GRID) {
|
||||||
val gridState = rememberLazyGridState()
|
val gridState = rememberLazyGridState()
|
||||||
@ -46,7 +62,11 @@ fun StreamList(
|
|||||||
gridHeader()
|
gridHeader()
|
||||||
|
|
||||||
items(streams.itemCount) {
|
items(streams.itemCount) {
|
||||||
StreamGridItem(streams[it]!!, onClick)
|
val stream = streams[it]!!
|
||||||
|
StreamGridItem(
|
||||||
|
stream, selectedStream == stream, onClick, onLongClick,
|
||||||
|
onDismissPopup
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -60,10 +80,12 @@ fun StreamList(
|
|||||||
|
|
||||||
items(streams.itemCount) {
|
items(streams.itemCount) {
|
||||||
val stream = streams[it]!!
|
val stream = streams[it]!!
|
||||||
|
val isSelected = selectedStream == stream
|
||||||
|
|
||||||
if (mode == ItemViewMode.CARD) {
|
if (mode == ItemViewMode.CARD) {
|
||||||
StreamCardItem(stream, onClick)
|
StreamCardItem(stream, isSelected, onClick, onLongClick, onDismissPopup)
|
||||||
} else {
|
} else {
|
||||||
StreamListItem(stream, onClick)
|
StreamListItem(stream, isSelected, onClick, onLongClick, onDismissPopup)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
package org.schabi.newpipe.compose.stream
|
package org.schabi.newpipe.compose.stream
|
||||||
|
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
|
import androidx.compose.foundation.combinedClickable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
@ -21,32 +23,51 @@ import androidx.compose.ui.unit.dp
|
|||||||
import org.schabi.newpipe.compose.theme.AppTheme
|
import org.schabi.newpipe.compose.theme.AppTheme
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem
|
import org.schabi.newpipe.extractor.stream.StreamInfoItem
|
||||||
|
|
||||||
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun StreamListItem(stream: StreamInfoItem, onClick: (StreamInfoItem) -> Unit) {
|
fun StreamListItem(
|
||||||
Row(
|
stream: StreamInfoItem,
|
||||||
modifier = Modifier
|
isSelected: Boolean = false,
|
||||||
.clickable(onClick = { onClick(stream) })
|
onClick: (StreamInfoItem) -> Unit = {},
|
||||||
.fillMaxWidth()
|
onLongClick: (StreamInfoItem) -> Unit = {},
|
||||||
.padding(12.dp),
|
onDismissPopup: () -> Unit = {}
|
||||||
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
) {
|
||||||
verticalAlignment = Alignment.CenterVertically
|
Box {
|
||||||
) {
|
Row(
|
||||||
StreamThumbnail(stream = stream, modifier = Modifier.size(width = 98.dp, height = 55.dp))
|
modifier = Modifier
|
||||||
|
.combinedClickable(
|
||||||
Column {
|
onLongClick = { onLongClick(stream) },
|
||||||
Text(
|
onClick = { onClick(stream) }
|
||||||
text = stream.name,
|
)
|
||||||
overflow = TextOverflow.Ellipsis,
|
.fillMaxWidth()
|
||||||
style = MaterialTheme.typography.titleSmall,
|
.padding(12.dp),
|
||||||
maxLines = 1
|
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
StreamThumbnail(
|
||||||
|
modifier = Modifier.size(width = 98.dp, height = 55.dp),
|
||||||
|
stream = stream
|
||||||
)
|
)
|
||||||
|
|
||||||
Text(text = stream.uploaderName.orEmpty(), style = MaterialTheme.typography.bodySmall)
|
Column {
|
||||||
|
Text(
|
||||||
|
text = stream.name,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
style = MaterialTheme.typography.titleSmall,
|
||||||
|
maxLines = 1
|
||||||
|
)
|
||||||
|
|
||||||
Text(
|
Text(text = stream.uploaderName.orEmpty(), style = MaterialTheme.typography.bodySmall)
|
||||||
text = getStreamInfoDetail(stream),
|
|
||||||
style = MaterialTheme.typography.bodySmall
|
Text(
|
||||||
)
|
text = getStreamInfoDetail(stream),
|
||||||
|
style = MaterialTheme.typography.bodySmall
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isSelected) {
|
||||||
|
StreamMenu(onDismissPopup)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -59,7 +80,7 @@ private fun StreamListItemPreview(
|
|||||||
) {
|
) {
|
||||||
AppTheme {
|
AppTheme {
|
||||||
Surface(color = MaterialTheme.colorScheme.background) {
|
Surface(color = MaterialTheme.colorScheme.background) {
|
||||||
StreamListItem(stream, onClick = {})
|
StreamListItem(stream)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,46 @@
|
|||||||
|
package org.schabi.newpipe.compose.stream
|
||||||
|
|
||||||
|
import androidx.compose.material3.DropdownMenu
|
||||||
|
import androidx.compose.material3.DropdownMenuItem
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import org.schabi.newpipe.R
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun StreamMenu(onDismissRequest: () -> Unit) {
|
||||||
|
DropdownMenu(expanded = true, onDismissRequest = onDismissRequest) {
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = { Text(text = stringResource(R.string.start_here_on_background)) },
|
||||||
|
onClick = onDismissRequest
|
||||||
|
)
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = { Text(text = stringResource(R.string.start_here_on_popup)) },
|
||||||
|
onClick = onDismissRequest
|
||||||
|
)
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = { Text(text = stringResource(R.string.download)) },
|
||||||
|
onClick = onDismissRequest
|
||||||
|
)
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = { Text(text = stringResource(R.string.add_to_playlist)) },
|
||||||
|
onClick = onDismissRequest
|
||||||
|
)
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = { Text(text = stringResource(R.string.share)) },
|
||||||
|
onClick = onDismissRequest
|
||||||
|
)
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = { Text(text = stringResource(R.string.open_in_browser)) },
|
||||||
|
onClick = onDismissRequest
|
||||||
|
)
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = { Text(text = stringResource(R.string.mark_as_watched)) },
|
||||||
|
onClick = onDismissRequest
|
||||||
|
)
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = { Text(text = stringResource(R.string.show_channel_details)) },
|
||||||
|
onClick = onDismissRequest
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -20,9 +20,9 @@ import org.schabi.newpipe.util.image.ImageStrategy
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun StreamThumbnail(
|
fun StreamThumbnail(
|
||||||
stream: StreamInfoItem,
|
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
contentScale: ContentScale = ContentScale.Fit,
|
stream: StreamInfoItem,
|
||||||
|
contentScale: ContentScale = ContentScale.Fit
|
||||||
) {
|
) {
|
||||||
Box(modifier = modifier, contentAlignment = Alignment.BottomEnd) {
|
Box(modifier = modifier, contentAlignment = Alignment.BottomEnd) {
|
||||||
AsyncImage(
|
AsyncImage(
|
||||||
|
Loading…
Reference in New Issue
Block a user