@@ -24,9 +24,11 @@ import androidx.compose.foundation.shape.CircleShape
2424import androidx.compose.foundation.shape.RoundedCornerShape
2525import androidx.compose.material.icons.Icons
2626import androidx.compose.material.icons.filled.AccountTree
27+ import androidx.compose.material.icons.filled.DataObject
2728import androidx.compose.material.icons.filled.ExpandLess
2829import androidx.compose.material.icons.filled.ExpandMore
2930import androidx.compose.material.icons.filled.Extension
31+ import androidx.compose.material.icons.filled.Folder
3032import androidx.compose.material.icons.filled.Plumbing
3133import androidx.compose.material3.CardDefaults
3234import androidx.compose.material3.HorizontalDivider
@@ -47,13 +49,15 @@ import androidx.compose.ui.graphics.vector.ImageVector
4749import androidx.compose.ui.input.pointer.PointerIcon
4850import androidx.compose.ui.input.pointer.pointerHoverIcon
4951import androidx.compose.ui.text.font.FontWeight
52+ import androidx.compose.ui.text.style.TextDecoration
5053import androidx.compose.ui.text.style.TextOverflow
5154import androidx.compose.ui.unit.dp
5255import com.meet.dev.analyzer.data.models.project.Dependency
5356import com.meet.dev.analyzer.data.models.project.ModuleBuildFileInfo
5457import com.meet.dev.analyzer.data.models.project.Plugin
5558import com.meet.dev.analyzer.presentation.components.EmptyStateCardLayout
5659import com.meet.dev.analyzer.presentation.components.VerticalScrollBarLayout
60+ import com.meet.dev.analyzer.utility.platform.FolderFileUtils
5761import java.awt.Cursor
5862
5963
@@ -66,12 +70,18 @@ fun ModulesTabContent(
6670 val scrollState = rememberLazyGridState()
6771 LazyVerticalGrid (
6872 state = scrollState,
69- columns = GridCells .Adaptive (minSize = 400 .dp),
73+ columns = GridCells .Adaptive (minSize = 360 .dp),
7074 modifier = Modifier .fillMaxSize(),
7175 contentPadding = PaddingValues (16 .dp),
72- verticalArrangement = Arrangement .spacedBy(16 .dp),
73- horizontalArrangement = Arrangement .spacedBy(16 .dp)
76+ verticalArrangement = Arrangement .spacedBy(12 .dp),
77+ horizontalArrangement = Arrangement .spacedBy(12 .dp)
7478 ) {
79+ if (moduleBuildFileInfos.isNotEmpty()) {
80+ item(span = { GridItemSpan (maxLineSpan) }) {
81+ ModulesSummaryCard (moduleBuildFileInfos = moduleBuildFileInfos)
82+ }
83+ }
84+
7585 items(
7686 items = moduleBuildFileInfos,
7787 key = { module -> module.uniqueId }
@@ -82,7 +92,9 @@ fun ModulesTabContent(
8292 plugins = module.plugins,
8393 fileName = module.type.fileName,
8494 dependencies = module.dependencies,
85- projectName = projectName
95+ projectName = projectName,
96+ modulePath = module.modulePath,
97+ isRootBuildFile = module.isRootBuildFile
8698 )
8799 }
88100
@@ -100,6 +112,126 @@ fun ModulesTabContent(
100112 }
101113}
102114
115+ @Composable
116+ private fun ModulesSummaryCard (moduleBuildFileInfos : List <ModuleBuildFileInfo >) {
117+ val totalSize = FolderFileUtils .formatSize(moduleBuildFileInfos.sumOf { it.sizeBytes })
118+ val pluginCount = moduleBuildFileInfos.sumOf { it.plugins.size }
119+ val dependencyCount = moduleBuildFileInfos.sumOf { it.dependencies.size }
120+ val configurationCount = moduleBuildFileInfos
121+ .flatMap { module -> module.plugins.map { it.configuration } + module.dependencies.map { it.configuration } }
122+ .distinct()
123+ .size
124+
125+ OutlinedCard (
126+ modifier = Modifier .fillMaxWidth(),
127+ colors = CardDefaults .outlinedCardColors(
128+ containerColor = MaterialTheme .colorScheme.surface
129+ )
130+ ) {
131+ Column (
132+ modifier = Modifier .padding(16 .dp),
133+ verticalArrangement = Arrangement .spacedBy(12 .dp)
134+ ) {
135+ Row (
136+ modifier = Modifier .fillMaxWidth(),
137+ verticalAlignment = Alignment .CenterVertically ,
138+ horizontalArrangement = Arrangement .spacedBy(10 .dp)
139+ ) {
140+ Icon (
141+ Icons .Default .AccountTree ,
142+ contentDescription = null ,
143+ tint = MaterialTheme .colorScheme.primary,
144+ modifier = Modifier .size(24 .dp)
145+ )
146+ Text (
147+ " Modules Overview" ,
148+ style = MaterialTheme .typography.titleLarge,
149+ fontWeight = FontWeight .Bold
150+ )
151+ }
152+
153+ Row (
154+ modifier = Modifier .fillMaxWidth(),
155+ horizontalArrangement = Arrangement .spacedBy(10 .dp)
156+ ) {
157+ ModuleSummaryTile (
158+ label = " Modules" ,
159+ value = moduleBuildFileInfos.size.toString(),
160+ icon = Icons .Default .AccountTree ,
161+ modifier = Modifier .weight(1f )
162+ )
163+ ModuleSummaryTile (
164+ label = " Total Size" ,
165+ value = totalSize,
166+ icon = Icons .Default .Folder ,
167+ modifier = Modifier .weight(1f )
168+ )
169+ ModuleSummaryTile (
170+ label = " Plugins" ,
171+ value = pluginCount.toString(),
172+ icon = Icons .Default .Plumbing ,
173+ modifier = Modifier .weight(1f )
174+ )
175+ ModuleSummaryTile (
176+ label = " Dependencies" ,
177+ value = dependencyCount.toString(),
178+ icon = Icons .Default .DataObject ,
179+ modifier = Modifier .weight(1f )
180+ )
181+ ModuleSummaryTile (
182+ label = " Configurations" ,
183+ value = configurationCount.toString(),
184+ icon = Icons .Default .Extension ,
185+ modifier = Modifier .weight(1f )
186+ )
187+ }
188+ }
189+ }
190+ }
191+
192+ @Composable
193+ private fun ModuleSummaryTile (
194+ label : String ,
195+ value : String ,
196+ icon : ImageVector ,
197+ modifier : Modifier = Modifier
198+ ) {
199+ Surface (
200+ modifier = modifier,
201+ color = MaterialTheme .colorScheme.surfaceVariant,
202+ shape = MaterialTheme .shapes.medium
203+ ) {
204+ Row (
205+ modifier = Modifier .padding(horizontal = 12 .dp, vertical = 10 .dp),
206+ verticalAlignment = Alignment .CenterVertically ,
207+ horizontalArrangement = Arrangement .spacedBy(8 .dp)
208+ ) {
209+ Icon (
210+ icon,
211+ contentDescription = null ,
212+ tint = MaterialTheme .colorScheme.primary,
213+ modifier = Modifier .size(18 .dp)
214+ )
215+ Column {
216+ Text (
217+ value,
218+ style = MaterialTheme .typography.titleMedium,
219+ fontWeight = FontWeight .Bold ,
220+ maxLines = 1 ,
221+ overflow = TextOverflow .Ellipsis
222+ )
223+ Text (
224+ label,
225+ style = MaterialTheme .typography.labelSmall,
226+ color = MaterialTheme .colorScheme.onSurfaceVariant,
227+ maxLines = 1 ,
228+ overflow = TextOverflow .Ellipsis
229+ )
230+ }
231+ }
232+ }
233+ }
234+
103235
104236@Composable
105237fun DetailedModuleCard (
@@ -109,6 +241,8 @@ fun DetailedModuleCard(
109241 plugins : List <Plugin >,
110242 dependencies : List <Dependency >,
111243 projectName : String ,
244+ modulePath : String ,
245+ isRootBuildFile : Boolean ,
112246) {
113247
114248 OutlinedCard (
@@ -119,9 +253,8 @@ fun DetailedModuleCard(
119253 ) {
120254 Column (
121255 modifier = Modifier .padding(20 .dp),
122- verticalArrangement = Arrangement .spacedBy(12 .dp)
256+ verticalArrangement = Arrangement .spacedBy(10 .dp)
123257 ) {
124- // Module header
125258 Row (
126259 modifier = Modifier .fillMaxWidth(),
127260 verticalAlignment = Alignment .CenterVertically
@@ -131,7 +264,14 @@ fun DetailedModuleCard(
131264 imageVector = getModuleIcon(moduleName = moduleName, projectName = projectName),
132265 contentDescription = moduleName,
133266 tint = getModuleColor(moduleName = moduleName, projectName = projectName),
134- modifier = Modifier .size(24 .dp)
267+ modifier = Modifier
268+ .size(34 .dp)
269+ .background(
270+ getModuleColor(moduleName = moduleName, projectName = projectName)
271+ .copy(alpha = 0.12f ),
272+ CircleShape
273+ )
274+ .padding(7 .dp)
135275 )
136276 Spacer (modifier = Modifier .width(12 .dp))
137277 Column (modifier = Modifier .weight(1f )) {
@@ -140,27 +280,48 @@ fun DetailedModuleCard(
140280 .replaceFirstChar { it.uppercase() },
141281 style = MaterialTheme .typography.titleMedium,
142282 fontWeight = FontWeight .Bold ,
283+ maxLines = 1 ,
284+ overflow = TextOverflow .Ellipsis
143285 )
144286 Text (
145- text = fileName.replaceFirstChar { it.uppercase() },
146- style = MaterialTheme .typography.bodyMedium,
147- color = getModuleColor(moduleName = moduleName, projectName = projectName)
287+ text = modulePath.ifBlank { fileName }.replaceFirstChar { it.uppercase() },
288+ style = MaterialTheme .typography.bodySmall,
289+ color = MaterialTheme .colorScheme.onSurfaceVariant,
290+ maxLines = 1 ,
291+ overflow = TextOverflow .Ellipsis ,
292+ textDecoration = TextDecoration .Underline ,
293+ modifier = Modifier .pointerHoverIcon(
294+ PointerIcon (
295+ Cursor .getPredefinedCursor(
296+ Cursor .HAND_CURSOR
297+ )
298+ )
299+ )
148300 )
149301 }
150- Surface (
151- color = MaterialTheme .colorScheme.primaryContainer,
152- shape = MaterialTheme .shapes.medium
153- ) {
154- Text (
155- text = sizeReadable,
156- style = MaterialTheme .typography.labelLarge,
157- fontWeight = FontWeight .Bold ,
158- modifier = Modifier .padding(horizontal = 12 .dp, vertical = 6 .dp)
159- )
302+ Column (horizontalAlignment = Alignment .End ) {
303+ Surface (
304+ color = MaterialTheme .colorScheme.primaryContainer,
305+ shape = MaterialTheme .shapes.medium
306+ ) {
307+ Text (
308+ text = sizeReadable,
309+ style = MaterialTheme .typography.labelLarge,
310+ fontWeight = FontWeight .Bold ,
311+ modifier = Modifier .padding(horizontal = 10 .dp, vertical = 5 .dp)
312+ )
313+ }
314+ if (isRootBuildFile) {
315+ Text (
316+ " Root" ,
317+ style = MaterialTheme .typography.labelSmall,
318+ color = MaterialTheme .colorScheme.primary,
319+ modifier = Modifier .padding(top = 4 .dp)
320+ )
321+ }
160322 }
161323 }
162324
163- // Module stats in grid
164325 if (plugins.isNotEmpty() || dependencies.isNotEmpty()) {
165326 Row (
166327 modifier = Modifier .fillMaxWidth(),
@@ -437,4 +598,4 @@ fun ModuleRow(
437598 color = MaterialTheme .colorScheme.onSurfaceVariant
438599 )
439600 }
440- }
601+ }
0 commit comments