mirror of
https://github.com/TeamNewPipe/NewPipe
synced 2024-11-25 19:49:32 +01:00
Improve loading indicator positioning
This commit is contained in:
parent
62d4044d6c
commit
823d4a041f
@ -3,6 +3,8 @@ package org.schabi.newpipe.fragments.list.comments
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.compose.content
|
||||
@ -18,7 +20,9 @@ class CommentsFragment : Fragment() {
|
||||
savedInstanceState: Bundle?
|
||||
) = content {
|
||||
AppTheme {
|
||||
CommentSection()
|
||||
Surface(color = MaterialTheme.colorScheme.background) {
|
||||
CommentSection()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,9 +15,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.ModalBottomSheet
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
@ -25,7 +23,6 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
@ -42,22 +39,18 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.paging.Pager
|
||||
import androidx.paging.PagingConfig
|
||||
import androidx.paging.cachedIn
|
||||
import coil.compose.AsyncImage
|
||||
import org.schabi.newpipe.R
|
||||
import org.schabi.newpipe.extractor.Page
|
||||
import org.schabi.newpipe.extractor.comments.CommentsInfoItem
|
||||
import org.schabi.newpipe.extractor.stream.Description
|
||||
import org.schabi.newpipe.paging.CommentsSource
|
||||
import org.schabi.newpipe.ui.components.common.rememberParsedDescription
|
||||
import org.schabi.newpipe.ui.theme.AppTheme
|
||||
import org.schabi.newpipe.util.Localization
|
||||
import org.schabi.newpipe.util.NavigationHelper
|
||||
import org.schabi.newpipe.util.image.ImageStrategy
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class)
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun Comment(comment: CommentsInfoItem) {
|
||||
val clipboardManager = LocalClipboardManager.current
|
||||
@ -157,23 +150,7 @@ fun Comment(comment: CommentsInfoItem) {
|
||||
}
|
||||
|
||||
if (showReplies) {
|
||||
ModalBottomSheet(onDismissRequest = { showReplies = false }) {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val flow = remember {
|
||||
Pager(PagingConfig(pageSize = 20, enablePlaceholders = false)) {
|
||||
CommentsSource(comment.serviceId, comment.url, comment.replies)
|
||||
}.flow
|
||||
.cachedIn(coroutineScope)
|
||||
}
|
||||
|
||||
Surface(color = MaterialTheme.colorScheme.background) {
|
||||
CommentSection(
|
||||
commentsFlow = flow,
|
||||
commentCount = comment.replyCount,
|
||||
parentComment = comment
|
||||
)
|
||||
}
|
||||
}
|
||||
CommentRepliesDialog(comment, onDismissRequest = { showReplies = false })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,132 @@
|
||||
package org.schabi.newpipe.ui.components.video.comment
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.ModalBottomSheet
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.rememberNestedScrollInteropConnection
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.paging.LoadState
|
||||
import androidx.paging.Pager
|
||||
import androidx.paging.PagingConfig
|
||||
import androidx.paging.PagingData
|
||||
import androidx.paging.cachedIn
|
||||
import androidx.paging.compose.collectAsLazyPagingItems
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import my.nanihadesuka.compose.LazyColumnScrollbar
|
||||
import my.nanihadesuka.compose.ScrollbarSettings
|
||||
import org.schabi.newpipe.R
|
||||
import org.schabi.newpipe.extractor.comments.CommentsInfoItem
|
||||
import org.schabi.newpipe.extractor.stream.Description
|
||||
import org.schabi.newpipe.paging.CommentsSource
|
||||
import org.schabi.newpipe.ui.components.common.LoadingIndicator
|
||||
import org.schabi.newpipe.ui.components.common.NoItemsMessage
|
||||
import org.schabi.newpipe.ui.theme.AppTheme
|
||||
import org.schabi.newpipe.ui.theme.md_theme_dark_primary
|
||||
|
||||
@Composable
|
||||
fun CommentRepliesDialog(
|
||||
parentComment: CommentsInfoItem,
|
||||
onDismissRequest: () -> Unit,
|
||||
) {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val commentsFlow = remember {
|
||||
Pager(PagingConfig(pageSize = 20, enablePlaceholders = false)) {
|
||||
CommentsSource(parentComment.serviceId, parentComment.url, parentComment.replies)
|
||||
}.flow
|
||||
.cachedIn(coroutineScope)
|
||||
}
|
||||
|
||||
CommentRepliesDialog(parentComment, commentsFlow, onDismissRequest)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun CommentRepliesDialog(
|
||||
parentComment: CommentsInfoItem,
|
||||
commentsFlow: Flow<PagingData<CommentsInfoItem>>,
|
||||
onDismissRequest: () -> Unit,
|
||||
) {
|
||||
val comments = commentsFlow.collectAsLazyPagingItems()
|
||||
val nestedScrollInterop = rememberNestedScrollInteropConnection()
|
||||
val state = rememberLazyListState()
|
||||
|
||||
ModalBottomSheet(onDismissRequest = onDismissRequest) {
|
||||
Surface(color = MaterialTheme.colorScheme.background) {
|
||||
LazyColumnScrollbar(
|
||||
state = state,
|
||||
settings = ScrollbarSettings.Default.copy(
|
||||
thumbSelectedColor = md_theme_dark_primary,
|
||||
thumbUnselectedColor = Color.Red
|
||||
)
|
||||
) {
|
||||
LazyColumn(
|
||||
modifier = Modifier.nestedScroll(nestedScrollInterop),
|
||||
state = state
|
||||
) {
|
||||
item {
|
||||
CommentRepliesHeader(comment = parentComment)
|
||||
HorizontalDivider(thickness = 1.dp)
|
||||
}
|
||||
|
||||
if (comments.itemCount == 0) {
|
||||
item {
|
||||
val refresh = comments.loadState.refresh
|
||||
if (refresh is LoadState.Loading) {
|
||||
LoadingIndicator(modifier = Modifier.padding(top = 8.dp))
|
||||
} else {
|
||||
val message = if (refresh is LoadState.Error) {
|
||||
R.string.error_unable_to_load_comments
|
||||
} else {
|
||||
R.string.no_comments
|
||||
}
|
||||
NoItemsMessage(message)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
items(comments.itemCount) {
|
||||
Comment(comment = comments[it]!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(name = "Light mode", uiMode = Configuration.UI_MODE_NIGHT_NO)
|
||||
@Preview(name = "Dark mode", uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun CommentRepliesDialogPreview() {
|
||||
val comment = CommentsInfoItem(
|
||||
commentText = Description("Hello world!", Description.PLAIN_TEXT),
|
||||
uploaderName = "Test",
|
||||
likeCount = 100,
|
||||
isPinned = true,
|
||||
isHeartedByUploader = true
|
||||
)
|
||||
val replies = (1..10).map {
|
||||
CommentsInfoItem(
|
||||
commentText = Description("Reply $it", Description.PLAIN_TEXT),
|
||||
uploaderName = "Test"
|
||||
)
|
||||
}
|
||||
val flow = flowOf(PagingData.from(replies))
|
||||
|
||||
AppTheme {
|
||||
CommentRepliesDialog(comment, flow, onDismissRequest = {})
|
||||
}
|
||||
}
|
@ -4,7 +4,6 @@ import android.content.res.Configuration
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
@ -40,94 +39,86 @@ import org.schabi.newpipe.viewmodels.util.Resource
|
||||
|
||||
@Composable
|
||||
fun CommentSection(commentsViewModel: CommentsViewModel = viewModel()) {
|
||||
Surface(color = MaterialTheme.colorScheme.background) {
|
||||
val state by commentsViewModel.uiState.collectAsStateWithLifecycle()
|
||||
CommentSection(state, commentsViewModel.comments)
|
||||
}
|
||||
val state by commentsViewModel.uiState.collectAsStateWithLifecycle()
|
||||
CommentSection(state, commentsViewModel.comments)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CommentSection(
|
||||
uiState: Resource<CommentInfo>,
|
||||
commentsFlow: Flow<PagingData<CommentsInfoItem>>
|
||||
) {
|
||||
when (uiState) {
|
||||
is Resource.Loading -> LoadingIndicator(modifier = Modifier.padding(top = 8.dp))
|
||||
|
||||
is Resource.Success -> {
|
||||
val commentsInfo = uiState.data
|
||||
CommentSection(
|
||||
commentsFlow = commentsFlow,
|
||||
commentCount = commentsInfo.commentCount,
|
||||
isCommentsDisabled = commentsInfo.isCommentsDisabled
|
||||
)
|
||||
}
|
||||
|
||||
is Resource.Error -> {
|
||||
// This is not rendered as VideoDetailFragment handles errors
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CommentSection(
|
||||
commentsFlow: Flow<PagingData<CommentsInfoItem>>,
|
||||
commentCount: Int,
|
||||
parentComment: CommentsInfoItem? = null,
|
||||
isCommentsDisabled: Boolean = false,
|
||||
) {
|
||||
val comments = commentsFlow.collectAsLazyPagingItems()
|
||||
val nestedScrollInterop = rememberNestedScrollInteropConnection()
|
||||
val state = rememberLazyListState()
|
||||
|
||||
LazyColumnScrollbar(
|
||||
state = state,
|
||||
settings = ScrollbarSettings.Default.copy(
|
||||
thumbSelectedColor = md_theme_dark_primary,
|
||||
thumbUnselectedColor = Color.Red
|
||||
)
|
||||
) {
|
||||
LazyColumn(
|
||||
modifier = Modifier.nestedScroll(nestedScrollInterop),
|
||||
state = state
|
||||
Surface(color = MaterialTheme.colorScheme.background) {
|
||||
LazyColumnScrollbar(
|
||||
state = state,
|
||||
settings = ScrollbarSettings.Default.copy(
|
||||
thumbSelectedColor = md_theme_dark_primary,
|
||||
thumbUnselectedColor = Color.Red
|
||||
)
|
||||
) {
|
||||
if (parentComment != null) {
|
||||
item {
|
||||
CommentRepliesHeader(comment = parentComment)
|
||||
HorizontalDivider(thickness = 1.dp)
|
||||
}
|
||||
}
|
||||
|
||||
if (comments.itemCount == 0) {
|
||||
item {
|
||||
val refresh = comments.loadState.refresh
|
||||
if (refresh is LoadState.Loading) {
|
||||
LoadingIndicator(modifier = Modifier.padding(top = 8.dp))
|
||||
} else {
|
||||
val message = if (refresh is LoadState.Error) {
|
||||
R.string.error_unable_to_load_comments
|
||||
} else if (isCommentsDisabled) {
|
||||
R.string.comments_are_disabled
|
||||
} else {
|
||||
R.string.no_comments
|
||||
LazyColumn(
|
||||
modifier = Modifier.nestedScroll(nestedScrollInterop),
|
||||
state = state
|
||||
) {
|
||||
when (uiState) {
|
||||
is Resource.Loading -> {
|
||||
item {
|
||||
LoadingIndicator(modifier = Modifier.padding(top = 8.dp))
|
||||
}
|
||||
NoItemsMessage(message)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// The number of replies is already shown in the main comment section
|
||||
if (parentComment == null) {
|
||||
item {
|
||||
Text(
|
||||
modifier = Modifier.padding(start = 8.dp),
|
||||
text = pluralStringResource(R.plurals.comments, commentCount, commentCount),
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
items(comments.itemCount) {
|
||||
Comment(comment = comments[it]!!)
|
||||
is Resource.Success -> {
|
||||
val commentInfo = uiState.data
|
||||
val count = commentInfo.commentCount
|
||||
|
||||
if (commentInfo.isCommentsDisabled) {
|
||||
item {
|
||||
NoItemsMessage(R.string.comments_are_disabled)
|
||||
}
|
||||
} else if (count == 0) {
|
||||
item {
|
||||
NoItemsMessage(R.string.no_comments)
|
||||
}
|
||||
} else {
|
||||
item {
|
||||
Text(
|
||||
modifier = Modifier.padding(start = 8.dp),
|
||||
text = pluralStringResource(R.plurals.comments, count, count),
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
}
|
||||
|
||||
when (comments.loadState.refresh) {
|
||||
is LoadState.Loading -> {
|
||||
item {
|
||||
LoadingIndicator(modifier = Modifier.padding(top = 8.dp))
|
||||
}
|
||||
}
|
||||
|
||||
is LoadState.Error -> {
|
||||
item {
|
||||
NoItemsMessage(R.string.error_unable_to_load_comments)
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
items(comments.itemCount) {
|
||||
Comment(comment = comments[it]!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is Resource.Error -> {
|
||||
item {
|
||||
NoItemsMessage(R.string.error_unable_to_load_comments)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -191,29 +182,3 @@ private fun CommentSectionErrorPreview() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(name = "Light mode", uiMode = Configuration.UI_MODE_NIGHT_NO)
|
||||
@Preview(name = "Dark mode", uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun CommentRepliesPreview() {
|
||||
val comment = CommentsInfoItem(
|
||||
commentText = Description("Hello world!", Description.PLAIN_TEXT),
|
||||
uploaderName = "Test",
|
||||
likeCount = 100,
|
||||
isPinned = true,
|
||||
isHeartedByUploader = true
|
||||
)
|
||||
val replies = (1..10).map {
|
||||
CommentsInfoItem(
|
||||
commentText = Description("Reply $it", Description.PLAIN_TEXT),
|
||||
uploaderName = "Test"
|
||||
)
|
||||
}
|
||||
val flow = flowOf(PagingData.from(replies))
|
||||
|
||||
AppTheme {
|
||||
Surface(color = MaterialTheme.colorScheme.background) {
|
||||
CommentSection(parentComment = comment, commentsFlow = flow, commentCount = 10)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user