Skip to content

Commit 823d4a0

Browse files
Improve loading indicator positioning
1 parent 62d4044 commit 823d4a0

4 files changed

Lines changed: 202 additions & 124 deletions

File tree

app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package org.schabi.newpipe.fragments.list.comments
33
import android.os.Bundle
44
import android.view.LayoutInflater
55
import android.view.ViewGroup
6+
import androidx.compose.material3.MaterialTheme
7+
import androidx.compose.material3.Surface
68
import androidx.core.os.bundleOf
79
import androidx.fragment.app.Fragment
810
import androidx.fragment.compose.content
@@ -18,7 +20,9 @@ class CommentsFragment : Fragment() {
1820
savedInstanceState: Bundle?
1921
) = content {
2022
AppTheme {
21-
CommentSection()
23+
Surface(color = MaterialTheme.colorScheme.background) {
24+
CommentSection()
25+
}
2226
}
2327
}
2428

app/src/main/java/org/schabi/newpipe/ui/components/video/comment/Comment.kt

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,14 @@ import androidx.compose.foundation.layout.fillMaxWidth
1515
import androidx.compose.foundation.layout.padding
1616
import androidx.compose.foundation.layout.size
1717
import androidx.compose.foundation.shape.CircleShape
18-
import androidx.compose.material3.ExperimentalMaterial3Api
1918
import androidx.compose.material3.MaterialTheme
20-
import androidx.compose.material3.ModalBottomSheet
2119
import androidx.compose.material3.Surface
2220
import androidx.compose.material3.Text
2321
import androidx.compose.material3.TextButton
2422
import androidx.compose.runtime.Composable
2523
import androidx.compose.runtime.getValue
2624
import androidx.compose.runtime.mutableStateOf
2725
import androidx.compose.runtime.remember
28-
import androidx.compose.runtime.rememberCoroutineScope
2926
import androidx.compose.runtime.saveable.rememberSaveable
3027
import androidx.compose.runtime.setValue
3128
import androidx.compose.ui.Alignment
@@ -42,22 +39,18 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
4239
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
4340
import androidx.compose.ui.unit.dp
4441
import androidx.fragment.app.FragmentActivity
45-
import androidx.paging.Pager
46-
import androidx.paging.PagingConfig
47-
import androidx.paging.cachedIn
4842
import coil.compose.AsyncImage
4943
import org.schabi.newpipe.R
5044
import org.schabi.newpipe.extractor.Page
5145
import org.schabi.newpipe.extractor.comments.CommentsInfoItem
5246
import org.schabi.newpipe.extractor.stream.Description
53-
import org.schabi.newpipe.paging.CommentsSource
5447
import org.schabi.newpipe.ui.components.common.rememberParsedDescription
5548
import org.schabi.newpipe.ui.theme.AppTheme
5649
import org.schabi.newpipe.util.Localization
5750
import org.schabi.newpipe.util.NavigationHelper
5851
import org.schabi.newpipe.util.image.ImageStrategy
5952

