Coverage Summary for Class: LicensesScreenKt (com.georgeci.moneysurfer.feature.settings.about.licenses)

Class Method, % Branch, % Line, % Instruction, %
LicensesScreenKt 0% (0/17) 0% (0/70) 0% (0/116) 0% (0/1659)
LicensesScreenKt$LicensesList$1$1$3$1$1 0% (0/1) 0% (0/1) 0% (0/10)
LicensesScreenKt$LicensesList$lambda$0$0$$inlined$items$default$1 0% (0/1)
LicensesScreenKt$LicensesList$lambda$0$0$$inlined$items$default$2 0% (0/1)
LicensesScreenKt$LicensesList$lambda$0$0$$inlined$items$default$3 0% (0/1)
LicensesScreenKt$LicensesList$lambda$0$0$$inlined$items$default$4 0% (0/1)
Total 0% (0/22) 0% (0/70) 0% (0/117) 0% (0/1669)


 package com.georgeci.moneysurfer.feature.settings.about.licenses
 
 import androidx.compose.animation.AnimatedVisibility
 import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.PaddingValues
 import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.Spacer
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.lazy.LazyColumn
 import androidx.compose.foundation.lazy.items
 import androidx.compose.material3.CircularProgressIndicator
 import androidx.compose.material3.Scaffold
 import androidx.compose.material3.Text
 import androidx.compose.material3.TopAppBarDefaults
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.text.style.TextAlign
 import androidx.compose.ui.unit.dp
 import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.georgeci.moneysurfer.uikit.atom.SurferCard
 import com.georgeci.moneysurfer.uikit.components.base.SurferPaneTopBar
 import com.georgeci.moneysurfer.uikit.modifier.surferContentContainer
 import com.georgeci.moneysurfer.uikit.modifier.surferSafeInsets
 import com.georgeci.moneysurfer.uikit.theme.AppTheme
 import com.georgeci.moneysurfer.utils.HandleSideEffect
 import moneysurfer.feature.settings.generated.resources.Res
 import moneysurfer.feature.settings.generated.resources.settings_licenses_error
 import moneysurfer.feature.settings.generated.resources.settings_licenses_summary_format
 import moneysurfer.feature.settings.generated.resources.settings_licenses_title
 import org.jetbrains.compose.resources.stringResource
 import org.koin.compose.viewmodel.koinViewModel
 
 @Composable
 fun LicensesScreen(
     onNavigateBack: () -> Unit,
     viewModel: LicensesViewModel = koinViewModel(),
 ) {
     val state by viewModel.collectAsStateWithLifecycle()
 
     viewModel.HandleSideEffect { effect ->
         when (effect) {
             LicensesEffect.NavigateBack -> onNavigateBack()
         }
     }
 
     LicensesContent(state = state, onEvent = viewModel::onEvent)
 }
 
 @Composable
 private fun LicensesContent(
     state: LicensesState,
     onEvent: (LicensesEvent) -> Unit,
 ) {
     Scaffold(
         modifier = Modifier.surferSafeInsets(),
         containerColor = AppTheme.materialColors.surface,
         topBar = {
             SurferPaneTopBar(
                 title = stringResource(Res.string.settings_licenses_title),
                 onBack = { onEvent(LicensesEvent.OnBackClick) },
                 colors = TopAppBarDefaults.topAppBarColors(
                     containerColor = AppTheme.materialColors.surface,
                     titleContentColor = AppTheme.materialColors.onSurface,
                 ),
             )
         },
     ) { padding ->
         when {
             state.isLoading -> LicensesLoading(padding)
             state.isError -> LicensesError(padding)
             else -> LicensesList(state = state, padding = padding, onEvent = onEvent)
         }
     }
 }
 
 @Composable
 private fun LicensesLoading(padding: PaddingValues) {
     Box(
         modifier = Modifier.fillMaxSize().padding(padding),
         contentAlignment = Alignment.Center,
     ) {
         CircularProgressIndicator(color = AppTheme.materialColors.primary)
     }
 }
 
 @Composable
 private fun LicensesError(padding: PaddingValues) {
     Box(
         modifier = Modifier.fillMaxSize().surferContentContainer().padding(padding),
         contentAlignment = Alignment.Center,
     ) {
         Text(
             text = stringResource(Res.string.settings_licenses_error),
             style = AppTheme.typography.bodyMedium,
             color = AppTheme.materialColors.onSurfaceVariant,
             textAlign = TextAlign.Center,
             modifier = Modifier.padding(horizontal = 32.dp),
         )
     }
 }
 
 @Composable
 private fun LicensesList(
     state: LicensesState,
     padding: PaddingValues,
     onEvent: (LicensesEvent) -> Unit,
 ) {
     LazyColumn(
         modifier = Modifier.fillMaxSize().surferContentContainer().padding(top = padding.calculateTopPadding()),
         contentPadding = PaddingValues(
             start = 16.dp,
             end = 16.dp,
             top = 4.dp,
             bottom = padding.calculateBottomPadding() + 28.dp,
         ),
         verticalArrangement = Arrangement.spacedBy(8.dp),
     ) {
         item(key = "summary") {
             Text(
                 text = stringResource(
                     Res.string.settings_licenses_summary_format,
                     state.libraries.sumOf { it.artifacts.size },
                 ),
                 style = AppTheme.typography.bodySmall,
                 color = AppTheme.materialColors.onSurfaceVariant,
                 modifier = Modifier.padding(horizontal = 4.dp, vertical = 6.dp),
             )
         }
         items(items = state.libraries, key = { it.id }) { library ->
             LibraryRow(
                 library = library,
                 expanded = state.expandedLibraryId == library.id,
                 onClick = { onEvent(LicensesEvent.OnLibraryClick(library.id)) },
             )
         }
     }
 }
 
 @Composable
 private fun LibraryRow(
     library: OssLibrary,
     expanded: Boolean,
     onClick: () -> Unit,
 ) {
     val colors = AppTheme.materialColors
     SurferCard(
         modifier = Modifier.fillMaxWidth(),
         onClick = onClick,
     ) {
         Column(modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp, vertical = 12.dp)) {
             Row(
                 verticalAlignment = Alignment.CenterVertically,
                 horizontalArrangement = Arrangement.spacedBy(8.dp),
             ) {
                 Text(
                     text = library.name,
                     style = AppTheme.typography.titleSmall,
                     color = colors.onSurface,
                     modifier = Modifier.weight(1f),
                 )
                 library.version?.let { version ->
                     Text(
                         text = version,
                         style = AppTheme.typography.labelMedium,
                         color = colors.onSurfaceVariant,
                     )
                 }
             }
             val subtitle = listOfNotNull(
                 library.author,
                 library.licenses.joinToString { it.name }.ifEmpty { null },
             ).joinToString(" ยท ")
             if (subtitle.isNotEmpty()) {
                 Text(
                     text = subtitle,
                     style = AppTheme.typography.bodySmall,
                     color = colors.onSurfaceVariant,
                 )
             }
             AnimatedVisibility(visible = expanded) {
                 Column {
                     Spacer(Modifier.height(10.dp))
                     Text(
                         text = library.artifacts.joinToString(separator = "\n"),
                         style = AppTheme.typography.bodySmall,
                         color = colors.onSurfaceVariant,
                     )
                     library.licenses.forEach { license ->
                         license.content?.let { content ->
                             Spacer(Modifier.height(10.dp))
                             Text(
                                 text = content,
                                 style = AppTheme.typography.bodySmall,
                                 color = colors.onSurfaceVariant,
                             )
                         }
                     }
                 }
             }
         }
     }
 }