Skip to content

Commit 5356322

Browse files
committed
Enhance duplicate icon name resolution with case-insensitive checks
1 parent b05c4b2 commit 5356322

File tree

4 files changed

+68
-23
lines changed

4 files changed

+68
-23
lines changed

tools/gradle-plugin/src/main/kotlin/io/github/composegears/valkyrie/gradle/internal/task/GenerateImageVectorsTask.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,6 @@ internal abstract class GenerateImageVectorsTask : DefaultTask() {
119119
// Check for duplicates with nested pack awareness
120120
validateDuplicates(iconFiles.files.toList(), iconNames)
121121

122-
123122
if (iconPack.isPresent && iconPack.get().targetSourceSet.get() == sourceSet.get()) {
124123
generateIconPack(outputDirectory = outputDirectory)
125124
}

tools/idea-plugin/src/main/kotlin/io/github/composegears/valkyrie/jewel/textfield/ConfirmTextField.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.width
77
import androidx.compose.foundation.text.input.rememberTextFieldState
88
import androidx.compose.foundation.text.input.setTextAndPlaceCursorAtEnd
99
import androidx.compose.runtime.Composable
10+
import androidx.compose.runtime.LaunchedEffect
1011
import androidx.compose.runtime.derivedStateOf
1112
import androidx.compose.runtime.getValue
1213
import androidx.compose.runtime.remember
@@ -41,6 +42,13 @@ fun ConfirmTextField(
4142
val state = rememberTextFieldState(text)
4243
val focusManager = LocalFocusManager.current
4344

45+
// Update text field state when external text changes
46+
LaunchedEffect(text) {
47+
if (state.text.toString() != text) {
48+
state.setTextAndPlaceCursorAtEnd(text)
49+
}
50+
}
51+
4452
val isError by remember { derivedStateOf { state.text.isEmpty() } }
4553
var focused by rememberMutableState { false }
4654

tools/idea-plugin/src/main/kotlin/io/github/composegears/valkyrie/ui/screen/mode/iconpack/conversion/IconPackConversionViewModel.kt

Lines changed: 55 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ class IconPackConversionViewModel(
148148
}
149149
copy(
150150
icons = updatedIcons,
151-
importIssues = updatedIcons.checkImportIssues(useFlatPackage = isFlatPackage)
151+
importIssues = updatedIcons.checkImportIssues(useFlatPackage = isFlatPackage),
152152
)
153153
}
154154
else -> this
@@ -271,35 +271,74 @@ class IconPackConversionViewModel(
271271
}
272272
}
273273

