From 1ccd9f600ffa1f2e3fac48d4cd60086b0d460980 Mon Sep 17 00:00:00 2001 From: Puvikaran Santhirasegaram <74664443+Puvikaran2001@users.noreply.github.com> Date: Wed, 22 May 2024 22:35:02 +0200 Subject: [PATCH 1/4] Refactor refreshable --- .../gui/components/Refreshable.kt | 34 +++++++++++++++++++ .../schedulingfrontend/gui/pages/HomePage.kt | 33 +++++++----------- .../gui/pages/TaskOverviewPage.kt | 31 +++++++---------- 3 files changed, 58 insertions(+), 40 deletions(-) create mode 100644 frontend/app/src/main/java/dk/scheduling/schedulingfrontend/gui/components/Refreshable.kt diff --git a/frontend/app/src/main/java/dk/scheduling/schedulingfrontend/gui/components/Refreshable.kt b/frontend/app/src/main/java/dk/scheduling/schedulingfrontend/gui/components/Refreshable.kt new file mode 100644 index 00000000..7c833bf0 --- /dev/null +++ b/frontend/app/src/main/java/dk/scheduling/schedulingfrontend/gui/components/Refreshable.kt @@ -0,0 +1,34 @@ +package dk.scheduling.schedulingfrontend.gui.components + +import androidx.compose.foundation.layout.Box +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.pulltorefresh.PullToRefreshContainer +import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.input.nestedscroll.nestedScroll + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun Refreshable( + onRefresh: suspend () -> Unit, + content: @Composable () -> Unit, +) { + val refreshState = rememberPullToRefreshState() + if (refreshState.isRefreshing) { + LaunchedEffect(true) { + onRefresh() + refreshState.endRefresh() + } + } + Box(Modifier.nestedScroll(refreshState.nestedScrollConnection)) { + content() + + PullToRefreshContainer( + modifier = Modifier.align(Alignment.TopCenter), + state = refreshState, + ) + } +} diff --git a/frontend/app/src/main/java/dk/scheduling/schedulingfrontend/gui/pages/HomePage.kt b/frontend/app/src/main/java/dk/scheduling/schedulingfrontend/gui/pages/HomePage.kt index 666c65bc..097c95eb 100644 --- a/frontend/app/src/main/java/dk/scheduling/schedulingfrontend/gui/pages/HomePage.kt +++ b/frontend/app/src/main/java/dk/scheduling/schedulingfrontend/gui/pages/HomePage.kt @@ -20,34 +20,30 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowDropDown import androidx.compose.material.icons.filled.Delete import androidx.compose.material3.ElevatedCard -import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text -import androidx.compose.material3.pulltorefresh.PullToRefreshContainer -import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue -import androidx.compose.runtime.toMutableStateList import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.rotate import androidx.compose.ui.graphics.Color -import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import dk.scheduling.schedulingfrontend.datasources.api.protocol.Device import dk.scheduling.schedulingfrontend.gui.components.ConfirmAlertDialog import dk.scheduling.schedulingfrontend.gui.components.DATE_FORMATTER import dk.scheduling.schedulingfrontend.gui.components.Loading +import dk.scheduling.schedulingfrontend.gui.components.Refreshable import dk.scheduling.schedulingfrontend.gui.theme.SchedulingFrontendTheme import dk.scheduling.schedulingfrontend.gui.theme.scheduled import dk.scheduling.schedulingfrontend.gui.theme.success @@ -91,30 +87,30 @@ fun HomePagePreviewDarkMode() { } } -@OptIn(ExperimentalMaterial3Api::class) @Composable fun HomePage( modifier: Modifier = Modifier, overviewRepository: IOverviewsRepository, deviceRepository: IDeviceRepository, ) { - var devices by remember { mutableStateOf(mutableListOf()) } - val refreshState = rememberPullToRefreshState() - if (refreshState.isRefreshing) { - LaunchedEffect(true) { - devices = overviewRepository.getDeviceOverview().toMutableStateList() - refreshState.endRefresh() + val devices = remember { mutableStateListOf() } + + suspend fun loadDevices() { + devices.apply { + clear() + addAll(overviewRepository.getDeviceOverview()) } } val (isLoading, setIsLoading) = remember { mutableStateOf(true) } - Loading( isLoading = isLoading, setIsLoading = setIsLoading, - onLoading = { devices = overviewRepository.getDeviceOverview().toMutableStateList() }, + onLoading = { loadDevices() }, ) { - Box(Modifier.nestedScroll(refreshState.nestedScrollConnection)) { + Refreshable( + onRefresh = { loadDevices() }, + ) { LazyColumn( modifier = modifier @@ -137,11 +133,6 @@ fun HomePage( Spacer(modifier = Modifier.height(70.dp)) } } - - PullToRefreshContainer( - modifier = Modifier.align(Alignment.TopCenter), - state = refreshState, - ) } } } diff --git a/frontend/app/src/main/java/dk/scheduling/schedulingfrontend/gui/pages/TaskOverviewPage.kt b/frontend/app/src/main/java/dk/scheduling/schedulingfrontend/gui/pages/TaskOverviewPage.kt index 4a0e0eb0..4308ecf4 100644 --- a/frontend/app/src/main/java/dk/scheduling/schedulingfrontend/gui/pages/TaskOverviewPage.kt +++ b/frontend/app/src/main/java/dk/scheduling/schedulingfrontend/gui/pages/TaskOverviewPage.kt @@ -21,15 +21,12 @@ import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuItem -import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text -import androidx.compose.material3.pulltorefresh.PullToRefreshContainer -import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope @@ -37,7 +34,6 @@ import androidx.compose.runtime.setValue import androidx.compose.runtime.toMutableStateList import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview @@ -50,6 +46,7 @@ import dk.scheduling.schedulingfrontend.gui.components.ConfirmAlertDialog import dk.scheduling.schedulingfrontend.gui.components.DATE_AND_TIME_FORMAT import dk.scheduling.schedulingfrontend.gui.components.DATE_FORMAT import dk.scheduling.schedulingfrontend.gui.components.Loading +import dk.scheduling.schedulingfrontend.gui.components.Refreshable import dk.scheduling.schedulingfrontend.gui.components.TIME_FORMAT import dk.scheduling.schedulingfrontend.gui.theme.SchedulingFrontendTheme import dk.scheduling.schedulingfrontend.model.DeviceTask @@ -63,19 +60,18 @@ import testdata.DummyEventRepository import testdata.DummyTaskRepository import java.time.LocalDateTime -@OptIn(ExperimentalMaterial3Api::class) @Composable fun TaskOverviewPage( modifier: Modifier = Modifier, overviewRepository: IOverviewsRepository, taskRepository: ITaskRepository, ) { - var deviceTasks by remember { mutableStateOf(mutableListOf()) } - val refreshState = rememberPullToRefreshState() - if (refreshState.isRefreshing) { - LaunchedEffect(true) { - deviceTasks = overviewRepository.getDeviceTasks().toMutableStateList() - refreshState.endRefresh() + val deviceTasks = remember { mutableStateListOf() } + + suspend fun loadDeviceTasks() { + deviceTasks.apply { + clear() + addAll(overviewRepository.getDeviceTasks()) } } @@ -84,9 +80,11 @@ fun TaskOverviewPage( Loading( isLoading = isLoading, setIsLoading = setIsLoading, - onLoading = { deviceTasks = overviewRepository.getDeviceTasks().toMutableStateList() }, + onLoading = { loadDeviceTasks() }, ) { - Box(Modifier.nestedScroll(refreshState.nestedScrollConnection)) { + Refreshable( + onRefresh = { loadDeviceTasks() }, + ) { LazyColumn( modifier = modifier @@ -106,11 +104,6 @@ fun TaskOverviewPage( Spacer(modifier = Modifier.height(70.dp)) } } - - PullToRefreshContainer( - modifier = Modifier.align(Alignment.TopCenter), - state = refreshState, - ) } } } From 47c63d5ec8ad96ed259885a781afdf8b491104ed Mon Sep 17 00:00:00 2001 From: Puvikaran Santhirasegaram <74664443+Puvikaran2001@users.noreply.github.com> Date: Wed, 22 May 2024 22:54:25 +0200 Subject: [PATCH 2/4] refactor --- .../gui/components/Dateformat.kt | 2 +- .../schedulingfrontend/gui/pages/HomePage.kt | 40 +++++++------------ 2 files changed, 16 insertions(+), 26 deletions(-) diff --git a/frontend/app/src/main/java/dk/scheduling/schedulingfrontend/gui/components/Dateformat.kt b/frontend/app/src/main/java/dk/scheduling/schedulingfrontend/gui/components/Dateformat.kt index 20dd3d53..70044e69 100644 --- a/frontend/app/src/main/java/dk/scheduling/schedulingfrontend/gui/components/Dateformat.kt +++ b/frontend/app/src/main/java/dk/scheduling/schedulingfrontend/gui/components/Dateformat.kt @@ -6,4 +6,4 @@ import java.util.Locale val DATE_FORMATTER: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") val DATE_FORMAT: DateTimeFormatter = DateTimeFormatter.ofPattern("MMM dd", Locale.ENGLISH) val TIME_FORMAT: DateTimeFormatter = DateTimeFormatter.ofPattern("HH:mm") -val DATE_AND_TIME_FORMAT: DateTimeFormatter = DateTimeFormatter.ofPattern("MMM dd HH:mm") +val DATE_AND_TIME_FORMAT: DateTimeFormatter = DateTimeFormatter.ofPattern("MMM dd, HH:mm") diff --git a/frontend/app/src/main/java/dk/scheduling/schedulingfrontend/gui/pages/HomePage.kt b/frontend/app/src/main/java/dk/scheduling/schedulingfrontend/gui/pages/HomePage.kt index 097c95eb..8ddd963f 100644 --- a/frontend/app/src/main/java/dk/scheduling/schedulingfrontend/gui/pages/HomePage.kt +++ b/frontend/app/src/main/java/dk/scheduling/schedulingfrontend/gui/pages/HomePage.kt @@ -173,27 +173,21 @@ fun DeviceCard( ), verticalAlignment = Alignment.CenterVertically, ) { - Column { - DeviceStateIcon(deviceState) - } + DeviceStateIcon(deviceState) - Column { - Text( - text = deviceOverview.device.name, - modifier = - Modifier.padding(8.dp), - ) - } + Text( + text = deviceOverview.device.name, + modifier = + Modifier.padding(8.dp), + ) Spacer(Modifier.weight(1f)) - Column { - Icon( - modifier = Modifier.rotate(rotationState), - imageVector = Icons.Default.ArrowDropDown, - contentDescription = "Drop-Down Arrow", - ) - } + Icon( + modifier = Modifier.rotate(rotationState), + imageVector = Icons.Default.ArrowDropDown, + contentDescription = "Drop-Down Arrow", + ) } if (expandedCard) { DeviceInfo(modifier = Modifier, deviceOverview.device) @@ -288,22 +282,18 @@ fun DeleteDeviceIconButton( onRemove: () -> Unit, modifier: Modifier = Modifier, ) { - var openConfirmDialog by remember { mutableStateOf(false) } + val (openConfirmDialog, setOpenConfirmDialog) = remember { mutableStateOf(false) } ConfirmAlertDialog( openConfirmDialog = openConfirmDialog, - setOpenConfirmDialog = { openConfirmDialog = it }, + setOpenConfirmDialog = setOpenConfirmDialog, title = "Remove " + device.name, text = "Are you sure that you want to remove " + device.name + "?", - onConfirm = { // TODO: Call API to remove a device - onRemove() - }, + onConfirm = { onRemove() }, ) IconButton( - onClick = { - openConfirmDialog = true - }, + onClick = { setOpenConfirmDialog(true) }, ) { Icon( imageVector = Icons.Default.Delete, From 1c15c9aacc16b6f6c178b253819c06088ad726ad Mon Sep 17 00:00:00 2001 From: Puvikaran Santhirasegaram <74664443+Puvikaran2001@users.noreply.github.com> Date: Wed, 22 May 2024 22:59:30 +0200 Subject: [PATCH 3/4] refactor --- .../gui/pages/CreateDevicePage.kt | 21 ++----------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/frontend/app/src/main/java/dk/scheduling/schedulingfrontend/gui/pages/CreateDevicePage.kt b/frontend/app/src/main/java/dk/scheduling/schedulingfrontend/gui/pages/CreateDevicePage.kt index ecdb1d4f..c6f5df11 100644 --- a/frontend/app/src/main/java/dk/scheduling/schedulingfrontend/gui/pages/CreateDevicePage.kt +++ b/frontend/app/src/main/java/dk/scheduling/schedulingfrontend/gui/pages/CreateDevicePage.kt @@ -17,16 +17,15 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.em import dk.scheduling.schedulingfrontend.datasources.api.protocol.Device import dk.scheduling.schedulingfrontend.gui.components.FilledButton import dk.scheduling.schedulingfrontend.gui.components.OutlinedButton import dk.scheduling.schedulingfrontend.gui.components.StandardTextField +import dk.scheduling.schedulingfrontend.gui.components.Title import dk.scheduling.schedulingfrontend.repositories.device.IDeviceRepository import kotlinx.coroutines.launch import testdata.DummyDeviceRepository @@ -50,23 +49,7 @@ fun CreateDevicePage( mutableStateOf(null) } - Column( - modifier = - modifier - .fillMaxSize() - .padding(all = 50.dp), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Top, - ) { - Spacer(modifier = Modifier.height(90.dp)) - Text( - text = "Create a Device", - fontSize = 7.em, - textAlign = TextAlign.Center, - color = MaterialTheme.colorScheme.primary, - fontWeight = FontWeight(700), - ) - } + Title(titleText = "Create a Device") Column( modifier = From 1777801f54ca75809e82e5135ff8524421187119 Mon Sep 17 00:00:00 2001 From: Puvikaran Santhirasegaram <74664443+Puvikaran2001@users.noreply.github.com> Date: Wed, 22 May 2024 23:06:51 +0200 Subject: [PATCH 4/4] refactor --- .../gui/pages/AccountPage.kt | 52 ++++--------------- 1 file changed, 11 insertions(+), 41 deletions(-) diff --git a/frontend/app/src/main/java/dk/scheduling/schedulingfrontend/gui/pages/AccountPage.kt b/frontend/app/src/main/java/dk/scheduling/schedulingfrontend/gui/pages/AccountPage.kt index d08299fd..8837c06b 100644 --- a/frontend/app/src/main/java/dk/scheduling/schedulingfrontend/gui/pages/AccountPage.kt +++ b/frontend/app/src/main/java/dk/scheduling/schedulingfrontend/gui/pages/AccountPage.kt @@ -3,9 +3,7 @@ package dk.scheduling.schedulingfrontend.gui.pages import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.material3.AlertDialog import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -21,8 +19,8 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.TextUnit import androidx.compose.ui.unit.TextUnitType import androidx.compose.ui.unit.dp +import dk.scheduling.schedulingfrontend.gui.components.ConfirmAlertDialog import dk.scheduling.schedulingfrontend.gui.components.FilledButton -import dk.scheduling.schedulingfrontend.gui.components.OutlinedButton import dk.scheduling.schedulingfrontend.gui.theme.SchedulingFrontendTheme import dk.scheduling.schedulingfrontend.repositories.account.IAccountRepository import kotlinx.coroutines.launch @@ -80,49 +78,21 @@ fun AccountPage( @Composable fun LogoutButton(logout: () -> Unit) { - var openConfirmDialog by remember { mutableStateOf(false) } + val (openConfirmDialog, setOpenConfirmDialog) = remember { mutableStateOf(false) } - if (openConfirmDialog) { - AlertDialog( - title = { - Text( - modifier = Modifier.fillMaxWidth(), - text = "Logout?", - textAlign = TextAlign.Center, - ) - }, - text = { - Text( - modifier = Modifier.fillMaxWidth(), - text = "Are you sure that you want to logout?", - textAlign = TextAlign.Center, - ) - }, - confirmButton = { - FilledButton( - onClick = { - openConfirmDialog = false - logout() - }, - text = "Confirm", - ) - }, - dismissButton = { - OutlinedButton( - onClick = { - openConfirmDialog = false - }, - text = "Cancel", - ) - }, - onDismissRequest = { openConfirmDialog = false }, - ) - } + ConfirmAlertDialog( + openConfirmDialog = openConfirmDialog, + setOpenConfirmDialog = setOpenConfirmDialog, + title = "Logout?", + text = "Are you sure that you want to logout?", + onConfirm = { logout() }, + dismissLabel = "Cancel", + ) FilledButton( text = "Logout", onClick = { - openConfirmDialog = true + setOpenConfirmDialog(true) }, ) }