diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 1030461..dc15ba0 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 = 4 - versionName = "0.3.1" + versionCode = 5 + versionName = "0.3.2" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } 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 108c1e5..8f78e92 100644 --- a/app/src/main/java/kr/tkrmagid/easyappliance/ui/AdminScreen.kt +++ b/app/src/main/java/kr/tkrmagid/easyappliance/ui/AdminScreen.kt @@ -18,10 +18,13 @@ import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.selection.selectable import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Refresh import androidx.compose.material3.Button import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedTextField @@ -58,6 +61,7 @@ import kr.tkrmagid.easyappliance.vm.macroFor fun AdminScreen( state: HomeUiState, onSelectDevice: (String) -> Unit, + onRefreshDevices: () -> Unit, onSetAppName: (String) -> Unit, onToggleRemaining: (Boolean) -> Unit, onToggleReservation: (Boolean) -> Unit, @@ -111,6 +115,15 @@ fun AdminScreen( } } + Spacer(Modifier.height(12.dp)) + OutlinedButton( + onClick = onRefreshDevices, + modifier = Modifier.fillMaxWidth().height(60.dp), + ) { + Icon(Icons.Filled.Refresh, contentDescription = null, modifier = Modifier.size(26.dp)) + Text(" 목록 새로고침", style = MaterialTheme.typography.bodyLarge) + } + if (selected != null) { Spacer(Modifier.height(28.dp)) SectionTitle("기기 이름 바꾸기") 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 e6bd150..5302ef7 100644 --- a/app/src/main/java/kr/tkrmagid/easyappliance/ui/AppRoot.kt +++ b/app/src/main/java/kr/tkrmagid/easyappliance/ui/AppRoot.kt @@ -1,5 +1,9 @@ package kr.tkrmagid.easyappliance.ui +import android.app.ActivityManager +import android.content.Context +import android.content.ContextWrapper +import androidx.activity.ComponentActivity import androidx.activity.compose.BackHandler import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize @@ -12,17 +16,25 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import androidx.lifecycle.Lifecycle import androidx.lifecycle.compose.LifecycleEventEffect import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewmodel.compose.viewModel import kr.tkrmagid.easyappliance.data.koreanLabel import kr.tkrmagid.easyappliance.vm.AppViewModel +import kr.tkrmagid.easyappliance.vm.appDisplayName import kr.tkrmagid.easyappliance.vm.displayLabelFor import kotlinx.coroutines.delay private enum class Screen { HOME, ADMIN } +private tailrec fun Context.findActivity(): ComponentActivity? = when (this) { + is ComponentActivity -> this + is ContextWrapper -> baseContext.findActivity() + else -> null +} + private const val POLL_OK_MS = 15_000L private const val POLL_OFFLINE_MS = 5_000L @@ -32,6 +44,16 @@ fun AppRoot() { val state by vm.state.collectAsStateWithLifecycle() var screen by rememberSaveable { mutableStateOf(Screen.HOME) } + // Reflect the custom app name in the OS: the label shown in the Recents/task + // switcher updates at runtime (the launcher icon label stays fixed by Android). + val context = LocalContext.current + val appName = state.appDisplayName() + LaunchedEffect(appName) { + context.findActivity()?.setTaskDescription( + ActivityManager.TaskDescription(appName), + ) + } + // Refresh when returning to the foreground... LifecycleEventEffect(Lifecycle.Event.ON_RESUME) { vm.refresh() } // ...and poll while composed; retry faster while disconnected so the warning @@ -55,7 +77,6 @@ fun AppRoot() { state = state, onTogglePower = vm::togglePower, onRunMacro = vm::runMacro, - onRefresh = vm::refresh, modifier = Modifier .fillMaxSize() .adminUnlockGesture { screen = Screen.ADMIN }, @@ -63,6 +84,7 @@ fun AppRoot() { Screen.ADMIN -> AdminScreen( state = state, onSelectDevice = vm::selectDevice, + onRefreshDevices = vm::refreshDevices, onSetAppName = vm::setAppName, onToggleRemaining = vm::setShowRemainingTime, onToggleReservation = vm::setShowReservation, 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 09a652d..5615816 100644 --- a/app/src/main/java/kr/tkrmagid/easyappliance/ui/HomeScreen.kt +++ b/app/src/main/java/kr/tkrmagid/easyappliance/ui/HomeScreen.kt @@ -15,7 +15,6 @@ import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.PowerSettingsNew -import androidx.compose.material.icons.filled.Refresh import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.Card @@ -23,7 +22,6 @@ import androidx.compose.material3.CardDefaults import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.OutlinedButton import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment @@ -46,7 +44,6 @@ fun HomeScreen( state: HomeUiState, onTogglePower: (Boolean) -> Unit, onRunMacro: () -> Unit, - onRefresh: () -> Unit, modifier: Modifier = Modifier, ) { BoxWithConstraints(modifier = modifier.fillMaxSize()) { @@ -110,15 +107,6 @@ fun HomeScreen( ) } } - - Spacer(Modifier.height(20.dp)) - OutlinedButton( - onClick = onRefresh, - modifier = Modifier.fillMaxWidth().height(BigButtonHeight), - ) { - Icon(Icons.Filled.Refresh, contentDescription = null, modifier = Modifier.size(30.dp)) - Text(" 새로고침", style = MaterialTheme.typography.labelLarge) - } } } } 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 b51932d..629ee09 100644 --- a/app/src/main/java/kr/tkrmagid/easyappliance/vm/AppViewModel.kt +++ b/app/src/main/java/kr/tkrmagid/easyappliance/vm/AppViewModel.kt @@ -123,6 +123,14 @@ class AppViewModel(app: Application) : AndroidViewModel(app) { viewModelScope.launch { loadStatus(id) } } + /** Reload the device list from the repository (admin "목록 새로고침"). */ + fun refreshDevices() { + viewModelScope.launch { + loadDevices() + resolveSelectionAndStatus(_state.value.settings) + } + } + /** "다시 연결하기" — clear preview flag and re-attempt list + status. */ fun retryConnection() { forcedWarning = false