274-
val nameGroups = processedIcons.groupBy { it.iconName.name }
275-
val nameCounters = mutableMapOf<String, Int>()
274+
// Group icons by their output location (considering useFlatPackage)
275+
val iconsByLocation = processedIcons.groupBy { icon ->
276+
when (val pack = icon.iconPack) {
277+
is IconPack.Single -> pack.iconPackName
278+
is IconPack.Nested -> when {
279+
isFlatPackage -> pack.iconPackName // All in same location when flat
280+
else -> "${pack.iconPackName}.${pack.currentNestedPack}" // Separate locations
281+
}
282+
}
283+
}
284+
285+
// Process duplicates within each location group
286+
val resolvedIcons = iconsByLocation.flatMap { (_, iconsInLocation) ->
287+
// First, resolve exact duplicates
288+
val nameGroups = iconsInLocation.groupBy { it.iconName.name }
289+
val nameCounters = mutableMapOf<String, Int>()
290+
291+
val iconsWithResolvedExactDuplicates = iconsInLocation.map { icon ->
292+
val originalName = icon.iconName.name
293+
val group = nameGroups[originalName]
294+
295+
if (group != null && group.size > 1) {
296+
val counter = nameCounters.getOrDefault(originalName, 0) + 1
297+
nameCounters[originalName] = counter
298+
299+
if (counter > 1) {
300+
icon.copy(iconName = IconName("$originalName${counter - 1}"))
301+
} else {
302+
icon
303+
}
304+
} else {
305+
icon
306+
}
307+
}
308+
309+
// Then, resolve case-insensitive duplicates
310+
val lowercaseGroups = iconsWithResolvedExactDuplicates.groupBy { it.iconName.name.lowercase() }
311+
val lowercaseCounters = mutableMapOf<String, Int>()
276312

277-
val icons = processedIcons.map { icon ->
278-
val originalName = icon.iconName.name
279-
val group = nameGroups[originalName]
313+
iconsWithResolvedExactDuplicates.map { icon ->
314+
val currentName = icon.iconName.name
315+
val lowercaseKey = currentName.lowercase()
316+
val group = lowercaseGroups[lowercaseKey]
280317

281-
if (group != null && group.size > 1) {
282-
val counter = nameCounters.getOrDefault(originalName, 0) + 1
283-
nameCounters[originalName] = counter
318+
// Only process if there are multiple icons with same lowercase name but different actual names
319+
if (group != null && group.size > 1 && group.map { it.iconName.name }.distinct().size > 1) {
320+
val counter = lowercaseCounters.getOrDefault(lowercaseKey, 0) + 1
321+
lowercaseCounters[lowercaseKey] = counter
284322

285-
if (counter > 1) {
286-
icon.copy(iconName = IconName("$originalName${counter - 1}"))
323+
if (counter > 1) {
324+
icon.copy(iconName = IconName("$currentName${counter - 1}"))
325+
} else {
326+
icon
327+
}
287328
} else {
288329
icon
289330
}
290-
} else {
291-
icon
292331
}
293332
}
294333

295-
if (icons.isEmpty()) {
334+
if (resolvedIcons.isEmpty()) {
296335
_events.emit(ConversionEvent.NothingToImport)
297336
reset()
298337
} else {
299338
_state.updateState {
300339
creationState.copy(
301-
icons = icons,
302-
importIssues = icons.checkImportIssues(useFlatPackage = isFlatPackage),
340+
icons = resolvedIcons,
341+
importIssues = resolvedIcons.checkImportIssues(useFlatPackage = isFlatPackage),
303342
)
304343
}
305344
}

tools/idea-plugin/src/main/kotlin/io/github/composegears/valkyrie/ui/screen/mode/iconpack/conversion/ui/util/IconValidation.kt

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ fun List<BatchIcon>.checkImportIssues(useFlatPackage: Boolean = false): Map<Vali
4949
val packIdentifier = when (val pack = it.iconPack) {
5050
is IconPack.Single -> pack.iconPackName
5151
is IconPack.Nested -> when {
52-
useFlatPackage -> pack.iconPackName // Flat package: check across all nested packs
53-
else -> "${pack.iconPackName}.${pack.currentNestedPack}" // Separate folders per nested pack
52+
useFlatPackage -> pack.iconPackName // Flat package: check across all nested packs
53+
else -> "${pack.iconPackName}.${pack.currentNestedPack}" // Separate folders per nested pack
5454
}
5555
}
5656
packIdentifier to it.iconName.name
@@ -72,17 +72,16 @@ fun List<BatchIcon>.checkImportIssues(useFlatPackage: Boolean = false): Map<Vali
7272
val packIdentifier = when (val pack = it.iconPack) {
7373
is IconPack.Single -> pack.iconPackName
7474
is IconPack.Nested -> when {
75-
useFlatPackage -> pack.iconPackName // Flat package: check across all nested packs
76-
else -> "${pack.iconPackName}.${pack.currentNestedPack}" // Separate folders per nested pack
75+
useFlatPackage -> pack.iconPackName // Flat package: check across all nested packs
76+
else -> "${pack.iconPackName}.${pack.currentNestedPack}" // Separate folders per nested pack
7777
}
7878
}
7979
packIdentifier to it.iconName.name.lowercase()
8080
}
8181
.filter {
8282
// Filter groups where there are multiple icons with the same lowercase name
8383
// but they are not already exact duplicates
84-
it.value.size > 1 &&
85-
it.value.map { icon -> icon.iconName.name }.distinct().size > 1
84+
it.value.size > 1 && it.value.map { icon -> icon.iconName.name }.distinct().size > 1
8685
}
8786
.values
8887
.flatten()

0 commit comments

Comments
 (0)