Skip to content

Commit 857273d

Browse files
🧪 [testing] Address PR feedback for VoicesLabelManager.formatLabelValue tests
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
1 parent 3d07a34 commit 857273d

3 files changed

Lines changed: 159 additions & 6 deletions

File tree

‎app/src/main/java/org/ole/planet/myplanet/services/VoicesLabelManager.kt‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,11 @@ class VoicesLabelManager(
127127
}
128128

129129
companion object {
130+
// internal visibility is required for testing
130131
internal fun formatLabelValue(raw: String): String {
131132
val cleaned = raw.replace("_", " ").replace("-", " ")
132133
if (cleaned.isBlank()) {
133-
return raw
134+
return ""
134135
}
135136
return cleaned
136137
.trim()
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
package org.ole.planet.myplanet.services
2+
3+
import android.content.Context
4+
import android.view.View
5+
import fisk.chipcloud.ChipCloud
6+
import io.realm.RealmList
7+
import java.util.Locale
8+
import kotlinx.coroutines.CoroutineScope
9+
import kotlinx.coroutines.Dispatchers
10+
import kotlinx.coroutines.launch
11+
import kotlinx.coroutines.withContext
12+
import org.ole.planet.myplanet.R
13+
import org.ole.planet.myplanet.databinding.RowNewsBinding
14+
import org.ole.planet.myplanet.model.RealmNews
15+
import org.ole.planet.myplanet.repository.VoicesRepository
16+
import org.ole.planet.myplanet.utils.Constants
17+
import org.ole.planet.myplanet.utils.Utilities
18+
19+
class VoicesLabelManager(
20+
private val context: Context,
21+
private val voicesRepository: VoicesRepository,
22+
private val scope: CoroutineScope
23+
) {
24+
fun setupAddLabelMenu(binding: RowNewsBinding, voice: RealmNews?, canManageLabels: Boolean) {
25+
binding.btnAddLabel.setOnClickListener(null)
26+
binding.btnAddLabel.isEnabled = canManageLabels
27+
if (!canManageLabels) {
28+
return
29+
}
30+
31+
binding.btnAddLabel.setOnClickListener {
32+
val usedLabels = voice?.labels?.toSet() ?: emptySet()
33+
val availableLabels = Constants.LABELS.filterValues { it !in usedLabels }
34+
35+
val wrapper = androidx.appcompat.view.ContextThemeWrapper(context, R.style.CustomPopupMenu)
36+
val menu = android.widget.PopupMenu(wrapper, binding.btnAddLabel)
37+
availableLabels.keys.forEach { labelName ->
38+
menu.menu.add(labelName)
39+
}
40+
menu.setOnMenuItemClickListener { menuItem ->
41+
val selectedLabel = Constants.LABELS[menuItem.title]
42+
val voiceId = voice?.id
43+
if (selectedLabel != null && voiceId != null && voice.labels?.contains(selectedLabel) != true) {
44+
scope.launch {
45+
try {
46+
voicesRepository.addLabel(voiceId, selectedLabel)
47+
withContext(Dispatchers.Main) {
48+
if (voice.labels == null) {
49+
voice.labels = RealmList()
50+
}
51+
voice.labels?.add(selectedLabel)
52+
Utilities.toast(context, context.getString(R.string.label_added))
53+
showChips(binding, voice, canManageLabels)
54+
}
55+
} catch (e: Exception) {
56+
e.printStackTrace()
57+
}
58+
}
59+
}
60+
true
61+
}
62+
menu.show()
63+
}
64+
}
65+
66+
fun showChips(binding: RowNewsBinding, voice: RealmNews, canManageLabels: Boolean) {
67+
binding.fbChips.removeAllViews()
68+
69+
for (label in voice.labels ?: emptyList()) {
70+
val chipConfig = Utilities.getCloudConfig().apply {
71+
selectMode(if (canManageLabels) ChipCloud.SelectMode.close else ChipCloud.SelectMode.none)
72+
}
73+
74+
val chipCloud = ChipCloud(context, binding.fbChips, chipConfig)
75+
chipCloud.addChip(getLabel(label))
76+
77+
if (canManageLabels) {
78+
chipCloud.setDeleteListener { _: Int, labelText: String? ->
79+
val selectedLabel = when {
80+
labelText == null -> null
81+
Constants.LABELS.containsKey(labelText) -> Constants.LABELS[labelText]
82+
else -> voice.labels?.firstOrNull { getLabel(it) == labelText }
83+
}
84+
val voiceId = voice.id
85+
if (selectedLabel != null && voiceId != null) {
86+
scope.launch {
87+
try {
88+
voicesRepository.removeLabel(voiceId, selectedLabel)
89+
withContext(Dispatchers.Main) {
90+
voice.labels?.remove(selectedLabel)
91+
showChips(binding, voice, canManageLabels)
92+
}
93+
} catch (e: Exception) {
94+
e.printStackTrace()
95+
}
96+
}
97+
}
98+
}
99+
}
100+
}
101+
updateAddLabelVisibility(binding, voice, canManageLabels)
102+
}
103+
104+
private fun updateAddLabelVisibility(
105+
binding: RowNewsBinding,
106+
voice: RealmNews?,
107+
canManageLabels: Boolean,
108+
) {
109+
if (!canManageLabels) {
110+
binding.btnAddLabel.visibility = View.GONE
111+
return
112+
}
113+
114+
val usedLabels = voice?.labels?.toSet() ?: emptySet()
115+
val labels = Constants.LABELS.values.toSet()
116+
binding.btnAddLabel.visibility =
117+
if (usedLabels.containsAll(labels)) View.GONE else View.VISIBLE
118+
}
119+
120+
private fun getLabel(s: String): String {
121+
for (key in Constants.LABELS.keys) {
122+
if (s == Constants.LABELS[key]) {
123+
return key
124+
}
125+
}
126+
return formatLabelValue(s)
127+
}
128+
129+
companion object {
130+
internal fun formatLabelValue(raw: String): String {
131+
val cleaned = raw.replace("_", " ").replace("-", " ")
132+
if (cleaned.isBlank()) {
133+
return raw
134+
}
135+
return cleaned
136+
.trim()
137+
.split(whitespaceRegex)
138+
.joinToString(" ") { part ->
139+
part.lowercase(Locale.getDefault()).replaceFirstChar { ch ->
140+
if (ch.isLowerCase()) ch.titlecase(Locale.getDefault()) else ch.toString()
141+
}
142+
}
143+
}
144+
private val whitespaceRegex by lazy { Regex("\\s+") }
145+
}
146+
}

‎app/src/test/java/org/ole/planet/myplanet/services/VoicesLabelManagerTest.kt‎

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ import org.junit.Test
55

66
class VoicesLabelManagerTest {
77

8+
@Test
9+
fun testFormatLabelValue_singleWord() {
10+
assertEquals("Hello", VoicesLabelManager.formatLabelValue("hello"))
11+
assertEquals("Hello", VoicesLabelManager.formatLabelValue("HELLO"))
12+
}
13+
814
@Test
915
fun testFormatLabelValue_normalizesCase() {
1016
assertEquals("Hello World", VoicesLabelManager.formatLabelValue("HELLO WORLD"))
@@ -27,11 +33,11 @@ class VoicesLabelManagerTest {
2733
}
2834

2935
@Test
30-
fun testFormatLabelValue_handlesBlankStrings() {
36+
fun testFormatLabelValue_handlesNonAlphaOnlyInputs() {
3137
assertEquals("", VoicesLabelManager.formatLabelValue(""))
32-
assertEquals(" ", VoicesLabelManager.formatLabelValue(" "))
33-
assertEquals(" _ ", VoicesLabelManager.formatLabelValue(" _ "))
34-
assertEquals("-", VoicesLabelManager.formatLabelValue("-"))
35-
assertEquals("_-", VoicesLabelManager.formatLabelValue("_-"))
38+
assertEquals("", VoicesLabelManager.formatLabelValue(" "))
39+
assertEquals("", VoicesLabelManager.formatLabelValue(" _ "))
40+
assertEquals("", VoicesLabelManager.formatLabelValue("-"))
41+
assertEquals("", VoicesLabelManager.formatLabelValue("_-"))
3642
}
3743
}

0 commit comments

Comments
 (0)