From 6687341c5141a99a56b2efed0ec8645cfd3f18fc Mon Sep 17 00:00:00 2001 From: kaorikizuna <34364395+Agung-Krisna@users.noreply.github.com> Date: Wed, 10 Jul 2024 00:39:23 +0800 Subject: [PATCH] feat: done all major functionality except search --- .../my/kaorikizuna/incu8tor/MainActivity.kt | 64 ++++++++++--------- .../incu8tor/ui/addevice/AddDevice.kt | 7 +- .../DeviceConfigurationScreen.kt | 14 ++-- .../ui/deviceDetail/DeviceDetailScreen.kt | 48 +++++++------- .../incu8tor/ui/home/HomeScreen.kt | 26 +++++--- 5 files changed, 88 insertions(+), 71 deletions(-) diff --git a/app/src/main/java/id/my/kaorikizuna/incu8tor/MainActivity.kt b/app/src/main/java/id/my/kaorikizuna/incu8tor/MainActivity.kt index ca9cdb9..0400361 100644 --- a/app/src/main/java/id/my/kaorikizuna/incu8tor/MainActivity.kt +++ b/app/src/main/java/id/my/kaorikizuna/incu8tor/MainActivity.kt @@ -11,16 +11,19 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.platform.LocalContext +import androidx.navigation.NavController import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import id.my.kaorikizuna.incu8tor.model.DeviceDetail import id.my.kaorikizuna.incu8tor.ui.addevice.AddDeviceScreen import id.my.kaorikizuna.incu8tor.ui.deviceConfiguration.DeviceConfigurationScreen +import id.my.kaorikizuna.incu8tor.ui.deviceDetail.DeviceDetailScreen import id.my.kaorikizuna.incu8tor.ui.home.HomeScreen import id.my.kaorikizuna.incu8tor.ui.theme.Incu8torTheme import id.my.kaorikizuna.incu8tor.viewmodel.DeviceViewModel +// TODO add the search functionality on home screen class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -28,36 +31,21 @@ class MainActivity : ComponentActivity() { setContent { Incu8torTheme { val viewModel = DeviceViewModel() - val deviceDetail = viewModel.getDevice("24:DC:C3:45:EA:CC") -// Log.d(TAG, "device: ${deviceDetail.toString()}") -// DeviceConfigurationScreenPreview() -// HomeScreen() + val navController = rememberNavController() - // testing purposes -// val (deviceDetail, setDeviceDetail) = remember { mutableStateOf(DeviceDetail()) } -// LaunchedEffect(Unit) { -// viewModel.getDevice("24:DC:C3:45:EA:CC", onSuccess = { -// setDeviceDetail(it) -// }) -// } -// if (deviceDetail != DeviceDetail()) { -// DeviceConfigurationScreen( -// deviceDetail = deviceDetail, -// onUpdate = { deviceDetail -> viewModel.updateDevice(deviceDetail) }, -// onDelete = { deviceDetail -> viewModel.deleteDevice(deviceDetail) },) -// } - -// AddDeviceScreen(onSave = { deviceDetail -> -// viewModel.addDevice(deviceDetail) -// }) NavHost(navController = navController, startDestination = "home") { composable(route = "home") { - HomeScreen(navController) + HomeScreen( + onDeviceClicked = { deviceDetail -> navController.navigate("deviceDetail/${deviceDetail.macAddress}") }, + navController = navController + ) } composable(route = "addDevice") { - AddDeviceScreen(navController = navController, onSave = { deviceDetail -> - viewModel.addDevice(deviceDetail) - }) + AddDeviceScreen( + onBackClicked = { navController.navigate("home") }, + onSave = { deviceDetail -> + viewModel.addDevice(deviceDetail) + }) } composable(route = "deviceConfiguration/{macAddress}") { backStackEntry -> val macAddress = backStackEntry.arguments?.getString("macAddress") @@ -70,16 +58,17 @@ class MainActivity : ComponentActivity() { } } if (deviceDetail != DeviceDetail()) { - DeviceConfigurationScreen( - navController = navController, - deviceDetail = deviceDetail, + DeviceConfigurationScreen(deviceDetail = deviceDetail, onUpdate = { deviceDetail -> viewModel.updateDevice(deviceDetail) }, onDelete = { deviceDetail -> viewModel.deleteDevice(deviceDetail) - } - ) + navController.navigate("home") + }, + onBackClicked = { + navController.navigate("deviceDetail/${deviceDetail.macAddress}") + }) } } composable(route = "deviceDetail/{macAddress}") { backStackEntry -> @@ -92,6 +81,21 @@ class MainActivity : ComponentActivity() { }) } } + if (deviceDetail != DeviceDetail()) { + DeviceDetailScreen(deviceDetail = deviceDetail, + onBackClicked = { navController.navigate("home") }, + onSettingsClicked = { navController.navigate("deviceConfiguration/${deviceDetail.macAddress}") }, + onIncubationClicked = { deviceDetail -> + // if incubation has already begun, end incubation + if (deviceDetail.dayStart > 0) { + viewModel.updateDevice(deviceDetail.copy(dayStart = 0)) + // else, start the incubation + } else { + viewModel.updateDevice(deviceDetail.copy(dayStart = System.currentTimeMillis() / 1000)) + } + navController.navigate("home") + }) + } } } diff --git a/app/src/main/java/id/my/kaorikizuna/incu8tor/ui/addevice/AddDevice.kt b/app/src/main/java/id/my/kaorikizuna/incu8tor/ui/addevice/AddDevice.kt index 5227c75..9b18f3c 100644 --- a/app/src/main/java/id/my/kaorikizuna/incu8tor/ui/addevice/AddDevice.kt +++ b/app/src/main/java/id/my/kaorikizuna/incu8tor/ui/addevice/AddDevice.kt @@ -82,7 +82,7 @@ import id.my.kaorikizuna.incu8tor.ui.theme.Red @OptIn(ExperimentalMaterial3Api::class) @Composable -fun AddDeviceScreen(navController: NavController, onSave: (DeviceDetail) -> Unit) { +fun AddDeviceScreen(onSave: (DeviceDetail) -> Unit, onBackClicked: () -> Unit) { val (deviceDetail, setDeviceDetail) = remember { mutableStateOf(DeviceDetail()) } Scaffold( @@ -90,7 +90,7 @@ fun AddDeviceScreen(navController: NavController, onSave: (DeviceDetail) -> Unit Incu8torModifiableTopBar( deviceTitle = "Incu8tor", actionButton = {}, - backNavigation = { navController.navigate("home") }) + backNavigation = { onBackClicked() }) } ) { paddingValues -> Column( @@ -214,9 +214,10 @@ fun AddDeviceScreen(navController: NavController, onSave: (DeviceDetail) -> Unit verticalArrangement = Arrangement.Bottom, horizontalAlignment = Alignment.CenterHorizontally ) { - ElevatedButton(onClick = { + Button(onClick = { Log.w("asdfasdf", "$deviceDetail") onSave(deviceDetail) + onBackClicked() }) { Text(text = "Save") } diff --git a/app/src/main/java/id/my/kaorikizuna/incu8tor/ui/deviceConfiguration/DeviceConfigurationScreen.kt b/app/src/main/java/id/my/kaorikizuna/incu8tor/ui/deviceConfiguration/DeviceConfigurationScreen.kt index beba77c..1d52222 100644 --- a/app/src/main/java/id/my/kaorikizuna/incu8tor/ui/deviceConfiguration/DeviceConfigurationScreen.kt +++ b/app/src/main/java/id/my/kaorikizuna/incu8tor/ui/deviceConfiguration/DeviceConfigurationScreen.kt @@ -60,10 +60,10 @@ import id.my.kaorikizuna.incu8tor.viewmodel.DeviceViewModel @Composable fun DeviceConfigurationScreen( - navController: NavController, deviceDetail: DeviceDetail, onUpdate: (DeviceDetail) -> Unit, - onDelete: (DeviceDetail) -> Unit + onDelete: (DeviceDetail) -> Unit, + onBackClicked: () -> Unit ) { val (currentDeviceDetail, setCurrentDeviceDetail) = remember { mutableStateOf(deviceDetail) } var showDialog by remember { mutableStateOf(false) } @@ -79,8 +79,8 @@ fun DeviceConfigurationScreen( DeleteDialog( onDismiss = { showDialog = false }, onConfirm = { - onDelete(deviceDetail) showDialog = false + onDelete(deviceDetail) }) } @@ -95,7 +95,8 @@ fun DeviceConfigurationScreen( ) } }, - backNavigation = { navController.navigate("home") }) + backNavigation = onBackClicked + ) }) { paddingValues -> Column( @@ -200,7 +201,10 @@ fun DeviceConfigurationScreen( verticalArrangement = Arrangement.Bottom, horizontalAlignment = Alignment.CenterHorizontally ) { - ElevatedButton(onClick = { onUpdate(currentDeviceDetail) }) { + Button(onClick = { + onUpdate(currentDeviceDetail) + onBackClicked() + }) { Text( text = "Update", style = MaterialTheme.typography.bodyLarge, diff --git a/app/src/main/java/id/my/kaorikizuna/incu8tor/ui/deviceDetail/DeviceDetailScreen.kt b/app/src/main/java/id/my/kaorikizuna/incu8tor/ui/deviceDetail/DeviceDetailScreen.kt index 9d79d90..24586bd 100644 --- a/app/src/main/java/id/my/kaorikizuna/incu8tor/ui/deviceDetail/DeviceDetailScreen.kt +++ b/app/src/main/java/id/my/kaorikizuna/incu8tor/ui/deviceDetail/DeviceDetailScreen.kt @@ -22,6 +22,7 @@ import id.my.kaorikizuna.incu8tor.viewmodel.DeviceViewModel import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowBack import androidx.compose.ui.graphics.ColorFilter +import androidx.navigation.NavController import java.text.SimpleDateFormat import java.time.LocalDate import java.time.temporal.ChronoUnit @@ -31,11 +32,21 @@ import androidx.compose.material3.OutlinedCard as OutlinedCard @OptIn(ExperimentalMaterial3Api::class) @Composable -fun DeviceDetailScreen(deviceDetail: DeviceDetail, onBackClicked: () -> Unit, onSettingsClicked: () -> Unit) { +fun DeviceDetailScreen( + deviceDetail: DeviceDetail, + onBackClicked: () -> Unit, + onSettingsClicked: () -> Unit, + onIncubationClicked: (DeviceDetail) -> Unit +) { Scaffold( topBar = { TopAppBar( - title = { Text(text = deviceDetail.deviceName, style = MaterialTheme.typography.titleSmall) }, + title = { + Text( + text = deviceDetail.deviceName, + style = MaterialTheme.typography.titleSmall + ) + }, navigationIcon = { IconButton(onClick = { onBackClicked() }) { Icon( @@ -161,10 +172,10 @@ fun DeviceDetailScreen(deviceDetail: DeviceDetail, onBackClicked: () -> Unit, on Spacer(modifier = Modifier.weight(1f)) Button( - onClick = { /* TODO: Implement action */ }, + onClick = { onIncubationClicked(deviceDetail) }, modifier = Modifier.align(Alignment.CenterHorizontally) ) { - Text(text = "End Incubation") + if (deviceDetail.dayStart == 0L) Text("Start Incubation") else Text("End Incubation") } } } @@ -172,30 +183,21 @@ fun DeviceDetailScreen(deviceDetail: DeviceDetail, onBackClicked: () -> Unit, on } fun calculateDaysBetween(startDateEpoch: Long): Long { + if (startDateEpoch == 0L) { + return 0 + } val currentDate = LocalDate.now() val startDate = LocalDate.ofEpochDay(startDateEpoch / (24 * 60 * 60)) return ChronoUnit.DAYS.between(startDate, currentDate) } fun getDateFromEpoch(epochTime: Long): String { - return SimpleDateFormat("dd MMMM yyyy, HH:mm", Locale.getDefault()).format(Date(epochTime * 1000)) -} - -@Preview(showBackground = true) -@Composable -fun DeviceDetailScreenPreview() { - val viewModel = DeviceViewModel() - val (deviceDetail, setDeviceDetail) = remember { mutableStateOf(DeviceDetail()) } - LaunchedEffect(Unit) { - viewModel.getDevice("24:DC:C3:45:EA:CC", onSuccess = { - setDeviceDetail(it) - }) - } - Incu8torTheme { - DeviceDetailScreen( - deviceDetail = deviceDetail, - onBackClicked = { /* Preview action */ }, - onSettingsClicked = { /* Preview action */ } - ) + if (epochTime == 0L) { + return "Not Yet Started" } + return SimpleDateFormat( + "dd MMMM yyyy, HH:mm", + Locale.getDefault() + ).format(Date(epochTime * 1000)) + } \ No newline at end of file diff --git a/app/src/main/java/id/my/kaorikizuna/incu8tor/ui/home/HomeScreen.kt b/app/src/main/java/id/my/kaorikizuna/incu8tor/ui/home/HomeScreen.kt index c1d27d8..65deb12 100644 --- a/app/src/main/java/id/my/kaorikizuna/incu8tor/ui/home/HomeScreen.kt +++ b/app/src/main/java/id/my/kaorikizuna/incu8tor/ui/home/HomeScreen.kt @@ -23,10 +23,13 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp import androidx.navigation.NavController +import id.my.kaorikizuna.incu8tor.R import id.my.kaorikizuna.incu8tor.model.Device import id.my.kaorikizuna.incu8tor.model.DeviceDetail import id.my.kaorikizuna.incu8tor.ui.components.Incu8torSearchBar @@ -45,7 +48,7 @@ val devices = listOf( ) @Composable -fun HomeScreen(navController: NavController) { +fun HomeScreen(navController: NavController, onDeviceClicked: (DeviceDetail) -> Unit) { val viewModel = DeviceViewModel() // turns out that the second positional argument of remember is the setter function, @@ -89,7 +92,8 @@ fun HomeScreen(navController: NavController) { items(devices) { device -> DeviceCard( device, - onClick = { navController.navigate("deviceConfiguration/${device.macAddress}") }) + onClick = { onDeviceClicked(device) } + ) } } } @@ -117,15 +121,17 @@ fun DeviceCard(deviceDetail: DeviceDetail, onClick: () -> Unit) { style = MaterialTheme.typography.bodySmall ) } -// TODO fix to tell if the device is connected or not // the icon needs to be within a container (box or row) to be able to be centered vertically -// Row(modifier = Modifier.align(Alignment.CenterVertically)) { -// Icon( -// painter = if (deviceDetail.isConnected) painterResource(id = R.drawable.wifi) -// else painterResource(id = R.drawable.wifi_off), -// contentDescription = "Device Connected", -// ) -// } + // device is online if it can report temperature and humidity + Row(modifier = Modifier.align(Alignment.CenterVertically)) { + Icon( + painter = if (deviceDetail.sensors.humidity > 0 && deviceDetail.sensors.temperature > 0) painterResource( + id = R.drawable.wifi + ) + else painterResource(id = R.drawable.wifi_off), + contentDescription = "Device Connected", + ) + } } } }