From 2287e1cf839a460dd34ee55490ae1a7753f6e59f Mon Sep 17 00:00:00 2001 From: tkrmagid Date: Wed, 5 Aug 2026 14:45:57 +0900 Subject: [PATCH] feat: app-level display name (v0.3.1) --- .gitignore | 1 - app/build.gradle.kts | 4 ++-- .../tkrmagid/easyappliance/data/SettingsRepository.kt | 7 +++++++ .../java/kr/tkrmagid/easyappliance/ui/AdminScreen.kt | 11 ++++++++++- .../main/java/kr/tkrmagid/easyappliance/ui/AppRoot.kt | 1 + .../java/kr/tkrmagid/easyappliance/ui/HomeScreen.kt | 8 ++++++++ .../java/kr/tkrmagid/easyappliance/vm/AppViewModel.kt | 6 ++++++ 7 files changed, 34 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 7ff173e..d67448f 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,3 @@ .cxx app/build/ build/ -.kotlin/ diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 62c6845..1030461 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -24,8 +24,8 @@ android { applicationId = "kr.tkrmagid.easyappliance" minSdk = 24 targetSdk = 35 - versionCode = 3 - versionName = "0.3.0" + versionCode = 4 + versionName = "0.3.1" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } diff --git a/app/src/main/java/kr/tkrmagid/easyappliance/data/SettingsRepository.kt b/app/src/main/java/kr/tkrmagid/easyappliance/data/SettingsRepository.kt index e8a2761..8c239e3 100644 --- a/app/src/main/java/kr/tkrmagid/easyappliance/data/SettingsRepository.kt +++ b/app/src/main/java/kr/tkrmagid/easyappliance/data/SettingsRepository.kt @@ -17,6 +17,8 @@ private val Context.dataStore: DataStore by preferencesDataStore(na /** User/admin choices that must survive app restarts. */ data class AppSettings( + /** App-level display name shown as the home header; null = default. */ + val appName: String? = null, val selectedDeviceId: String? = null, val showRemainingTime: Boolean = true, val showReservation: Boolean = true, @@ -36,6 +38,7 @@ class SettingsRepository(private val context: Context) { val settings: Flow = context.dataStore.data.map { p -> AppSettings( + appName = p[KEY_APP_NAME]?.takeIf { it.isNotBlank() }, selectedDeviceId = p[KEY_SELECTED_DEVICE], showRemainingTime = p[KEY_SHOW_REMAINING] ?: true, showReservation = p[KEY_SHOW_RESERVATION] ?: true, @@ -47,6 +50,9 @@ class SettingsRepository(private val context: Context) { ) } + suspend fun setAppName(name: String) = + edit { it[KEY_APP_NAME] = name.trim() } + suspend fun setSelectedDevice(deviceId: String) = edit { it[KEY_SELECTED_DEVICE] = deviceId } @@ -93,6 +99,7 @@ class SettingsRepository(private val context: Context) { else runCatching { Json.decodeFromString>(raw) }.getOrDefault(emptyMap()) private companion object { + val KEY_APP_NAME = stringPreferencesKey("app_name") val KEY_SELECTED_DEVICE = stringPreferencesKey("selected_device_id") val KEY_SHOW_REMAINING = booleanPreferencesKey("show_remaining_time") val KEY_SHOW_RESERVATION = booleanPreferencesKey("show_reservation") diff --git a/app/src/main/java/kr/tkrmagid/easyappliance/ui/AdminScreen.kt b/app/src/main/java/kr/tkrmagid/easyappliance/ui/AdminScreen.kt index 28357bd..108c1e5 100644 --- a/app/src/main/java/kr/tkrmagid/easyappliance/ui/AdminScreen.kt +++ b/app/src/main/java/kr/tkrmagid/easyappliance/ui/AdminScreen.kt @@ -49,6 +49,7 @@ import kr.tkrmagid.easyappliance.data.DeviceImages import kr.tkrmagid.easyappliance.data.DeviceMacro import kr.tkrmagid.easyappliance.data.ImageStorage import kr.tkrmagid.easyappliance.vm.HomeUiState +import kr.tkrmagid.easyappliance.vm.appDisplayName import kr.tkrmagid.easyappliance.vm.displayLabelFor import kr.tkrmagid.easyappliance.vm.imageRefFor import kr.tkrmagid.easyappliance.vm.macroFor @@ -57,6 +58,7 @@ import kr.tkrmagid.easyappliance.vm.macroFor fun AdminScreen( state: HomeUiState, onSelectDevice: (String) -> Unit, + onSetAppName: (String) -> Unit, onToggleRemaining: (Boolean) -> Unit, onToggleReservation: (Boolean) -> Unit, onTogglePowerControls: (Boolean) -> Unit, @@ -78,6 +80,13 @@ fun AdminScreen( Text("관리자 설정", style = MaterialTheme.typography.headlineLarge) Spacer(Modifier.height(24.dp)) + SectionTitle("앱 이름 바꾸기") + NameEditor( + current = state.appDisplayName(), + onSave = onSetAppName, + ) + + Spacer(Modifier.height(28.dp)) SectionTitle("조작할 기기 선택") Card( modifier = Modifier.fillMaxWidth(), @@ -104,7 +113,7 @@ fun AdminScreen( if (selected != null) { Spacer(Modifier.height(28.dp)) - SectionTitle("이름 바꾸기") + SectionTitle("기기 이름 바꾸기") NameEditor( current = state.displayLabelFor(selected), onSave = { onSetLabel(selected.id, it) }, diff --git a/app/src/main/java/kr/tkrmagid/easyappliance/ui/AppRoot.kt b/app/src/main/java/kr/tkrmagid/easyappliance/ui/AppRoot.kt index 75348c7..e6bd150 100644 --- a/app/src/main/java/kr/tkrmagid/easyappliance/ui/AppRoot.kt +++ b/app/src/main/java/kr/tkrmagid/easyappliance/ui/AppRoot.kt @@ -63,6 +63,7 @@ fun AppRoot() { Screen.ADMIN -> AdminScreen( state = state, onSelectDevice = vm::selectDevice, + onSetAppName = vm::setAppName, onToggleRemaining = vm::setShowRemainingTime, onToggleReservation = vm::setShowReservation, onTogglePowerControls = vm::setShowPowerControls, diff --git a/app/src/main/java/kr/tkrmagid/easyappliance/ui/HomeScreen.kt b/app/src/main/java/kr/tkrmagid/easyappliance/ui/HomeScreen.kt index 99ea525..09a652d 100644 --- a/app/src/main/java/kr/tkrmagid/easyappliance/ui/HomeScreen.kt +++ b/app/src/main/java/kr/tkrmagid/easyappliance/ui/HomeScreen.kt @@ -34,6 +34,7 @@ import androidx.compose.ui.unit.dp import kr.tkrmagid.easyappliance.data.DeviceType import androidx.compose.material.icons.filled.PlayArrow import kr.tkrmagid.easyappliance.vm.HomeUiState +import kr.tkrmagid.easyappliance.vm.appDisplayName import kr.tkrmagid.easyappliance.vm.displayLabelFor import kr.tkrmagid.easyappliance.vm.imageRefFor import kr.tkrmagid.easyappliance.vm.macroFor @@ -71,6 +72,13 @@ fun HomeScreen( modifier = Modifier.widthIn(max = contentMaxWidth).fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally, ) { + Text( + text = state.appDisplayName(), + style = MaterialTheme.typography.titleLarge, + color = MaterialTheme.colorScheme.primary, + textAlign = TextAlign.Center, + ) + Spacer(Modifier.height(16.dp)) DeviceImage( imageRef = state.imageRefFor(device), modifier = Modifier.size(if (narrow) 96.dp else 128.dp), diff --git a/app/src/main/java/kr/tkrmagid/easyappliance/vm/AppViewModel.kt b/app/src/main/java/kr/tkrmagid/easyappliance/vm/AppViewModel.kt index 769c5c8..b51932d 100644 --- a/app/src/main/java/kr/tkrmagid/easyappliance/vm/AppViewModel.kt +++ b/app/src/main/java/kr/tkrmagid/easyappliance/vm/AppViewModel.kt @@ -170,6 +170,7 @@ class AppViewModel(app: Application) : AndroidViewModel(app) { viewModelScope.launch { settingsRepo.setDeviceMacro(deviceId, macro) } } + fun setAppName(name: String) { viewModelScope.launch { settingsRepo.setAppName(name) } } fun setShowRemainingTime(value: Boolean) { viewModelScope.launch { settingsRepo.setShowRemainingTime(value) } } fun setShowReservation(value: Boolean) { viewModelScope.launch { settingsRepo.setShowReservation(value) } } fun setShowPowerControls(value: Boolean) { viewModelScope.launch { settingsRepo.setShowPowerControls(value) } } @@ -188,3 +189,8 @@ fun HomeUiState.imageRefFor(device: Device): String = /** The device's macro, or null if none configured. */ fun HomeUiState.macroFor(device: Device): DeviceMacro? = settings.deviceMacros[device.id] + +const val DEFAULT_APP_NAME = "쉬운 가전 리모컨" + +/** App-level display name shown as the home header. */ +fun HomeUiState.appDisplayName(): String = settings.appName ?: DEFAULT_APP_NAME