@@ -7,20 +7,19 @@ import androidx.compose.foundation.lazy.rememberLazyListState
77import androidx.compose.material3.HorizontalDivider
88import androidx.compose.material3.MaterialTheme
99import androidx.compose.material3.Surface
10+ import androidx.compose.material3.Text
1011import androidx.compose.runtime.Composable
11- import androidx.compose.runtime.derivedStateOf
1212import androidx.compose.runtime.getValue
13- import androidx.compose.runtime.remember
1413import androidx.compose.ui.Modifier
1514import androidx.compose.ui.input.nestedscroll.nestedScroll
1615import androidx.compose.ui.platform.rememberNestedScrollInteropConnection
16+ import androidx.compose.ui.res.pluralStringResource
17+ import androidx.compose.ui.text.font.FontWeight
1718import androidx.compose.ui.tooling.preview.Preview
18- import androidx.compose.ui.tooling.preview.PreviewParameter
19- import androidx.compose.ui.tooling.preview.PreviewParameterProvider
2019import androidx.compose.ui.unit.dp
20+ import androidx.lifecycle.compose.collectAsStateWithLifecycle
2121import androidx.lifecycle.viewmodel.compose.viewModel
2222import androidx.paging.LoadState
23- import androidx.paging.LoadStates
2423import androidx.paging.PagingData
2524import androidx.paging.compose.collectAsLazyPagingItems
2625import kotlinx.coroutines.flow.Flow
@@ -30,106 +29,157 @@ import org.schabi.newpipe.R
3029import org.schabi.newpipe.extractor.Page
3130import org.schabi.newpipe.extractor.comments.CommentsInfoItem
3231import org.schabi.newpipe.extractor.stream.Description
33- import org.schabi.newpipe.paging.CommentsDisabledException
3432import org.schabi.newpipe.ui.components.common.LoadingIndicator
3533import org.schabi.newpipe.ui.components.common.NoItemsMessage
3634import org.schabi.newpipe.ui.theme.AppTheme
3735import org.schabi.newpipe.viewmodels.CommentsViewModel
36+ import org.schabi.newpipe.viewmodels.util.Resource
3837
3938@Composable
4039fun CommentSection (commentsViewModel : CommentsViewModel = viewModel()) {
41- CommentSection (commentsFlow = commentsViewModel.comments)
40+ Surface (color = MaterialTheme .colorScheme.background) {
41+ val state by commentsViewModel.uiState.collectAsStateWithLifecycle()
42+ CommentSection (state, commentsViewModel.comments)
43+ }
44+ }
45+
46+ @Composable
47+ private fun CommentSection (
48+ uiState : Resource <CommentInfo >,
49+ commentsFlow : Flow <PagingData <CommentsInfoItem >>
50+ ) {
51+ when (uiState) {
52+ is Resource .Loading -> LoadingIndicator (modifier = Modifier .padding(top = 8 .dp))
53+
54+ is Resource .Success -> {
55+ val commentsInfo = uiState.data
56+ CommentSection (
57+ commentsFlow = commentsFlow,
58+ commentCount = commentsInfo.commentCount,
59+ isCommentsDisabled = commentsInfo.isCommentsDisabled
60+ )
61+ }
62+
63+ is Resource .Error -> {
64+ // This is not rendered as VideoDetailFragment handles errors
65+ }
66+ }
4267}
4368
4469@Composable
4570fun CommentSection (
71+ commentsFlow : Flow <PagingData <CommentsInfoItem >>,
72+ commentCount : Int ,
4673 parentComment : CommentsInfoItem ? = null,
47- commentsFlow : Flow < PagingData < CommentsInfoItem >>
74+ isCommentsDisabled : Boolean = false,
4875) {
4976 val comments = commentsFlow.collectAsLazyPagingItems()
50- val itemCount by remember { derivedStateOf { comments.itemCount } }
5177 val nestedScrollInterop = rememberNestedScrollInteropConnection()
5278 val state = rememberLazyListState()
5379
54- Surface (color = MaterialTheme .colorScheme.background) {
55- LazyColumnScrollbar (state = state) {
56- LazyColumn (modifier = Modifier .nestedScroll(nestedScrollInterop), state = state) {
57- if (parentComment != null ) {
58- item {
59- CommentRepliesHeader (comment = parentComment)
60- HorizontalDivider (thickness = 1 .dp)
61- }
80+ LazyColumnScrollbar (state = state) {
81+ LazyColumn (
82+ modifier = Modifier .nestedScroll(nestedScrollInterop),
83+ state = state
84+ ) {
85+ if (parentComment != null ) {
86+ item {
87+ CommentRepliesHeader (comment = parentComment)
88+ HorizontalDivider (thickness = 1 .dp)
6289 }
90+ }
6391
64- if (itemCount == 0 ) {
65- item {
66- val refresh = comments.loadState.refresh
67- if (refresh is LoadState .Loading ) {
68- LoadingIndicator (modifier = Modifier .padding(top = 8 .dp))
92+ if (comments.itemCount == 0 ) {
93+ item {
94+ val refresh = comments.loadState.refresh
95+ if (refresh is LoadState .Loading ) {
96+ LoadingIndicator (modifier = Modifier .padding(top = 8 .dp))
97+ } else {
98+ val message = if (refresh is LoadState .Error ) {
99+ R .string.error_unable_to_load_comments
100+ } else if (isCommentsDisabled) {
101+ R .string.comments_are_disabled
69102 } else {
70- val error = (refresh as ? LoadState .Error )?.error
71- val message = if (error is CommentsDisabledException ) {
72- R .string.comments_are_disabled
73- } else {
74- R .string.no_comments
75- }
76- NoItemsMessage (message)
103+ R .string.no_comments
77104 }
105+ NoItemsMessage (message)
78106 }
79- } else {
80- items(itemCount) {
81- Comment (comment = comments[it]!! )
107+ }
108+ } else {
109+ // The number of replies is already shown in the main comment section
110+ if (parentComment == null ) {
111+ item {
112+ Text (
113+ modifier = Modifier .padding(start = 8 .dp),
114+ text = pluralStringResource(R .plurals.comments, commentCount, commentCount),
115+ fontWeight = FontWeight .Bold
116+ )
82117 }
83118 }
119+
120+ items(comments.itemCount) {
121+ Comment (comment = comments[it]!! )
122+ }
84123 }
85124 }
86125 }
87126}
88127
89- private class CommentDataProvider : PreviewParameterProvider <PagingData <CommentsInfoItem >> {
90- private val notLoading = LoadState .NotLoading (true )
128+ @Preview(name = " Light mode" , uiMode = Configuration .UI_MODE_NIGHT_NO )
129+ @Preview(name = " Dark mode" , uiMode = Configuration .UI_MODE_NIGHT_YES )
130+ @Composable
131+ private fun CommentSectionLoadingPreview () {
132+ AppTheme {
133+ Surface (color = MaterialTheme .colorScheme.background) {
134+ CommentSection (uiState = Resource .Loading , commentsFlow = flowOf())
135+ }
136+ }
137+ }
91138
92- override val values = sequenceOf(
93- // Normal view
94- PagingData .from(
95- listOf (
96- CommentsInfoItem (
97- commentText = Description (
98- " Comment 1\n\n This line should be hidden by default." ,
99- Description .PLAIN_TEXT
100- ),
101- uploaderName = " Test" ,
102- replies = Page (" " ),
103- replyCount = 10
104- )
105- ) + (2 .. 10 ).map {
106- CommentsInfoItem (
107- commentText = Description (" Comment $it " , Description .PLAIN_TEXT ),
108- uploaderName = " Test"
109- )
110- }
111- ),
112- // Comments disabled
113- PagingData .from(
114- listOf<CommentsInfoItem >(),
115- LoadStates (LoadState .Error (CommentsDisabledException ()), notLoading, notLoading)
116- ),
117- // No comments
118- PagingData .from(
119- listOf<CommentsInfoItem >(),
120- LoadStates (notLoading, notLoading, notLoading)
139+ @Preview(name = " Light mode" , uiMode = Configuration .UI_MODE_NIGHT_NO )
140+ @Preview(name = " Dark mode" , uiMode = Configuration .UI_MODE_NIGHT_YES )
141+ @Composable
142+ private fun CommentSectionSuccessPreview () {
143+ val comments = listOf (
144+ CommentsInfoItem (
145+ commentText = Description (
146+ " Comment 1\n\n This line should be hidden by default." ,
147+ Description .PLAIN_TEXT
148+ ),
149+ uploaderName = " Test" ,
150+ replies = Page (" " ),
151+ replyCount = 10
121152 )
122- )
153+ ) + (2 .. 10 ).map {
154+ CommentsInfoItem (
155+ commentText = Description (" Comment $it " , Description .PLAIN_TEXT ),
156+ uploaderName = " Test"
157+ )
158+ }
159+
160+ AppTheme {
161+ Surface (color = MaterialTheme .colorScheme.background) {
162+ CommentSection (
163+ uiState = Resource .Success (
164+ CommentInfo (
165+ serviceId = 1 , url = " " , comments = comments, nextPage = null ,
166+ commentCount = 10 , isCommentsDisabled = false
167+ )
168+ ),
169+ commentsFlow = flowOf(PagingData .from(comments))
170+ )
171+ }
172+ }
123173}
124174
125175@Preview(name = " Light mode" , uiMode = Configuration .UI_MODE_NIGHT_NO )
126176@Preview(name = " Dark mode" , uiMode = Configuration .UI_MODE_NIGHT_YES )
127177@Composable
128- private fun CommentSectionPreview (
129- @PreviewParameter(CommentDataProvider ::class ) pagingData : PagingData <CommentsInfoItem >
130- ) {
178+ private fun CommentSectionErrorPreview () {
131179 AppTheme {
132- CommentSection (commentsFlow = flowOf(pagingData))
180+ Surface (color = MaterialTheme .colorScheme.background) {
181+ CommentSection (uiState = Resource .Error (RuntimeException ()), commentsFlow = flowOf())
182+ }
133183 }
134184}
135185
@@ -153,6 +203,8 @@ private fun CommentRepliesPreview() {
153203 val flow = flowOf(PagingData .from(replies))
154204
155205 AppTheme {
156- CommentSection (parentComment = comment, commentsFlow = flow)
206+ Surface (color = MaterialTheme .colorScheme.background) {
207+ CommentSection (parentComment = comment, commentsFlow = flow, commentCount = 10 )
208+ }
157209 }
158210}
0 commit comments