refactor(i18n): final sweep for hardcoded strings and test refactoring
All checks were successful
Update Wiki Documentation / generate-docs (push) Successful in 2m12s

This commit is contained in:
Krzysztof Cieślik
2026-06-14 06:37:57 +02:00
parent 5467792b5a
commit 231ec0cf92
10 changed files with 86 additions and 60 deletions

View File

@@ -14,9 +14,15 @@ class AutomatedClickTest {
@Test
fun clickThroughAllTabs() {
Thread.sleep(1000)
val tabs = listOf("OŚWIETLENIE", "GNIAZDKA", "MOC", "POGODA", "WSZYSTKO")
tabs.forEach { tabName ->
onView(withText(tabName)).perform(click())
val tabResIds = listOf(
R.string.tab_lighting,
R.string.tab_sockets,
R.string.tab_power,
R.string.tab_weather,
R.string.tab_all
)
tabResIds.forEach { resId ->
onView(withText(resId)).perform(click())
Thread.sleep(500)
}
}

View File

@@ -26,14 +26,20 @@ class MonkeyStressTest {
@Test
fun runMonkeyTest() {
val iterations = 50
val tabs = listOf("WSZYSTKO", "OŚWIETLENIE", "GNIAZDKA", "MOC", "POGODA")
val tabResIds = listOf(
R.string.tab_all,
R.string.tab_lighting,
R.string.tab_sockets,
R.string.tab_power,
R.string.tab_weather
)
for (i in 1..iterations) {
val actionType = random.nextInt(3)
try {
when (actionType) {
0 -> {
val tab = tabs[random.nextInt(tabs.size)]
onView(withText(tab)).perform(click())
val tabResId = tabResIds[random.nextInt(tabResIds.size)]
onView(withText(tabResId)).perform(click())
}
1 -> {
onView(withId(R.id.gridView)).perform(clickRandomItem())
@@ -52,7 +58,7 @@ class MonkeyStressTest {
private fun clickRandomItem(): ViewAction {
return object : ViewAction {
override fun getConstraints(): Matcher<View> = withId(R.id.gridView)
override fun getDescription(): String = "Kliknięcie losowego elementu w GridView"
override fun getDescription(): String = "Click random element in GridView"
override fun perform(uiController: UiController, view: View) {
val gridView = view as GridView
if (gridView.childCount > 0) {

View File

@@ -49,21 +49,21 @@ class ConnectionSettingsActivity : BaseActivity() {
Prefs.setSelectedEntities(this@ConnectionSettingsActivity, emptySet())
HaClient.clearCache()
runOnUiThread {
tvStatus.text = "POŁĄCZONO POMYŚLNIE"
tvStatus.text = strings.get(StringKey.STATUS_SUCCESS)
tvStatus.setTextColor(0xFF0056B3.toInt())
Toast.makeText(this@ConnectionSettingsActivity, "Zapisano i wyczyszczono widżety", Toast.LENGTH_SHORT).show()
Toast.makeText(this@ConnectionSettingsActivity, strings.get(StringKey.TOAST_SAVED_CLEARED), Toast.LENGTH_SHORT).show()
finish()
}
} else {
runOnUiThread {
tvStatus.text = "BŁĄD: ${response.code()}"
tvStatus.text = "${strings.get(StringKey.STATUS_ERROR)}: ${response.code()}"
tvStatus.setTextColor(0xFFE23A24.toInt())
}
}
}
override fun onFailure(call: Call<List<HaState>>, t: Throwable) {
runOnUiThread {
tvStatus.text = "BŁĄD SIECI: ${t.message}"
tvStatus.text = "${strings.get(StringKey.STATUS_ERROR_NETWORK)}: ${t.message}"
tvStatus.setTextColor(0xFFE23A24.toInt())
}
}

View File

@@ -20,13 +20,14 @@ class EntitySelectionActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_entity_selection)
val strings = com.example.retroha.i18n.AndroidStrings(this)
etSearch = findViewById(R.id.etSearch)
lvEntities = findViewById(R.id.lvEntities)
val btnSave = findViewById<Button>(R.id.btnSave)
selectedEntities.addAll(Prefs.getSelectedEntities(this))
btnSave.setOnClickListener {
Prefs.setSelectedEntities(this, selectedEntities)
Toast.makeText(this, "Wybrane encje zapisane", Toast.LENGTH_SHORT).show()
Toast.makeText(this, strings.get(com.example.retroha.i18n.StringKey.TOAST_ENTITIES_SAVED), Toast.LENGTH_SHORT).show()
finish()
}
etSearch.addTextChangedListener(object : TextWatcher {
@@ -58,12 +59,14 @@ class EntitySelectionActivity : BaseActivity() {
allEntities.sortBy { it.entity_id }
runOnUiThread { filterEntities(etSearch.text.toString()) }
} else {
runOnUiThread { Toast.makeText(this@EntitySelectionActivity, "Błąd HA: ${response.code()}", Toast.LENGTH_SHORT).show() }
val strings = com.example.retroha.i18n.AndroidStrings(this@EntitySelectionActivity)
runOnUiThread { Toast.makeText(this@EntitySelectionActivity, "${strings.get(com.example.retroha.i18n.StringKey.STATUS_ERROR_HA)}: ${response.code()}", Toast.LENGTH_SHORT).show() }
}
}
override fun onFailure(call: Call<List<HaState>>, t: Throwable) {
val strings = com.example.retroha.i18n.AndroidStrings(this@EntitySelectionActivity)
runOnUiThread {
Toast.makeText(this@EntitySelectionActivity, "Błąd: ${t.message}", Toast.LENGTH_LONG).show()
Toast.makeText(this@EntitySelectionActivity, "${strings.get(com.example.retroha.i18n.StringKey.STATUS_ERROR_NETWORK)}: ${t.message}", Toast.LENGTH_LONG).show()
}
}
})

View File

@@ -29,8 +29,9 @@ class LanguageActivity : BaseActivity() {
setBackgroundColor(Colors.WHITE)
setPadding(dp(32), dp(32), dp(32), dp(32))
}
val strings = AndroidStrings(this)
val title = TextView(this).apply {
text = "WYBIERZ JĘZYK\nSELECT LANGUAGE"
text = strings.get(StringKey.TITLE_SELECT_LANGUAGE)
typeface = android.graphics.Typeface.MONOSPACE
textSize = 18f
setTextColor(Colors.BLACK)

View File

@@ -36,7 +36,7 @@ class MainActivity : BaseActivity() {
private val allEntities = mutableListOf<WidgetConfig>()
private val displayedEntities = mutableListOf<WidgetConfig>()
private val mainHandler = Handler(Looper.getMainLooper())
private var currentCategory = "WSZYSTKO"
private var currentCategory = StringKey.TAB_ALL
private lateinit var tvStatusIndicator: TextView
private lateinit var tabContainer: LinearLayout
private val refreshRunnable = object : Runnable {
@@ -78,12 +78,18 @@ class MainActivity : BaseActivity() {
}
findViewById<android.view.View>(R.id.tvTitle).setOnClickListener {
fetchHaStates()
Toast.makeText(this, "Odświeżanie...", Toast.LENGTH_SHORT).show()
Toast.makeText(this, strings.get(StringKey.STATUS_REFRESHING), Toast.LENGTH_SHORT).show()
}
setupTabs()
}
private fun setupTabs() {
val categories = listOf("WSZYSTKO", "OŚWIETLENIE", "GNIAZDKA", "MOC", "POGODA")
val categories = listOf(
StringKey.TAB_ALL,
StringKey.TAB_LIGHTING,
StringKey.TAB_SOCKETS,
StringKey.TAB_POWER,
StringKey.TAB_WEATHER
)
val mainView = findViewById<View>(android.R.id.content)
tabContainer.post {
tabContainer.removeAllViews()
@@ -102,7 +108,7 @@ class MainActivity : BaseActivity() {
}
val tabButton = TextView(this).apply {
layoutParams = FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT)
text = cat
text = strings.get(cat)
typeface = android.graphics.Typeface.MONOSPACE
textSize = 11f
setPadding(dp(12), 0, dp(12), 0)
@@ -131,14 +137,14 @@ class MainActivity : BaseActivity() {
private fun dp(v: Int) = (v * resources.displayMetrics.density + 0.5f).toInt()
private fun filterEntities() {
val filtered = when (currentCategory) {
"WSZYSTKO" -> allEntities
"OŚWIETLENIE" -> allEntities.filter { it.domain == "light" }
"GNIAZDKA" -> allEntities.filter {
StringKey.TAB_ALL -> allEntities
StringKey.TAB_LIGHTING -> allEntities.filter { it.domain == "light" }
StringKey.TAB_SOCKETS -> allEntities.filter {
it.domain == "switch" || it.domain == "outlet" ||
it.entityId.contains("socket") || it.entityId.contains("plug")
}
"MOC" -> allEntities.filter { it.secondary.contains("W") || it.entityId.contains("power") || it.entityId.contains("energy") || it.entityId.contains("current_consumption") }
"POGODA" -> allEntities.filter { it.domain == "weather" || it.domain == "sensor" && (it.entityId.contains("temp") || it.entityId.contains("hum")) }
StringKey.TAB_POWER -> allEntities.filter { it.secondary.contains("W") || it.entityId.contains("power") || it.entityId.contains("energy") || it.entityId.contains("current_consumption") }
StringKey.TAB_WEATHER -> allEntities.filter { it.domain == "weather" || it.domain == "sensor" && (it.entityId.contains("temp") || it.entityId.contains("hum")) }
else -> allEntities
}
runOnUiThread {
@@ -157,7 +163,7 @@ class MainActivity : BaseActivity() {
private fun fetchHaStates() {
val token = Prefs.getToken(this)
if (token.isEmpty()) {
tvStatusIndicator.text = "BRAK TOKENU"
tvStatusIndicator.text = strings.get(StringKey.STATUS_NO_TOKEN)
tvStatusIndicator.setTextColor(com.example.retroha.theme.Colors.RED)
return
}
@@ -167,19 +173,19 @@ class MainActivity : BaseActivity() {
val states = response.body() ?: return
updateEntities(states)
runOnUiThread {
tvStatusIndicator.text = "ONLINE"
tvStatusIndicator.text = strings.get(StringKey.STATUS_CONNECTED)
tvStatusIndicator.setTextColor(com.example.retroha.theme.Colors.BLUE)
}
} else {
runOnUiThread {
tvStatusIndicator.text = "BŁĄD HA: ${response.code()}"
tvStatusIndicator.text = "${strings.get(StringKey.STATUS_ERROR_HA)}: ${response.code()}"
tvStatusIndicator.setTextColor(com.example.retroha.theme.Colors.RED)
}
}
}
override fun onFailure(call: Call<List<HaState>>, t: Throwable) {
runOnUiThread {
tvStatusIndicator.text = "OFFLINE"
tvStatusIndicator.text = strings.get(StringKey.STATUS_OFFLINE)
tvStatusIndicator.setTextColor(com.example.retroha.theme.Colors.RED)
}
}
@@ -254,12 +260,12 @@ class MainActivity : BaseActivity() {
HaClient.getService(this).toggle(domain, ToggleRequest(cfg.entityId)).enqueue(object : Callback<List<HaState>> {
override fun onResponse(call: Call<List<HaState>>, response: Response<List<HaState>>) {
if (!response.isSuccessful) {
runOnUiThread { Toast.makeText(this@MainActivity, "BŁĄD HA: ${response.code()}", Toast.LENGTH_SHORT).show() }
runOnUiThread { Toast.makeText(this@MainActivity, "${strings.get(StringKey.STATUS_ERROR_HA)}: ${response.code()}", Toast.LENGTH_SHORT).show() }
}
fetchHaStates()
}
override fun onFailure(call: Call<List<HaState>>, t: Throwable) {
runOnUiThread { Toast.makeText(this@MainActivity, "BŁĄD SIECI: ${t.message}", Toast.LENGTH_SHORT).show() }
runOnUiThread { Toast.makeText(this@MainActivity, "${strings.get(StringKey.STATUS_ERROR_NETWORK)}: ${t.message}", Toast.LENGTH_SHORT).show() }
fetchHaStates()
}
})
@@ -276,12 +282,12 @@ class MainActivity : BaseActivity() {
HaClient.getService(this).toggle(domain, ToggleRequest(cfg.entityId)).enqueue(object : Callback<List<HaState>> {
override fun onResponse(call: Call<List<HaState>>, response: Response<List<HaState>>) {
if (!response.isSuccessful) {
runOnUiThread { Toast.makeText(this@MainActivity, "BŁĄD HA: ${response.code()}", Toast.LENGTH_SHORT).show() }
runOnUiThread { Toast.makeText(this@MainActivity, "${strings.get(StringKey.STATUS_ERROR_HA)}: ${response.code()}", Toast.LENGTH_SHORT).show() }
}
fetchHaStates()
}
override fun onFailure(call: Call<List<HaState>>, t: Throwable) {
runOnUiThread { Toast.makeText(this@MainActivity, "BŁĄD SIECI: ${t.message}", Toast.LENGTH_SHORT).show() }
runOnUiThread { Toast.makeText(this@MainActivity, "${strings.get(StringKey.STATUS_ERROR_NETWORK)}: ${t.message}", Toast.LENGTH_SHORT).show() }
fetchHaStates()
}
})

View File

@@ -35,6 +35,12 @@ class AndroidStrings(private val context: Context) : Strings {
StringKey.STATUS_OFFLINE -> R.string.status_offline
StringKey.STATUS_ERROR_HA -> R.string.status_error_ha
StringKey.STATUS_NO_TOKEN -> R.string.status_no_token
StringKey.TITLE_SELECT_LANGUAGE -> R.string.title_select_language
StringKey.STATUS_REFRESHING -> R.string.status_refreshing
StringKey.STATUS_SUCCESS -> R.string.status_success
StringKey.TOAST_SAVED_CLEARED -> R.string.toast_saved_cleared
StringKey.STATUS_ERROR -> R.string.status_error
StringKey.STATUS_ERROR_NETWORK -> R.string.status_error_network
StringKey.CONFIRM_DELETE_ALL -> R.string.confirm_delete_all
StringKey.CONFIRM_CHANGE_CONN -> R.string.confirm_change_conn
StringKey.DIALOG_BRIGHTNESS -> R.string.dialog_brightness
@@ -44,6 +50,7 @@ class AndroidStrings(private val context: Context) : Strings {
StringKey.DIALOG_YES_CHANGE -> R.string.dialog_yes_change
StringKey.DIALOG_YES_DELETE -> R.string.dialog_yes_delete
StringKey.TOAST_CLEARED -> R.string.toast_cleared
StringKey.TOAST_ENTITIES_SAVED -> R.string.toast_entities_saved
}
)
}

View File

@@ -1,52 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">RetroHA</string>
<string name="app_title">HA_PANEL</string>
<string name="state_on">ON</string>
<string name="state_off">OFF</string>
<string name="state_unavailable">UNAVAILABLE</string>
<string name="state_toggling"></string>
<string name="btn_settings">SETTINGS</string>
<string name="toast_widget_add">Add widget — TODO</string>
<string name="tab_all">ALL</string>
<string name="tab_lighting">LIGHTING</string>
<string name="tab_sockets">SOCKETS</string>
<string name="tab_power">POWER</string>
<string name="tab_weather">WEATHER</string>
<string name="title_settings">ENTITY SELECTION</string>
<string name="title_connection">SERVER CONFIGURATION</string>
<string name="title_instructions">USER MANUAL</string>
<string name="instruction_1">1. CLICK TILE TO TOGGLE (ON/OFF).</string>
<string name="instruction_2">2. LONG PRESS LIGHT TILE TO OPEN BRIGHTNESS MENU.</string>
<string name="instruction_3">3. USE TABS AT TOP TO FILTER DEVICES.</string>
<string name="instruction_4">4. CLICK \'HA_PANEL\' TITLE TO FORCE REFRESH.</string>
<string name="instruction_5">5. CONNECTION CHANGE CLEARS WIDGET LIST.</string>
<string name="label_url">URL ADDRESS</string>
<string name="label_token">ACCESS TOKEN</string>
<string name="label_refresh">REFRESH (SECONDS)</string>
<string name="btn_test_save">TEST AND SAVE</string>
<string name="btn_delete_all">DELETE ALL WIDGETS</string>
<string name="btn_save_selected">SAVE SELECTED</string>
<string name="btn_change_lang">JĘZYK / LANGUAGE</string>
<string name="btn_change_lang">LANGUAGE / JĘZYK</string>
<string name="btn_entity_selection">WIDGET SELECTION</string>
<string name="btn_instructions">USER MANUAL</string>
<string name="status_connecting">CONNECTING...</string>
<string name="status_connected">CONNECTED SUCCESSFULLY</string>
<string name="status_connected">ONLINE</string>
<string name="status_offline">OFFLINE</string>
<string name="status_error_ha">HA ERROR</string>
<string name="status_no_token">NO TOKEN</string>
<string name="title_select_language">SELECT LANGUAGE\nWYBIERZ JĘZYK</string>
<string name="status_refreshing">Refreshing...</string>
<string name="status_success">CONNECTED SUCCESSFULLY</string>
<string name="toast_saved_cleared">Saved and cleared widgets</string>
<string name="status_error">ERROR</string>
<string name="status_error_network">NETWORK ERROR</string>
<string name="confirm_delete_all">ARE YOU SURE YOU WANT TO DELETE ALL WIDGETS FROM HOME?</string>
<string name="confirm_change_conn">CHANGING ADDRESS OR TOKEN WILL DELETE ALL SELECTED WIDGETS. CONTINUE?</string>
<string name="dialog_brightness">BRIGHTNESS</string>
<string name="dialog_set">SET</string>
<string name="dialog_cancel">CANCEL</string>
@@ -54,7 +49,7 @@
<string name="dialog_yes_change">YES, CHANGE</string>
<string name="dialog_yes_delete">YES, DELETE</string>
<string name="toast_cleared">Dashboard cleared</string>
<string name="toast_entities_saved">Selected entities saved</string>
<string name="inst_header_1">BASIC USAGE</string>
<string name="inst_body_1">- Short click on a tile toggles the device (ON/OFF).\n- Long press on a light tile opens a dedicated brightness slider.\n- Use the tabs at the top (e.g., Lighting, Power) to quickly filter displayed devices.</string>
<string name="inst_header_2">SORTING &amp; VISIBILITY</string>

View File

@@ -1,52 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">RetroHA</string>
<string name="app_title">HA_PANEL</string>
<string name="state_on">WŁ.</string>
<string name="state_off">WYŁ.</string>
<string name="state_unavailable">NIEOSIĄGALNE</string>
<string name="state_toggling"></string>
<string name="btn_settings">USTAWIENIA</string>
<string name="toast_widget_add">Dodaj widget — TODO</string>
<string name="tab_all">WSZYSTKO</string>
<string name="tab_lighting">OŚWIETLENIE</string>
<string name="tab_sockets">GNIAZDKA</string>
<string name="tab_power">MOC</string>
<string name="tab_weather">POGODA</string>
<string name="title_settings">WYBÓR ENCJI</string>
<string name="title_connection">KONFIGURACJA SERWERA</string>
<string name="title_instructions">INSTRUKCJA OBSŁUGI</string>
<string name="instruction_1">1. KLIKNIJ KAFELEK, ABY PRZEŁĄCZYĆ (ON/OFF).</string>
<string name="instruction_2">2. PRZYTRZYMAJ KAFELEK ŚWIATŁA, ABY OTWORZYĆ MENU JASNOŚCI.</string>
<string name="instruction_3">3. UŻYWAJ ZAKŁADEK NA GÓRZE DO FILTROWANIA URZĄDZEŃ.</string>
<string name="instruction_4">4. KLIKNIJ TYTUŁ \'HA_PANEL\', ABY WYMUSIĆ ODŚWIEŻENIE.</string>
<string name="instruction_5">5. ZMIANA POŁĄCZENIA CZYŚCI LISTĘ WIDŻETÓW.</string>
<string name="label_url">ADRES URL</string>
<string name="label_token">TOKEN DOSTĘPU</string>
<string name="label_refresh">ODŚWIEŻANIE (SEKUNDY)</string>
<string name="btn_test_save">TESTUJ I ZAPISZ</string>
<string name="btn_delete_all">USUŃ WSZYSTKIE WIDŻETY</string>
<string name="btn_save_selected">ZAPISZ WYBRANE</string>
<string name="btn_change_lang">JĘZYK / LANGUAGE</string>
<string name="btn_entity_selection">WYBÓR WIDŻETÓW</string>
<string name="btn_instructions">INSTRUKCJA OBSŁUGI</string>
<string name="status_connecting">ŁĄCZENIE...</string>
<string name="status_connected">POŁĄCZONO POMYŚLNIE</string>
<string name="status_connected">ONLINE</string>
<string name="status_offline">OFFLINE</string>
<string name="status_error_ha">BŁĄD HA</string>
<string name="status_no_token">BRAK TOKENU</string>
<string name="title_select_language">WYBIERZ JĘZYK\nSELECT LANGUAGE</string>
<string name="status_refreshing">Odświeżanie...</string>
<string name="status_success">POŁĄCZONO POMYŚLNIE</string>
<string name="toast_saved_cleared">Zapisano i wyczyszczono widżety</string>
<string name="status_error">BŁĄD</string>
<string name="status_error_network">BŁĄD SIECI</string>
<string name="confirm_delete_all">CZY NA PEWNO CHCESZ USUNĄĆ WSZYSTKIE WIDŻETY Z PULPITU?</string>
<string name="confirm_change_conn">ZMIANA ADRESU LUB TOKENU SPOWODUJE USUNIĘCIE WSZYSTKICH WYBRANYCH WIDŻETÓW. KONTYNUOWAĆ?</string>
<string name="dialog_brightness">JASNOŚĆ</string>
<string name="dialog_set">USTAW</string>
<string name="dialog_cancel">ANULUJ</string>
@@ -54,7 +49,7 @@
<string name="dialog_yes_change">TAK, ZMIEŃ</string>
<string name="dialog_yes_delete">TAK, USUŃ</string>
<string name="toast_cleared">Wyczyszczono pulpit</string>
<string name="toast_entities_saved">Wybrane encje zapisane</string>
<string name="inst_header_1">PODSTAWY OBSŁUGI</string>
<string name="inst_body_1">- Krótkie kliknięcie kafelka przełącza urządzenie (ON/OFF).\n- Długie przytrzymanie kafelka światła otwiera dedykowany suwak jasności.\n- Zakładki na górze ekranu (np. Oświetlenie, Moc) służą do szybkiego filtrowania wyświetlanych urządzeń.</string>
<string name="inst_header_2">SORTOWANIE I WIDOCZNOŚĆ</string>