mirror of
				https://github.com/TeamNewPipe/NewPipe
				synced 2025-10-31 07:13:00 +00:00 
			
		
		
		
	Use Fragment.content extension, improve comment composables
This commit is contained in:
		| @@ -216,7 +216,7 @@ dependencies { | ||||
|     implementation 'androidx.constraintlayout:constraintlayout:2.1.4' | ||||
|     implementation 'androidx.core:core-ktx:1.12.0' | ||||
|     implementation 'androidx.documentfile:documentfile:1.0.1' | ||||
|     implementation 'androidx.fragment:fragment-ktx:1.6.2' | ||||
|     implementation 'androidx.fragment:fragment-compose:1.8.2' | ||||
|     implementation "androidx.lifecycle:lifecycle-livedata-ktx:${androidxLifecycleVersion}" | ||||
|     implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:${androidxLifecycleVersion}" | ||||
|     implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.1.0' | ||||
|   | ||||
| @@ -3,28 +3,25 @@ package org.schabi.newpipe.fragments.list.comments | ||||
| import android.os.Bundle | ||||
| import android.view.LayoutInflater | ||||
| import android.view.ViewGroup | ||||
| import androidx.compose.ui.platform.ComposeView | ||||
| import androidx.compose.ui.platform.ViewCompositionStrategy | ||||
| import androidx.compose.material3.MaterialTheme | ||||
| import androidx.compose.material3.Surface | ||||
| import androidx.core.os.bundleOf | ||||
| import androidx.fragment.app.Fragment | ||||
| import androidx.lifecycle.viewmodel.compose.viewModel | ||||
| import androidx.fragment.compose.content | ||||
| import org.schabi.newpipe.ui.components.comment.CommentSection | ||||
| import org.schabi.newpipe.ui.theme.AppTheme | ||||
| import org.schabi.newpipe.util.KEY_SERVICE_ID | ||||
| import org.schabi.newpipe.util.KEY_URL | ||||
| import org.schabi.newpipe.viewmodels.CommentsViewModel | ||||
|  | ||||
| class CommentsFragment : Fragment() { | ||||
|     override fun onCreateView( | ||||
|         inflater: LayoutInflater, | ||||
|         container: ViewGroup?, | ||||
|         savedInstanceState: Bundle? | ||||
|     ) = ComposeView(requireContext()).apply { | ||||
|         setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) | ||||
|         setContent { | ||||
|             val viewModel = viewModel<CommentsViewModel>() | ||||
|             AppTheme { | ||||
|                 CommentSection(commentsFlow = viewModel.comments) | ||||
|     ) = content { | ||||
|         AppTheme { | ||||
|             Surface(color = MaterialTheme.colorScheme.background) { | ||||
|                 CommentSection() | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -2,14 +2,12 @@ package org.schabi.newpipe.fragments.list.videos | ||||
|  | ||||
| import android.os.Bundle | ||||
| import android.view.LayoutInflater | ||||
| import android.view.View | ||||
| import android.view.ViewGroup | ||||
| import androidx.compose.material3.MaterialTheme | ||||
| import androidx.compose.material3.Surface | ||||
| import androidx.compose.ui.platform.ComposeView | ||||
| import androidx.compose.ui.platform.ViewCompositionStrategy | ||||
| import androidx.core.os.bundleOf | ||||
| import androidx.fragment.app.Fragment | ||||
| import androidx.fragment.compose.content | ||||
| import org.schabi.newpipe.extractor.stream.StreamInfo | ||||
| import org.schabi.newpipe.ktx.serializable | ||||
| import org.schabi.newpipe.ui.components.video.RelatedItems | ||||
| @@ -21,15 +19,10 @@ class RelatedItemsFragment : Fragment() { | ||||
|         inflater: LayoutInflater, | ||||
|         container: ViewGroup?, | ||||
|         savedInstanceState: Bundle? | ||||
|     ): View { | ||||
|         return ComposeView(requireContext()).apply { | ||||
|             setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) | ||||
|             setContent { | ||||
|                 AppTheme { | ||||
|                     Surface(color = MaterialTheme.colorScheme.background) { | ||||
|                         RelatedItems(requireArguments().serializable<StreamInfo>(KEY_INFO)!!) | ||||
|                     } | ||||
|                 } | ||||
|     ) = content { | ||||
|         AppTheme { | ||||
|             Surface(color = MaterialTheme.colorScheme.background) { | ||||
|                 RelatedItems(requireArguments().serializable<StreamInfo>(KEY_INFO)!!) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -1,30 +1,24 @@ | ||||
| package org.schabi.newpipe.ui.components.comment | ||||
|  | ||||
| import android.content.res.Configuration | ||||
| import androidx.compose.foundation.layout.Column | ||||
| import androidx.compose.foundation.layout.fillMaxWidth | ||||
| import androidx.compose.foundation.layout.padding | ||||
| import androidx.compose.foundation.layout.wrapContentSize | ||||
| 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 | ||||
| import androidx.compose.runtime.Composable | ||||
| import androidx.compose.runtime.derivedStateOf | ||||
| import androidx.compose.runtime.getValue | ||||
| import androidx.compose.runtime.remember | ||||
| import androidx.compose.ui.Alignment | ||||
| import androidx.compose.ui.Modifier | ||||
| import androidx.compose.ui.input.nestedscroll.nestedScroll | ||||
| import androidx.compose.ui.platform.rememberNestedScrollInteropConnection | ||||
| import androidx.compose.ui.res.stringResource | ||||
| import androidx.compose.ui.tooling.preview.Preview | ||||
| import androidx.compose.ui.tooling.preview.PreviewParameter | ||||
| import androidx.compose.ui.tooling.preview.PreviewParameterProvider | ||||
| import androidx.compose.ui.unit.dp | ||||
| import androidx.compose.ui.unit.sp | ||||
| import androidx.lifecycle.viewmodel.compose.viewModel | ||||
| import androidx.paging.LoadState | ||||
| import androidx.paging.LoadStates | ||||
| import androidx.paging.PagingData | ||||
| @@ -37,66 +31,58 @@ import org.schabi.newpipe.extractor.comments.CommentsInfoItem | ||||
| import org.schabi.newpipe.extractor.stream.Description | ||||
| import org.schabi.newpipe.paging.CommentsDisabledException | ||||
| 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.viewmodels.CommentsViewModel | ||||
|  | ||||
| @Composable | ||||
| fun CommentSection(commentsViewModel: CommentsViewModel = viewModel()) { | ||||
|     CommentSection(commentsFlow = commentsViewModel.comments) | ||||
| } | ||||
|  | ||||
| @Composable | ||||
| fun CommentSection( | ||||
|     parentComment: CommentsInfoItem? = null, | ||||
|     commentsFlow: Flow<PagingData<CommentsInfoItem>> | ||||
| ) { | ||||
|     Surface(color = MaterialTheme.colorScheme.background) { | ||||
|         val comments = commentsFlow.collectAsLazyPagingItems() | ||||
|         val itemCount by remember { derivedStateOf { comments.itemCount } } | ||||
|         val nestedScrollInterop = rememberNestedScrollInteropConnection() | ||||
|         val state = rememberLazyListState() | ||||
|     val comments = commentsFlow.collectAsLazyPagingItems() | ||||
|     val itemCount by remember { derivedStateOf { comments.itemCount } } | ||||
|     val nestedScrollInterop = rememberNestedScrollInteropConnection() | ||||
|     val state = rememberLazyListState() | ||||
|  | ||||
|         LazyColumnScrollbar(state = state) { | ||||
|             LazyColumn(modifier = Modifier.nestedScroll(nestedScrollInterop), state = state) { | ||||
|                 if (parentComment != null) { | ||||
|                     item { | ||||
|                         CommentRepliesHeader(comment = parentComment) | ||||
|                         HorizontalDivider(thickness = 1.dp) | ||||
|     LazyColumnScrollbar(state = state) { | ||||
|         LazyColumn(modifier = Modifier.nestedScroll(nestedScrollInterop), state = state) { | ||||
|             if (parentComment != null) { | ||||
|                 item { | ||||
|                     CommentRepliesHeader(comment = parentComment) | ||||
|                     HorizontalDivider(thickness = 1.dp) | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             if (itemCount == 0) { | ||||
|                 item { | ||||
|                     val refresh = comments.loadState.refresh | ||||
|                     if (refresh is LoadState.Loading) { | ||||
|                         LoadingIndicator(modifier = Modifier.padding(top = 8.dp)) | ||||
|                     } else { | ||||
|                         val error = (refresh as? LoadState.Error)?.error | ||||
|                         val message = if (error is CommentsDisabledException) { | ||||
|                             R.string.comments_are_disabled | ||||
|                         } else { | ||||
|                             R.string.no_comments | ||||
|                         } | ||||
|                         NoItemsMessage(message) | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 if (itemCount == 0) { | ||||
|                     item { | ||||
|                         val refresh = comments.loadState.refresh | ||||
|                         if (refresh is LoadState.Loading) { | ||||
|                             LoadingIndicator(modifier = Modifier.padding(top = 8.dp)) | ||||
|                         } else { | ||||
|                             NoCommentsMessage((refresh as? LoadState.Error)?.error) | ||||
|                         } | ||||
|                     } | ||||
|                 } else { | ||||
|                     items(itemCount) { | ||||
|                         Comment(comment = comments[it]!!) | ||||
|                     } | ||||
|             } else { | ||||
|                 items(itemCount) { | ||||
|                     Comment(comment = comments[it]!!) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @Composable | ||||
| private fun NoCommentsMessage(error: Throwable?) { | ||||
|     val message = if (error is CommentsDisabledException) { | ||||
|         R.string.comments_are_disabled | ||||
|     } else { | ||||
|         R.string.no_comments | ||||
|     } | ||||
|  | ||||
|     Column( | ||||
|         modifier = Modifier | ||||
|             .fillMaxWidth() | ||||
|             .wrapContentSize(Alignment.Center), | ||||
|         horizontalAlignment = Alignment.CenterHorizontally | ||||
|     ) { | ||||
|         Text(text = "(╯°-°)╯", fontSize = 35.sp) | ||||
|         Text(text = stringResource(id = message), fontSize = 24.sp) | ||||
|     } | ||||
| } | ||||
|  | ||||
| private class CommentDataProvider : PreviewParameterProvider<PagingData<CommentsInfoItem>> { | ||||
|     private val notLoading = LoadState.NotLoading(true) | ||||
|  | ||||
| @@ -130,7 +116,9 @@ private fun CommentSectionPreview( | ||||
|     @PreviewParameter(CommentDataProvider::class) pagingData: PagingData<CommentsInfoItem> | ||||
| ) { | ||||
|     AppTheme { | ||||
|         CommentSection(commentsFlow = flowOf(pagingData)) | ||||
|         Surface(color = MaterialTheme.colorScheme.background) { | ||||
|             CommentSection(commentsFlow = flowOf(pagingData)) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -154,6 +142,8 @@ private fun CommentRepliesPreview() { | ||||
|     val flow = flowOf(PagingData.from(replies)) | ||||
|  | ||||
|     AppTheme { | ||||
|         CommentSection(parentComment = comment, commentsFlow = flow) | ||||
|         Surface(color = MaterialTheme.colorScheme.background) { | ||||
|             CommentSection(parentComment = comment, commentsFlow = flow) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Isira Seneviratne
					Isira Seneviratne