Coverage Summary for Class: WorkspaceManageScreenKt (com.georgeci.moneysurfer.feature.workspace.members)

Class Method, % Branch, % Line, % Instruction, %
WorkspaceManageScreenKt 0% (0/10) 0% (0/67) 0% (0/73) 0% (0/1023)
WorkspaceManageScreenKt$WhenMappings
Total 0% (0/10) 0% (0/67) 0% (0/73) 0% (0/1023)


 package com.georgeci.moneysurfer.feature.workspace.members
 
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.Spacer
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.rememberScrollState
 import androidx.compose.foundation.verticalScroll
 import androidx.compose.material3.Icon
 import androidx.compose.material3.IconButton
 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.Modifier
 import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.tooling.preview.Preview
 import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.georgeci.moneysurfer.domain.model.WorkspaceRole
 import com.georgeci.moneysurfer.domain.primitives.UserId
 import com.georgeci.moneysurfer.domain.primitives.WorkspaceId
 import com.georgeci.moneysurfer.uikit.components.base.SurferToolbar
 import com.georgeci.moneysurfer.uikit.icons.SurferIcons
 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.workspace.generated.resources.Res
 import moneysurfer.feature.workspace.generated.resources.workspace_members_back_content_description
 import moneysurfer.feature.workspace.generated.resources.workspace_members_subtitle_editor_format
 import moneysurfer.feature.workspace.generated.resources.workspace_members_subtitle_owner_format
 import moneysurfer.feature.workspace.generated.resources.workspace_members_subtitle_unknown_format
 import moneysurfer.feature.workspace.generated.resources.workspace_members_subtitle_viewer_format
 import moneysurfer.feature.workspace.generated.resources.workspace_members_title_format
 import org.jetbrains.compose.resources.pluralStringResource
 import org.jetbrains.compose.resources.stringResource
 import org.koin.compose.viewmodel.koinViewModel
 import org.koin.core.parameter.parametersOf
 
 /**
  * Full-screen host for [WorkspaceMembersScreen]. Reuses the same view-model as the bottom-sheet
  * variant — only the surrounding chrome differs. Used from Settings → Members entry, where a
  * dedicated screen reads better than a modal sheet.
  */
 @Composable
 fun WorkspaceManageScreen(
     workspaceId: WorkspaceId,
     onNavigateBack: () -> Unit,
     onNavigateToInvite: (WorkspaceId) -> Unit,
     onNavigateToMemberActions: (WorkspaceId, UserId) -> Unit,
     viewModel: WorkspaceMembersViewModel = koinViewModel(
         key = workspaceId.value,
     ) { parametersOf(workspaceId) },
 ) {
     val state by viewModel.collectAsStateWithLifecycle()
 
     viewModel.HandleSideEffect { effect ->
         when (effect) {
             WorkspaceMembersEffect.Dismiss -> onNavigateBack()
             WorkspaceMembersEffect.OpenInvite -> onNavigateToInvite(workspaceId)
             is WorkspaceMembersEffect.OpenMemberActions ->
                 onNavigateToMemberActions(effect.workspaceId, effect.targetUserId)
             WorkspaceMembersEffect.LeftWorkspace -> onNavigateBack()
             is WorkspaceMembersEffect.ShowError -> Unit
         }
     }
 
     WorkspaceManageScreenContent(
         state = state,
         onEvent = viewModel::onEvent,
         onBack = onNavigateBack,
     )
 }
 
 @Composable
 private fun WorkspaceManageScreenContent(
     state: WorkspaceMembersState,
     onEvent: (WorkspaceMembersEvent) -> Unit,
     onBack: () -> Unit,
 ) {
     val content = state as? WorkspaceMembersState.Content
     val title = content?.workspaceName
         ?.takeIf { it.isNotEmpty() }
         ?.let { stringResource(Res.string.workspace_members_title_format, it) }
         .orEmpty()
     val subtitle = content?.let { roleSubtitle(it.viewerRole, it.activeCount) }.orEmpty()
     Scaffold(
         modifier = Modifier.surferSafeInsets(),
         containerColor = AppTheme.materialColors.surface,
         topBar = {
             SurferToolbar(
                 navigationIcon = {
                     IconButton(onClick = onBack) {
                         Icon(
                             imageVector = SurferIcons.Back,
                             contentDescription = stringResource(Res.string.workspace_members_back_content_description),
                             tint = AppTheme.materialColors.onSurface,
                         )
                     }
                 },
                 colors = TopAppBarDefaults.topAppBarColors(
                     containerColor = AppTheme.materialColors.surface,
                     titleContentColor = AppTheme.materialColors.onSurface,
                 ),
                 title = {
                     Column {
                         Text(
                             text = title,
                             style = AppTheme.typography.titleMedium,
                             color = AppTheme.materialColors.onSurface,
                             maxLines = 1,
                             overflow = TextOverflow.Ellipsis,
                         )
                         if (subtitle.isNotEmpty()) {
                             Text(
                                 text = subtitle,
                                 style = AppTheme.typography.bodySmall,
                                 color = AppTheme.materialColors.onSurfaceVariant,
                                 maxLines = 1,
                                 overflow = TextOverflow.Ellipsis,
                             )
                         }
                     }
                 },
             )
         },
     ) { padding ->
         Column(
             modifier = Modifier
                 .fillMaxSize()
                 .surferContentContainer()
                 .padding(top = padding.calculateTopPadding())
                 .verticalScroll(rememberScrollState()),
         ) {
             WorkspaceMembersScreen(
                 state = state,
                 onEvent = onEvent,
                 showHeader = false,
             )
             Spacer(Modifier.height(padding.calculateBottomPadding()))
         }
     }
 }
 
 @Composable
 private fun roleSubtitle(role: WorkspaceRole?, memberCount: Int): String = when (role) {
     WorkspaceRole.OWNER ->
         pluralStringResource(Res.plurals.workspace_members_subtitle_owner_format, memberCount, memberCount)
     WorkspaceRole.EDITOR ->
         pluralStringResource(Res.plurals.workspace_members_subtitle_editor_format, memberCount, memberCount)
     WorkspaceRole.VIEWER ->
         pluralStringResource(Res.plurals.workspace_members_subtitle_viewer_format, memberCount, memberCount)
     null ->
         pluralStringResource(Res.plurals.workspace_members_subtitle_unknown_format, memberCount, memberCount)
 }
 
 // ── Previews ─────────────────────────────────────────────────────────────────
 
 @Preview
 @Composable
 private fun WorkspaceManageScreenPreview() {
     AppTheme {
         WorkspaceManageScreenContent(
             state = previewState(WorkspaceRole.OWNER),
             onEvent = {},
             onBack = {},
         )
     }
 }