diff --git a/frontend/app/build.gradle b/frontend/app/build.gradle index 6f5e5efac4c80480e985d8571734ddea5fd6fa68..790169e1335aa8eeb5cf2c7a5676a07ac3952a31 100644 --- a/frontend/app/build.gradle +++ b/frontend/app/build.gradle @@ -91,6 +91,7 @@ dependencies { implementation "androidx.room:room-runtime:$room_version" implementation "androidx.room:room-ktx:$room_version" kapt "androidx.room:room-compiler:$room_version" + implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.3.2") } kotlin.sourceSets.all { diff --git a/frontend/app/src/main/java/space/rethelyi/mosogepsch/MainActivity.kt b/frontend/app/src/main/java/space/rethelyi/mosogepsch/MainActivity.kt index 9c973f4741757791cce0f3d39348c736b6cfa3ca..d9e0138ea2a7b3fdf49d84cdffb33269eb2af906 100644 --- a/frontend/app/src/main/java/space/rethelyi/mosogepsch/MainActivity.kt +++ b/frontend/app/src/main/java/space/rethelyi/mosogepsch/MainActivity.kt @@ -11,6 +11,8 @@ import androidx.compose.ui.platform.LocalContext import androidx.core.app.NotificationManagerCompat import kotlinx.coroutines.delay import kotlinx.coroutines.launch +import kotlinx.datetime.Clock +import kotlinx.datetime.Instant import space.rethelyi.mosogepsch.model.LaundryRoom import space.rethelyi.mosogepsch.model.data.MosogepSchDatabase import space.rethelyi.mosogepsch.network.Api @@ -41,7 +43,7 @@ class MainActivity : ComponentActivity() { fun MosogepSCH() { var rooms by remember { mutableStateOf(listOf<LaundryRoom>()) } var error by remember { mutableStateOf(false) } - var lastRequestTime by remember { mutableStateOf<Date?>(null) } + var lastRequestTime by remember { mutableStateOf<Instant?>(null) } val coroutineScope = rememberCoroutineScope() val ctx = LocalContext.current @@ -50,13 +52,12 @@ fun MosogepSCH() { suspend fun reload() { try { val tmprooms = Api.getLaundryRooms() - lastRequestTime = Date() + lastRequestTime = Clock.System.now() for (room in tmprooms) { room.machines.forEach { - it.last_query_time = room.last_query_time it.floorId = room.id.toString() } - room.machines = room.machines.sortedBy { it.kind_of } + room.machines = room.machines.sortedBy { it.kindOf } room.toDb(ctx) } rooms = tmprooms @@ -67,7 +68,7 @@ fun MosogepSCH() { val oldRooms: MutableList<LaundryRoom> = mutableListOf() list.forEach { element -> val floor = element.toLaundryRoom(ctx) - floor.machines = floor.machines.sortedBy { it.kind_of } + floor.machines = floor.machines.sortedBy { it.kindOf } oldRooms.add(floor) } rooms = oldRooms diff --git a/frontend/app/src/main/java/space/rethelyi/mosogepsch/model/LaundryRoom.kt b/frontend/app/src/main/java/space/rethelyi/mosogepsch/model/LaundryRoom.kt index ab666742425aaffc6b537a78fc0a27b91a961283..95c09b1b8831bf997a8d6ad13f8aca56828e5fad 100644 --- a/frontend/app/src/main/java/space/rethelyi/mosogepsch/model/LaundryRoom.kt +++ b/frontend/app/src/main/java/space/rethelyi/mosogepsch/model/LaundryRoom.kt @@ -11,14 +11,13 @@ import java.util.* data class LaundryRoom( var id: Int, var machines: List<Machine>, - var last_query_time: Date, +// var last_query_time: Date, ) { suspend fun toDb(context: Context) { val db = MosogepSchDatabase.getInstance(context) db.dao.insertLaundryRoom( LaundryRoomData( id = id, - last_query_time = last_query_time, ) ) diff --git a/frontend/app/src/main/java/space/rethelyi/mosogepsch/model/Machine.kt b/frontend/app/src/main/java/space/rethelyi/mosogepsch/model/Machine.kt index 9b3bc42c1b40ef5d9ca1f812471953c00f3d6e89..5a68dc471d06d53eac93d23c57b0d30732107cac 100644 --- a/frontend/app/src/main/java/space/rethelyi/mosogepsch/model/Machine.kt +++ b/frontend/app/src/main/java/space/rethelyi/mosogepsch/model/Machine.kt @@ -1,27 +1,40 @@ package space.rethelyi.mosogepsch.model +import kotlinx.datetime.Clock +import kotlinx.datetime.Instant import space.rethelyi.mosogepsch.model.data.entities.MachineData import java.io.Serializable -import java.time.LocalDateTime import java.util.* data class Machine( var id: Int, - var kind_of: String, - var status: Int, - var message: String? = null, - var last_query_time: Date, - var floorId: String, + var kindOf: Kind = Kind.Unknown, + var status: Status, + var lastQueryTime: Instant = Clock.System.now(), + var lastChanged: Instant = Clock.System.now(), + var floorId: String ) : Serializable { fun toMachineData(): MachineData { return MachineData( id = id, - kind_of = kind_of, + kindOf = kindOf, status = status, - message = message, - last_query_time = last_query_time, - floorId = floorId, + lastQueryTime = lastQueryTime, + lastChanged = lastChanged, + floorId = floorId ) } } + +enum class Status { + Available, + NotAvailable, + LostInSpace +} + +enum class Kind { + Dryer, + Washer, + Unknown, +} \ No newline at end of file diff --git a/frontend/app/src/main/java/space/rethelyi/mosogepsch/model/data/DateConverter.kt b/frontend/app/src/main/java/space/rethelyi/mosogepsch/model/data/DateConverter.kt index 1523e1abd6807a71748a0409b5532d44d70b538d..5fbb6f74c60f6ec1cd15c1cb0f30e40a9650852a 100644 --- a/frontend/app/src/main/java/space/rethelyi/mosogepsch/model/data/DateConverter.kt +++ b/frontend/app/src/main/java/space/rethelyi/mosogepsch/model/data/DateConverter.kt @@ -1,16 +1,16 @@ package space.rethelyi.mosogepsch.model.data import androidx.room.TypeConverter -import java.util.* +import kotlinx.datetime.Instant object DateConverter { @TypeConverter - fun toDate(dateLong: Long): Date { - return Date(dateLong) + fun toDate(dateLong: Long): Instant { + return Instant.fromEpochSeconds(dateLong) } @TypeConverter - fun fromDate(date: Date): Long { - return date.time + fun fromDate(date: Instant): Long { + return date.epochSeconds } } diff --git a/frontend/app/src/main/java/space/rethelyi/mosogepsch/model/data/MosogepSchDatabase.kt b/frontend/app/src/main/java/space/rethelyi/mosogepsch/model/data/MosogepSchDatabase.kt index 3783307dc27e629b2e0cc4fb6fcb29332c8af27f..60a945a6f345dcda0ef360e8b209e37f157edd25 100644 --- a/frontend/app/src/main/java/space/rethelyi/mosogepsch/model/data/MosogepSchDatabase.kt +++ b/frontend/app/src/main/java/space/rethelyi/mosogepsch/model/data/MosogepSchDatabase.kt @@ -13,7 +13,7 @@ import space.rethelyi.mosogepsch.model.data.entities.MachineData LaundryRoomData::class, MachineData::class, ], - version = 2 + version = 7 ) @TypeConverters( diff --git a/frontend/app/src/main/java/space/rethelyi/mosogepsch/model/data/entities/LaundryRoomData.kt b/frontend/app/src/main/java/space/rethelyi/mosogepsch/model/data/entities/LaundryRoomData.kt index d32c4676d9fa8ab673ad61193564a80a6af7a0ad..cb0d528ac48d9d7c221ae4ba35186fb954940d59 100644 --- a/frontend/app/src/main/java/space/rethelyi/mosogepsch/model/data/entities/LaundryRoomData.kt +++ b/frontend/app/src/main/java/space/rethelyi/mosogepsch/model/data/entities/LaundryRoomData.kt @@ -13,7 +13,6 @@ import java.util.* data class LaundryRoomData( @PrimaryKey(autoGenerate = false) var id: Int, - var last_query_time: Date, ) { suspend fun toLaundryRoom(context: Context): LaundryRoom { val db = MosogepSchDatabase.getInstance(context) @@ -27,7 +26,6 @@ data class LaundryRoomData( return LaundryRoom( id = id, machines = machines, - last_query_time = last_query_time, ) } } diff --git a/frontend/app/src/main/java/space/rethelyi/mosogepsch/model/data/entities/MachineData.kt b/frontend/app/src/main/java/space/rethelyi/mosogepsch/model/data/entities/MachineData.kt index 09c2c2123b15e90ea0f88fb1f37b06dd562eebb2..342b1089572827fffe4bf9c9e1772c5dcfd62ba4 100644 --- a/frontend/app/src/main/java/space/rethelyi/mosogepsch/model/data/entities/MachineData.kt +++ b/frontend/app/src/main/java/space/rethelyi/mosogepsch/model/data/entities/MachineData.kt @@ -2,26 +2,32 @@ package space.rethelyi.mosogepsch.model.data.entities import androidx.room.Entity import androidx.room.PrimaryKey +import kotlinx.datetime.Clock +import kotlinx.datetime.Instant +import space.rethelyi.mosogepsch.model.Kind import space.rethelyi.mosogepsch.model.Machine +import space.rethelyi.mosogepsch.model.Status import java.util.* @Entity data class MachineData( @PrimaryKey(autoGenerate = false) var id: Int, - var kind_of: String, - var status: Int, - var message: String? = null, - var last_query_time: Date, + var kindOf: Kind, + var status: Status, +// var message: String? = null, + var lastQueryTime: Instant = Clock.System.now(), + var lastChanged: Instant = Clock.System.now(), var floorId: String, ) { fun toMachine(): Machine { return Machine( id = id, - kind_of = kind_of, + kindOf = kindOf, status = status, - message = message, - last_query_time = last_query_time, +// message = message, + lastQueryTime = lastQueryTime, + lastChanged = lastChanged, floorId = floorId ) } diff --git a/frontend/app/src/main/java/space/rethelyi/mosogepsch/network/Api.kt b/frontend/app/src/main/java/space/rethelyi/mosogepsch/network/Api.kt index b2e6aaaaed9f605a96302155629f8b57e9f11bd1..27155d636ad595466ff50f089aead6a0626566d0 100644 --- a/frontend/app/src/main/java/space/rethelyi/mosogepsch/network/Api.kt +++ b/frontend/app/src/main/java/space/rethelyi/mosogepsch/network/Api.kt @@ -6,7 +6,7 @@ import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory import space.rethelyi.mosogepsch.model.LaundryRoom -private const val SERVICE_URL = "https://mosogep.sch.bme.hu/api/v1/" +private const val SERVICE_URL = "https://mosogep-ng.sch.bme.hu/api/" object Api: MosogepschApi by Retrofit.Builder() diff --git a/frontend/app/src/main/java/space/rethelyi/mosogepsch/network/MosogepschApi.kt b/frontend/app/src/main/java/space/rethelyi/mosogepsch/network/MosogepschApi.kt index a28ecc1581190a531d96d9634a0d3a2e72dbcdc2..ec615ef117d17c92604942b75840712c50d36269 100644 --- a/frontend/app/src/main/java/space/rethelyi/mosogepsch/network/MosogepschApi.kt +++ b/frontend/app/src/main/java/space/rethelyi/mosogepsch/network/MosogepschApi.kt @@ -6,6 +6,6 @@ import space.rethelyi.mosogepsch.model.LaundryRoom interface MosogepschApi { - @GET("laundry-room/") + @GET("v2") suspend fun getLaundryRooms(): List<LaundryRoom> } \ No newline at end of file diff --git a/frontend/app/src/main/java/space/rethelyi/mosogepsch/notification/PushNotificationService.kt b/frontend/app/src/main/java/space/rethelyi/mosogepsch/notification/PushNotificationService.kt index 61c130507261e35e54bdf67d7cfacb23d7f65239..b9eb8079f95732d67c482723591cee382be538b6 100644 --- a/frontend/app/src/main/java/space/rethelyi/mosogepsch/notification/PushNotificationService.kt +++ b/frontend/app/src/main/java/space/rethelyi/mosogepsch/notification/PushNotificationService.kt @@ -4,7 +4,9 @@ import com.google.firebase.messaging.FirebaseMessagingService import com.google.firebase.messaging.RemoteMessage import com.google.gson.Gson import space.rethelyi.mosogepsch.R +import space.rethelyi.mosogepsch.model.Kind import space.rethelyi.mosogepsch.model.Machine +import space.rethelyi.mosogepsch.model.Status class PushNotificationService : FirebaseMessagingService () { private val gson = Gson() @@ -18,15 +20,15 @@ class PushNotificationService : FirebaseMessagingService () { val title = ctx.getString( R.string.title, machine.floorId, - if (machine.kind_of == "DR") ctx.getString(R.string.dryer) + if (machine.kindOf == Kind.Dryer) ctx.getString(R.string.dryer) else ctx.getString(R.string.washer) ) val msg = ctx.getString( R.string.notification_msg, machine.floorId, - if (machine.kind_of == "DR") ctx.getString(R.string.dryer) + if (machine.kindOf == Kind.Dryer) ctx.getString(R.string.dryer) else ctx.getString(R.string.washer), - if (machine.status == 0) ctx.getString(R.string.available) + if (machine.status == Status.Available) ctx.getString(R.string.available) else ctx.getString(R.string.not_available) ) diff --git a/frontend/app/src/main/java/space/rethelyi/mosogepsch/view/Floor.kt b/frontend/app/src/main/java/space/rethelyi/mosogepsch/view/Floor.kt index 298521d144c679435d87344672cfc7077b4a54f5..3bef450813e15cee23932b311ae1738ed5474c7b 100644 --- a/frontend/app/src/main/java/space/rethelyi/mosogepsch/view/Floor.kt +++ b/frontend/app/src/main/java/space/rethelyi/mosogepsch/view/Floor.kt @@ -11,12 +11,13 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import kotlinx.datetime.Instant import space.rethelyi.mosogepsch.R import space.rethelyi.mosogepsch.model.Machine import java.util.* @Composable -fun FloorListItem(floor: Floor, lastRequestTime: Date?) { +fun FloorListItem(floor: Floor, lastRequestTime: Instant?) { val modifier = Modifier.fillMaxWidth() Card( modifier = modifier, diff --git a/frontend/app/src/main/java/space/rethelyi/mosogepsch/view/MachineOnFloor.kt b/frontend/app/src/main/java/space/rethelyi/mosogepsch/view/MachineOnFloor.kt index a17b534e819edf503f88c439cc352bb5a6f7d6e7..ca12ff1c0fae3e3aafd435c5308bbbb61c05fe48 100644 --- a/frontend/app/src/main/java/space/rethelyi/mosogepsch/view/MachineOnFloor.kt +++ b/frontend/app/src/main/java/space/rethelyi/mosogepsch/view/MachineOnFloor.kt @@ -10,14 +10,15 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp +import kotlinx.datetime.Instant import space.rethelyi.mosogepsch.R +import space.rethelyi.mosogepsch.model.Kind import space.rethelyi.mosogepsch.model.Machine -import java.time.Instant -import java.time.LocalDateTime +import space.rethelyi.mosogepsch.model.Status import java.util.* @Composable -fun MachineOnFloorView(machine: Machine, modifier: Modifier, lastRequestTime: Date?) { +fun MachineOnFloorView(machine: Machine, modifier: Modifier, lastRequestTime: Instant?) { val context = LocalContext.current Card( modifier = modifier @@ -26,14 +27,14 @@ fun MachineOnFloorView(machine: Machine, modifier: Modifier, lastRequestTime: Da onClick = { val intent = Intent(context, MachineViewActivity::class.java) intent.putExtra("machine", machine) - intent.putExtra("last_request_time", lastRequestTime) + intent.putExtra("last_request_time", lastRequestTime.toString()) context.startActivity(intent) }), color = when { - machine.last_query_time.isLostInSpace(lastRequestTime) -> { + machine.lastChanged.isLostInSpace(lastRequestTime) -> { MaterialTheme.colorScheme.background } - machine.status == 1 -> { + machine.status == Status.NotAvailable -> { MaterialTheme.colorScheme.error } else -> MaterialTheme.colorScheme.primary @@ -48,12 +49,12 @@ fun MachineOnFloorView(machine: Machine, modifier: Modifier, lastRequestTime: Da modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceAround, ) { - if (machine.kind_of == "DR") { + if (machine.kindOf == Kind.Dryer) { Icon( painter = painterResource(id = R.drawable.dryer), contentDescription = "dryer" ) - } else if (machine.kind_of == "WM") { + } else if (machine.kindOf == Kind.Washer) { Icon( painter = painterResource(id = R.drawable.washer), contentDescription = "washer" @@ -71,8 +72,8 @@ fun MachineOnFloorView(machine: Machine, modifier: Modifier, lastRequestTime: Da const val spaceThreshold = 10*60*1000 // 10 minutes -fun Date.isLostInSpace(lastRequestTime: Date?) : Boolean { +fun Instant.isLostInSpace(lastRequestTime: Instant?) : Boolean { if (lastRequestTime == null) return false - val diff = lastRequestTime.time - this.time + val diff = lastRequestTime.epochSeconds - this.epochSeconds return diff > spaceThreshold } \ No newline at end of file diff --git a/frontend/app/src/main/java/space/rethelyi/mosogepsch/view/MachineScreen.kt b/frontend/app/src/main/java/space/rethelyi/mosogepsch/view/MachineScreen.kt index 08772de86232f1f2cca708d03b4faa136893ad70..4fa409ddd47fef797424b65b3c1cfb3fd9c7a91c 100644 --- a/frontend/app/src/main/java/space/rethelyi/mosogepsch/view/MachineScreen.kt +++ b/frontend/app/src/main/java/space/rethelyi/mosogepsch/view/MachineScreen.kt @@ -10,7 +10,6 @@ import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource @@ -18,8 +17,11 @@ import androidx.compose.ui.unit.dp import androidx.core.content.edit import com.google.firebase.ktx.Firebase import com.google.firebase.messaging.ktx.messaging +import kotlinx.datetime.Instant import space.rethelyi.mosogepsch.R +import space.rethelyi.mosogepsch.model.Kind import space.rethelyi.mosogepsch.model.Machine +import space.rethelyi.mosogepsch.model.Status import java.text.SimpleDateFormat import java.util.* @@ -27,7 +29,7 @@ val format = SimpleDateFormat.getDateTimeInstance() @Composable @OptIn(ExperimentalMaterial3Api::class) -fun MachineScreen(machine: Machine, lastRequestTime: Date?, onUpdate: (Boolean) -> Unit) { +fun MachineScreen(machine: Machine, lastRequestTime: Instant?, onUpdate: (Boolean) -> Unit) { val ctx = LocalContext.current val modifier = Modifier.fillMaxWidth() Scaffold( @@ -46,7 +48,7 @@ fun MachineScreen(machine: Machine, lastRequestTime: Date?, onUpdate: (Boolean) text = stringResource( R.string.title, machine.floorId, - if (machine.kind_of == "DR") stringResource(R.string.dryer) + if (machine.kindOf == Kind.Dryer) stringResource(R.string.dryer) else stringResource(R.string.washer) ) ) @@ -63,20 +65,20 @@ fun MachineScreen(machine: Machine, lastRequestTime: Date?, onUpdate: (Boolean) Card( modifier = modifier, color = when { - machine.last_query_time.isLostInSpace(lastRequestTime) -> { + machine.lastQueryTime.isLostInSpace(lastRequestTime) -> { MaterialTheme.colorScheme.surfaceVariant } - machine.status == 1 -> { + machine.status == Status.NotAvailable -> { MaterialTheme.colorScheme.error } else -> MaterialTheme.colorScheme.primary }, ) { val status = when { - machine.last_query_time.isLostInSpace(lastRequestTime) -> { + machine.lastQueryTime.isLostInSpace(lastRequestTime) -> { stringResource(R.string.lost_in_space) } - machine.status == 1 -> { + machine.status == Status.NotAvailable -> { stringResource(R.string.not_available) } else -> stringResource(R.string.available) @@ -93,7 +95,7 @@ fun MachineScreen(machine: Machine, lastRequestTime: Date?, onUpdate: (Boolean) modifier = modifier .padding(8.dp), text = stringResource(R.string.last_queried, - format.format(machine.last_query_time) + format.format(machine.lastQueryTime) )) } Card( @@ -105,7 +107,7 @@ fun MachineScreen(machine: Machine, lastRequestTime: Date?, onUpdate: (Boolean) val successfullyUnsubscribed = stringResource(R.string.unsub_success) val failedToUnsubscribe = stringResource(R.string.unsub_fail) // val topic = "test" //machine.kind_of + machine.id - val topic = machine.kind_of + machine.id + val topic = machine.kindOf.toString() + machine.id.toString() val sharedPref = ctx.getSharedPreferences(machine.id.toString(), Context.MODE_PRIVATE) var subscribeState by remember { mutableStateOf(sharedPref.getBoolean(machine.id.toString(), false)) } diff --git a/frontend/app/src/main/java/space/rethelyi/mosogepsch/view/MachineViewActivity.kt b/frontend/app/src/main/java/space/rethelyi/mosogepsch/view/MachineViewActivity.kt index ab183a57daaecd99f1d81667f3a227a0cef56c0f..e573e6441355fd228d4a8ffcb184b587c0963f82 100644 --- a/frontend/app/src/main/java/space/rethelyi/mosogepsch/view/MachineViewActivity.kt +++ b/frontend/app/src/main/java/space/rethelyi/mosogepsch/view/MachineViewActivity.kt @@ -5,6 +5,7 @@ import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface +import kotlinx.datetime.Instant import space.rethelyi.mosogepsch.model.Machine import space.rethelyi.mosogepsch.ui.theme.MosogepSCHTheme import java.util.* @@ -14,7 +15,7 @@ class MachineViewActivity : ComponentActivity() { super.onCreate(savedInstanceState) val machine = intent.getSerializableExtra("machine") as? Machine ?: throw IllegalArgumentException("machine must be machine") - val lastRequestTime = intent.getSerializableExtra("last_request_time") as? Date ?: throw IllegalArgumentException("date must be date") + val lastRequestTime = intent.getSerializableExtra("last_request_time") as? String ?: throw IllegalArgumentException("date must be date") setContent { MosogepSCHTheme { @@ -22,7 +23,7 @@ class MachineViewActivity : ComponentActivity() { Surface(color = MaterialTheme.colorScheme.background) { MachineScreen( machine = machine, - lastRequestTime = lastRequestTime + lastRequestTime = Instant.parse(lastRequestTime) ) { false } } } diff --git a/frontend/app/src/main/java/space/rethelyi/mosogepsch/view/MainScreen.kt b/frontend/app/src/main/java/space/rethelyi/mosogepsch/view/MainScreen.kt index 703c63d21776a15262773d27257de97255af1848..38f561aba2b23858bddcd7a2d7bc900bc006ed07 100644 --- a/frontend/app/src/main/java/space/rethelyi/mosogepsch/view/MainScreen.kt +++ b/frontend/app/src/main/java/space/rethelyi/mosogepsch/view/MainScreen.kt @@ -15,13 +15,14 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import com.google.accompanist.swiperefresh.SwipeRefresh import com.google.accompanist.swiperefresh.SwipeRefreshState +import kotlinx.datetime.Instant import space.rethelyi.mosogepsch.model.LaundryRoom import space.rethelyi.mosogepsch.view.helpers.AppBar import java.util.* @Composable @OptIn(ExperimentalMaterial3Api::class) -fun MainScreen(rooms: List<LaundryRoom>, error: Boolean, lastRequestTime: Date?, reload: (swipe: SwipeRefreshState) -> Unit) { +fun MainScreen(rooms: List<LaundryRoom>, error: Boolean, lastRequestTime: Instant?, reload: (swipe: SwipeRefreshState) -> Unit) { val isRefreshing by remember { mutableStateOf(SwipeRefreshState(!error)) } Scaffold( topBar = { AppBar(!error) }