60-
@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class)
53+
@OptIn(ExperimentalFoundationApi::class)
6154
@Composable
6255
fun Comment(comment: CommentsInfoItem) {
6356
val clipboardManager = LocalClipboardManager.current
@@ -157,23 +150,7 @@ fun Comment(comment: CommentsInfoItem) {
157150
}
158151

159152
if (showReplies) {
160-
ModalBottomSheet(onDismissRequest = { showReplies = false }) {
161-
val coroutineScope = rememberCoroutineScope()
162-
val flow = remember {
163-
Pager(PagingConfig(pageSize = 20, enablePlaceholders = false)) {
164-
CommentsSource(comment.serviceId, comment.url, comment.replies)
165-
}.flow
166-
.cachedIn(coroutineScope)
167-
}
168-
169-
Surface(color = MaterialTheme.colorScheme.background) {
170-
CommentSection(
171-
commentsFlow = flow,
172-
commentCount = comment.replyCount,
173-
parentComment = comment
174-
)
175-
}
176-
}
153+
CommentRepliesDialog(comment, onDismissRequest = { showReplies = false })
177154
}
178155
}
179156

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
package org.schabi.newpipe.ui.components.video.comment
2+
3+
import android.content.res.Configuration
4+
import androidx.compose.foundation.layout.padding
5+
import androidx.compose.foundation.lazy.LazyColumn
6+
import androidx.compose.foundation.lazy.rememberLazyListState
7+
import androidx.compose.material3.ExperimentalMaterial3Api
8+
import androidx.compose.material3.HorizontalDivider
9+
import androidx.compose.material3.MaterialTheme
10+
import androidx.compose.material3.ModalBottomSheet
11+
import androidx.compose.material3.Surface
12+
import androidx.compose.runtime.Composable
13+
import androidx.compose.runtime.remember
14+
import androidx.compose.runtime.rememberCoroutineScope
15+
import androidx.compose.ui.Modifier
16+
import androidx.compose.ui.graphics.Color
17+
import androidx.compose.ui.input.nestedscroll.nestedScroll
18+
import androidx.compose.ui.platform.rememberNestedScrollInteropConnection
19+
import androidx.compose.ui.tooling.preview.Preview
20+
import androidx.compose.ui.unit.dp
21+
import androidx.paging.LoadState
22+
import androidx.paging.Pager
23+
import androidx.paging.PagingConfig
24+
import androidx.paging.PagingData
25+
import androidx.paging.cachedIn
26+
import androidx.paging.compose.collectAsLazyPagingItems
27+
import kotlinx.coroutines.flow.Flow
28+
import kotlinx.coroutines.flow.flowOf
29+
import my.nanihadesuka.compose.LazyColumnScrollbar
30+
import my.nanihadesuka.compose.ScrollbarSettings
31+
import org.schabi.newpipe.R
32+
import org.schabi.newpipe.extractor.comments.CommentsInfoItem
33+
import org.schabi.newpipe.extractor.stream.Description
34+
import org.schabi.newpipe.paging.CommentsSource
35+
import org.schabi.newpipe.ui.components.common.LoadingIndicator
36+
import org.schabi.newpipe.ui.components.common.NoItemsMessage
37+
import org.schabi.newpipe.ui.theme.AppTheme
38+
import org.schabi.newpipe.ui.theme.md_theme_dark_primary
39+
40+
@Composable
41+
fun CommentRepliesDialog(
42+
parentComment: CommentsInfoItem,
43+
onDismissRequest: () -> Unit,
44+
) {
45+
val coroutineScope = rememberCoroutineScope()
46+
val commentsFlow = remember {
47+
Pager(PagingConfig(pageSize = 20, enablePlaceholders = false)) {
48+
CommentsSource(parentComment.serviceId, parentComment.url, parentComment.replies)
49+
}.flow
50+
.cachedIn(coroutineScope)
51+
}
52+
53+
CommentRepliesDialog(parentComment, commentsFlow, onDismissRequest)
54+
}
55+
56+
@OptIn(ExperimentalMaterial3Api::class)
57+
@Composable
58+
private fun CommentRepliesDialog(
59+
parentComment: CommentsInfoItem,
60+
commentsFlow: Flow<PagingData<CommentsInfoItem>>,
61+
onDismissRequest: () -> Unit,
62+
) {
63+
val comments = commentsFlow.collectAsLazyPagingItems()
64+
val nestedScrollInterop = rememberNestedScrollInteropConnection()
65+
val state = rememberLazyListState()
66+
67+
ModalBottomSheet(onDismissRequest = onDismissRequest) {
68+
Surface(color = MaterialTheme.colorScheme.background) {
69+
LazyColumnScrollbar(
70+
state = state,
71+
settings = ScrollbarSettings.Default.copy(
72+
thumbSelectedColor = md_theme_dark_primary,
73+
thumbUnselectedColor = Color.Red
74+
)
75+
) {
76+
LazyColumn(
77+
modifier = Modifier.nestedScroll(nestedScrollInterop),
78+
state = state
79+
) {
80+
item {
81+
CommentRepliesHeader(comment = parentComment)
82+
HorizontalDivider(thickness = 1.dp)
83+
}
84+
85+
if (comments.itemCount == 0) {
86+
item {
87+
val refresh = comments.loadState.refresh
88+
if (refresh is LoadState.Loading) {
89+
LoadingIndicator(modifier = Modifier.padding(top = 8.dp))
90+
} else {
91+
val message = if (refresh is LoadState.Error) {
92+
R.string.error_unable_to_load_comments
93+
} else {
94+
R.string.no_comments
95+
}
96+
NoItemsMessage(message)
97+
}
98+
}
99+
} else {
100+
items(comments.itemCount) {
101+
Comment(comment = comments[it]!!)
102+
}
103+
}
104+
}
105+
}
106+
}
107+
}
108+
}
109+
110+
@Preview(name = "Light mode", uiMode = Configuration.UI_MODE_NIGHT_NO)
111+
@Preview(name = "Dark mode", uiMode = Configuration.UI_MODE_NIGHT_YES)
112+
@Composable
113+
private fun CommentRepliesDialogPreview() {
114+
val comment = CommentsInfoItem(
115+
commentText = Description("Hello world!", Description.PLAIN_TEXT),
116+
uploaderName = "Test",
117+
likeCount = 100,
118+
isPinned = true,
119+
isHeartedByUploader = true
120+
)
121+
val replies = (1..10).map {
122+
CommentsInfoItem(
123+
commentText = Description("Reply $it", Description.PLAIN_TEXT),
124+
uploaderName = "Test"
125+
)
126+
}
127+
val flow = flowOf(PagingData.from(replies))
128+
129+
AppTheme {
130+
CommentRepliesDialog(comment, flow, onDismissRequest = {})
131+
}
132+
}

0 commit comments

Comments
 (0)