From 11d3798930908d4dcf6ce24b9e9c4a9c78e3db63 Mon Sep 17 00:00:00 2001 From: Ndiritu Date: Wed, 2 Oct 2024 16:07:51 +0300 Subject: [PATCH] extract filters column to its own composable --- .../com/devmike/issues/screen/IssuesScreen.kt | 132 ++---------------- .../issues/screen/components/FiltersScreen.kt | 132 ++++++++++++++++++ 2 files changed, 143 insertions(+), 121 deletions(-) create mode 100644 feature/issues/src/main/java/com/devmike/issues/screen/components/FiltersScreen.kt diff --git a/feature/issues/src/main/java/com/devmike/issues/screen/IssuesScreen.kt b/feature/issues/src/main/java/com/devmike/issues/screen/IssuesScreen.kt index 3514022..fcab2cb 100644 --- a/feature/issues/src/main/java/com/devmike/issues/screen/IssuesScreen.kt +++ b/feature/issues/src/main/java/com/devmike/issues/screen/IssuesScreen.kt @@ -1,46 +1,35 @@ package com.devmike.issues.screen import androidx.compose.animation.AnimatedContent -import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.ExperimentalFoundationApi -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.WindowInsets 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.layout.size import androidx.compose.foundation.layout.wrapContentWidth import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.filled.Search import androidx.compose.material3.Button import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.FilterChip -import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold -import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable -import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview @@ -50,12 +39,11 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.paging.LoadState import androidx.paging.PagingData import androidx.paging.compose.collectAsLazyPagingItems -import com.devmike.domain.helper.IssueState import com.devmike.domain.models.IssueModel import com.devmike.domain.models.LabelModel import com.devmike.issues.screen.components.AssigneesScreen +import com.devmike.issues.screen.components.FiltersScreen import com.devmike.issues.screen.components.IssueCard -import com.devmike.issues.screen.components.IssueStateChip import com.devmike.issues.screen.components.LabelsScreen import com.devmike.issues.screen.components.NoIssuesFoundScreen import com.devmike.issues.screen.components.SearchTextField @@ -77,13 +65,6 @@ fun IssuesScreen( val selectedAssignes by viewModel.selectedAssignees.collectAsStateWithLifecycle() val selectedLabels by viewModel.selectedLabels.collectAsStateWithLifecycle() - val showClearChip = - remember(selectedAssignes, selectedLabels) { - derivedStateOf { - selectedAssignes.isNotEmpty() || selectedLabels.isNotEmpty() - } - }.value - val selectedIssueState by viewModel.selectedIssueState.collectAsStateWithLifecycle() AssigneesScreen( @@ -162,104 +143,15 @@ fun IssuesScreen( ), ) { stickyHeader { - Surface { - Column( - horizontalAlignment = Alignment.CenterHorizontally, - modifier = Modifier.fillMaxWidth(), - ) { - Row( - modifier = Modifier.padding(horizontal = 8.dp), - horizontalArrangement = Arrangement.spacedBy(8.dp), - verticalAlignment = Alignment.CenterVertically, - ) { - IssueStateChip( - selectedState = selectedIssueState, - states = IssueState.entries, - onStateSelected = { - viewModel.modifyIssueState(it) - }, - ) - FilterChip( - selected = selectedLabels.isNotEmpty(), - onClick = { showLabelsDialog = true }, - leadingIcon = { - if (selectedLabels.isNotEmpty()) { - Box( - modifier = - Modifier - .background( - MaterialTheme.colorScheme.onPrimary, - CircleShape, - ).clip(CircleShape) - .size(15.dp), - ) { - Text( - text = "${ - - selectedLabels.size - }", - modifier = - Modifier - .align(Alignment.Center), - style = MaterialTheme.typography.labelSmall, - ) - } - } - }, - label = { - Text( - text = "Labels", - ) - }, - ) - - FilterChip( - selected = selectedAssignes.isNotEmpty(), - onClick = { showAssigneesDialog = true }, - leadingIcon = { - if (selectedAssignes.isNotEmpty()) { - Box( - modifier = - Modifier - .background( - MaterialTheme.colorScheme.onPrimary, - CircleShape, - ).clip(CircleShape) - .size(15.dp), - ) { - Text( - text = "${ - - selectedAssignes.size - }", - modifier = - Modifier - .align(Alignment.Center), - style = MaterialTheme.typography.labelSmall, - ) - } - } - }, - label = { - Text( - text = - - "Assignees", - ) - }, - ) - - AnimatedVisibility(showClearChip) { - FilterChip( - selected = showClearChip, - onClick = { viewModel.clearFilters() }, - label = { Text(text = "Clear Filters") }, - ) - } - } - HorizontalDivider() - } - } + FiltersScreen( + selectedAssignes = selectedAssignes.map { it.username }, + selectedLabels = selectedLabels.map { it.name }, + selectedIssueState = selectedIssueState, + showLabelsDialog = { showLabelsDialog = true }, + showAssigneesDialog = { showAssigneesDialog = true }, + clearFilters = viewModel::clearFilters, + modifyIssueState = viewModel::modifyIssueState, + ) } items(issues.itemCount) { index -> val issue = issues[index] @@ -282,9 +174,7 @@ fun IssuesScreen( loadState.refresh is LoadState.Loading -> { item { Box( - modifier = - Modifier - .padding(), + modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.Center, ) { CircularProgressIndicator( diff --git a/feature/issues/src/main/java/com/devmike/issues/screen/components/FiltersScreen.kt b/feature/issues/src/main/java/com/devmike/issues/screen/components/FiltersScreen.kt new file mode 100644 index 0000000..4dc0a43 --- /dev/null +++ b/feature/issues/src/main/java/com/devmike/issues/screen/components/FiltersScreen.kt @@ -0,0 +1,132 @@ +package com.devmike.issues.screen.components + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.FilterChip +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.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.unit.dp +import com.devmike.domain.helper.IssueState + +@Composable +fun FiltersScreen( + selectedAssignes: List, + selectedLabels: List, + selectedIssueState: IssueState, + showLabelsDialog: () -> Unit, + showAssigneesDialog: () -> Unit, + clearFilters: () -> Unit, + modifyIssueState: (IssueState) -> Unit, +) { + val showClearChip = selectedAssignes.isNotEmpty() || selectedLabels.isNotEmpty() + Surface { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier.fillMaxWidth(), + ) { + Row( + modifier = Modifier.padding(horizontal = 8.dp), + horizontalArrangement = Arrangement.spacedBy(8.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + IssueStateChip( + selectedState = selectedIssueState, + states = IssueState.entries, + onStateSelected = modifyIssueState, + ) + FilterChip( + selected = selectedLabels.isNotEmpty(), + onClick = showLabelsDialog, + leadingIcon = { + if (selectedLabels.isNotEmpty()) { + Box( + modifier = + Modifier + .background( + MaterialTheme.colorScheme.onPrimary, + CircleShape, + ).clip(CircleShape) + .size(15.dp), + ) { + Text( + text = "${ + + selectedLabels.size + }", + modifier = + Modifier + .align(Alignment.Center), + style = MaterialTheme.typography.labelSmall, + ) + } + } + }, + label = { + Text( + text = "Labels", + ) + }, + ) + + FilterChip( + selected = selectedAssignes.isNotEmpty(), + onClick = showAssigneesDialog, + leadingIcon = { + if (selectedAssignes.isNotEmpty()) { + Box( + modifier = + Modifier + .background( + MaterialTheme.colorScheme.onPrimary, + CircleShape, + ).clip(CircleShape) + .size(15.dp), + ) { + Text( + text = "${ + + selectedAssignes.size + }", + modifier = + Modifier + .align(Alignment.Center), + style = MaterialTheme.typography.labelSmall, + ) + } + } + }, + label = { + Text( + text = + + "Assignees", + ) + }, + ) + + AnimatedVisibility(showClearChip) { + FilterChip( + selected = showClearChip, + onClick = clearFilters, + label = { Text(text = "Clear Filters") }, + ) + } + } + HorizontalDivider() + } + } +}