From a6999ffda592310c8c159c8c3f1f224c892280c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20St=C4=99pie=C5=84?= Date: Tue, 7 Jan 2025 19:41:26 +0100 Subject: [PATCH] Implement room fetching --- .../androidclient/error/ErrorHandler.kt | 4 +- .../androidclient/model/CreateRoomPayload.kt | 13 +++++ .../androidclient/model/RoomListView.kt | 12 +++++ .../androidclient/network/api/FeelBeatApi.kt | 8 +-- .../network/api/KtorFeelBeatApi.kt | 46 ++++++++++++++-- .../network/api/payloads/CreateRoomPayload.kt | 28 ---------- .../api/responses/FetchRoomsResponse.kt | 6 +++ .../app/game/gameresult/GameResultScreen.kt | 2 +- .../game/gameresult/GameResultViewModel.kt | 4 +- .../ui/app/game/guesssong/GuessSongScreen.kt | 4 +- .../app/game/guesssong/GuessSongViewModel.kt | 6 +-- .../ui/app/game/guesssong/GuessState.kt | 8 +-- .../ui/app/game/startgame/StartGameScreen.kt | 2 +- .../app/game/startgame/StartGameViewModel.kt | 2 +- .../androidclient/ui/app/home/HomeScreen.kt | 54 +++++++++++++++---- .../ui/app/home/HomeViewModel.kt | 45 +++++++++------- .../app/lobby/acceptgame/AcceptGameScreen.kt | 2 +- .../lobby/acceptgame/AcceptGameViewModel.kt | 4 +- .../ui/app/lobby/acceptgame/GameState.kt | 8 +-- .../androidclient/ui/app/model/Player.kt | 3 -- .../ui/app/model/RoomSettings.kt | 10 ---- .../androidclient/ui/app/model/Song.kt | 3 -- .../ui/app/navigation/AppGraph.kt | 4 +- .../viewmodels/NewRoomSettingsViewModel.kt | 2 +- .../viewmodels/RoomSettingsViewModel.kt | 2 +- .../androidclient/ui/app/uimodel/Player.kt | 3 ++ .../{model => uimodel}/PlayerWithResult.kt | 2 +- .../ui/app/{model => uimodel}/Playlist.kt | 2 +- .../ui/app/{model => uimodel}/Room.kt | 2 +- .../ui/app/uimodel/RoomSettings.kt | 24 +++++++++ .../androidclient/ui/app/uimodel/Song.kt | 3 ++ 31 files changed, 208 insertions(+), 110 deletions(-) create mode 100644 app/src/main/java/com/github/feelbeatapp/androidclient/model/CreateRoomPayload.kt create mode 100644 app/src/main/java/com/github/feelbeatapp/androidclient/model/RoomListView.kt delete mode 100644 app/src/main/java/com/github/feelbeatapp/androidclient/network/api/payloads/CreateRoomPayload.kt create mode 100644 app/src/main/java/com/github/feelbeatapp/androidclient/network/api/responses/FetchRoomsResponse.kt delete mode 100644 app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/model/Player.kt delete mode 100644 app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/model/RoomSettings.kt delete mode 100644 app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/model/Song.kt create mode 100644 app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/uimodel/Player.kt rename app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/{model => uimodel}/PlayerWithResult.kt (74%) rename app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/{model => uimodel}/Playlist.kt (50%) rename app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/{model => uimodel}/Room.kt (73%) create mode 100644 app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/uimodel/RoomSettings.kt create mode 100644 app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/uimodel/Song.kt diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/error/ErrorHandler.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/error/ErrorHandler.kt index 34afc61..4ea2d90 100644 --- a/app/src/main/java/com/github/feelbeatapp/androidclient/error/ErrorHandler.kt +++ b/app/src/main/java/com/github/feelbeatapp/androidclient/error/ErrorHandler.kt @@ -1,14 +1,16 @@ package com.github.feelbeatapp.androidclient.error +import android.util.Log +import javax.inject.Inject import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.asSharedFlow -import javax.inject.Inject class ErrorHandler @Inject constructor() : ErrorEmitter, ErrorReceiver { private val _errors = MutableSharedFlow() override val errors = _errors.asSharedFlow() override suspend fun submitError(exception: FeelBeatException) { + Log.e("App error", exception.toString()) _errors.emit(exception) } } diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/model/CreateRoomPayload.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/model/CreateRoomPayload.kt new file mode 100644 index 0000000..ff03f40 --- /dev/null +++ b/app/src/main/java/com/github/feelbeatapp/androidclient/model/CreateRoomPayload.kt @@ -0,0 +1,13 @@ +package com.github.feelbeatapp.androidclient.model + +import kotlinx.serialization.Serializable + +@Serializable +data class CreateRoomPayload( + val maxPlayers: Int, + val turnCount: Int, + val timePenaltyPerSecond: Int, + val basePoints: Int, + val incorrectGuessPenalty: Int, + val playListId: String, +) diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/model/RoomListView.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/model/RoomListView.kt new file mode 100644 index 0000000..5727638 --- /dev/null +++ b/app/src/main/java/com/github/feelbeatapp/androidclient/model/RoomListView.kt @@ -0,0 +1,12 @@ +package com.github.feelbeatapp.androidclient.model + +import kotlinx.serialization.Serializable + +@Serializable +data class RoomListView( + val id: String, + val name: String, + val players: Int, + val maxPlayers: Int, + val imageUrl: String, +) diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/network/api/FeelBeatApi.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/network/api/FeelBeatApi.kt index dd4b505..c67fcf3 100644 --- a/app/src/main/java/com/github/feelbeatapp/androidclient/network/api/FeelBeatApi.kt +++ b/app/src/main/java/com/github/feelbeatapp/androidclient/network/api/FeelBeatApi.kt @@ -1,8 +1,10 @@ package com.github.feelbeatapp.androidclient.network.api -import com.github.feelbeatapp.androidclient.ui.app.model.RoomSettings - +import com.github.feelbeatapp.androidclient.model.CreateRoomPayload +import com.github.feelbeatapp.androidclient.model.RoomListView interface FeelBeatApi { - suspend fun createRoom(settings: RoomSettings): String + suspend fun createRoom(payload: CreateRoomPayload): String + + suspend fun fetchRooms(): List } diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/network/api/KtorFeelBeatApi.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/network/api/KtorFeelBeatApi.kt index 2f3c44d..a7e84c8 100644 --- a/app/src/main/java/com/github/feelbeatapp/androidclient/network/api/KtorFeelBeatApi.kt +++ b/app/src/main/java/com/github/feelbeatapp/androidclient/network/api/KtorFeelBeatApi.kt @@ -4,11 +4,13 @@ import com.github.feelbeatapp.androidclient.auth.AuthManager import com.github.feelbeatapp.androidclient.error.ErrorCode import com.github.feelbeatapp.androidclient.error.FeelBeatException import com.github.feelbeatapp.androidclient.error.FeelBeatServerException -import com.github.feelbeatapp.androidclient.network.api.payloads.CreateRoomPayload +import com.github.feelbeatapp.androidclient.model.CreateRoomPayload +import com.github.feelbeatapp.androidclient.model.RoomListView import com.github.feelbeatapp.androidclient.network.api.responses.CreateRoomResponse -import com.github.feelbeatapp.androidclient.ui.app.model.RoomSettings +import com.github.feelbeatapp.androidclient.network.api.responses.FetchRoomsResponse import io.ktor.client.HttpClient import io.ktor.client.call.body +import io.ktor.client.request.get import io.ktor.client.request.headers import io.ktor.client.request.post import io.ktor.client.request.setBody @@ -28,8 +30,7 @@ constructor( private val httpClient: HttpClient, private val authManager: AuthManager, ) : FeelBeatApi { - override suspend fun createRoom(settings: RoomSettings): String { - val payload = CreateRoomPayload.fromRoomSettings(settings) + override suspend fun createRoom(payload: CreateRoomPayload): String { val token = authManager.getAccessToken() val res = @@ -49,7 +50,7 @@ constructor( } if (res.status != HttpStatusCode.OK) { - throw FeelBeatServerException(res.bodyAsText()) + throw FeelBeatServerException(res.bodyAsText().trim()) } val (roomId) = @@ -65,4 +66,39 @@ constructor( return roomId } + + override suspend fun fetchRooms(): List { + val token = authManager.getAccessToken() + + val res = + try { + httpClient.get("$baseUrl/rooms") { + headers { set("Authorization", "Bearer $token") } + } + } catch (e: Exception) { + when (e) { + is IOException, + is UnresolvedAddressException -> + throw FeelBeatException(ErrorCode.FEELBEAT_SERVER_UNREACHABLE, e) + else -> throw e + } + } + + if (res.status != HttpStatusCode.OK) { + throw FeelBeatServerException(res.bodyAsText().trim()) + } + + val (rooms) = + try { + res.body() + } catch (e: UnsupportedOperationException) { + throw FeelBeatException( + ErrorCode.FEELBEAT_SERVER_INCORRECT_RESPONSE_FORMAT, + "Failed to parse server response", + e, + ) + } + + return rooms + } } diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/network/api/payloads/CreateRoomPayload.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/network/api/payloads/CreateRoomPayload.kt deleted file mode 100644 index ea39add..0000000 --- a/app/src/main/java/com/github/feelbeatapp/androidclient/network/api/payloads/CreateRoomPayload.kt +++ /dev/null @@ -1,28 +0,0 @@ -package com.github.feelbeatapp.androidclient.network.api.payloads - -import com.github.feelbeatapp.androidclient.ui.app.model.RoomSettings -import io.ktor.http.Url -import kotlinx.serialization.Serializable - -@Serializable -data class CreateRoomPayload( - val maxPlayers: Int, - val turnCount: Int, - val timePenaltyPerSecond: Int, - val basePoints: Int, - val incorrectGuessPenalty: Int, - val playListId: String, -) { - companion object { - fun fromRoomSettings(settings: RoomSettings): CreateRoomPayload { - return CreateRoomPayload( - maxPlayers = settings.maxPlayers, - turnCount = settings.turnCount, - timePenaltyPerSecond = settings.timePenaltyPerSecond, - basePoints = settings.basePoints, - incorrectGuessPenalty = settings.incorrectGuessPenalty, - playListId = Url(settings.playlistLink).segments.last(), - ) - } - } -} diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/network/api/responses/FetchRoomsResponse.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/network/api/responses/FetchRoomsResponse.kt new file mode 100644 index 0000000..5db8fda --- /dev/null +++ b/app/src/main/java/com/github/feelbeatapp/androidclient/network/api/responses/FetchRoomsResponse.kt @@ -0,0 +1,6 @@ +package com.github.feelbeatapp.androidclient.network.api.responses + +import com.github.feelbeatapp.androidclient.model.RoomListView +import kotlinx.serialization.Serializable + +@Serializable data class FetchRoomsResponse(val rooms: List) diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/game/gameresult/GameResultScreen.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/game/gameresult/GameResultScreen.kt index b6f0873..67b0a10 100644 --- a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/game/gameresult/GameResultScreen.kt +++ b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/game/gameresult/GameResultScreen.kt @@ -28,7 +28,7 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.github.feelbeatapp.androidclient.R -import com.github.feelbeatapp.androidclient.ui.app.model.PlayerWithResult +import com.github.feelbeatapp.androidclient.ui.app.uimodel.PlayerWithResult import com.github.feelbeatapp.androidclient.ui.app.navigation.AppRoute @Composable diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/game/gameresult/GameResultViewModel.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/game/gameresult/GameResultViewModel.kt index 57ef033..e1de7c7 100644 --- a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/game/gameresult/GameResultViewModel.kt +++ b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/game/gameresult/GameResultViewModel.kt @@ -4,8 +4,8 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.github.feelbeatapp.androidclient.R import com.github.feelbeatapp.androidclient.ui.app.game.guesssong.ResultStatus -import com.github.feelbeatapp.androidclient.ui.app.model.Player -import com.github.feelbeatapp.androidclient.ui.app.model.PlayerWithResult +import com.github.feelbeatapp.androidclient.ui.app.uimodel.Player +import com.github.feelbeatapp.androidclient.ui.app.uimodel.PlayerWithResult import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/game/guesssong/GuessSongScreen.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/game/guesssong/GuessSongScreen.kt index 2152db3..a8b4bcd 100644 --- a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/game/guesssong/GuessSongScreen.kt +++ b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/game/guesssong/GuessSongScreen.kt @@ -38,8 +38,8 @@ import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.github.feelbeatapp.androidclient.R -import com.github.feelbeatapp.androidclient.ui.app.model.PlayerWithResult -import com.github.feelbeatapp.androidclient.ui.app.model.Song +import com.github.feelbeatapp.androidclient.ui.app.uimodel.PlayerWithResult +import com.github.feelbeatapp.androidclient.ui.app.uimodel.Song import com.github.feelbeatapp.androidclient.ui.app.navigation.AppRoute @OptIn(ExperimentalMaterial3Api::class) diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/game/guesssong/GuessSongViewModel.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/game/guesssong/GuessSongViewModel.kt index c8aa7e7..e16a96d 100644 --- a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/game/guesssong/GuessSongViewModel.kt +++ b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/game/guesssong/GuessSongViewModel.kt @@ -4,9 +4,9 @@ import androidx.compose.ui.text.input.TextFieldValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.github.feelbeatapp.androidclient.R -import com.github.feelbeatapp.androidclient.ui.app.model.Player -import com.github.feelbeatapp.androidclient.ui.app.model.PlayerWithResult -import com.github.feelbeatapp.androidclient.ui.app.model.Song +import com.github.feelbeatapp.androidclient.ui.app.uimodel.Player +import com.github.feelbeatapp.androidclient.ui.app.uimodel.PlayerWithResult +import com.github.feelbeatapp.androidclient.ui.app.uimodel.Song import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/game/guesssong/GuessState.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/game/guesssong/GuessState.kt index b8eb37b..30dbbf1 100644 --- a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/game/guesssong/GuessState.kt +++ b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/game/guesssong/GuessState.kt @@ -1,10 +1,10 @@ package com.github.feelbeatapp.androidclient.ui.app.game.guesssong import androidx.compose.ui.text.input.TextFieldValue -import com.github.feelbeatapp.androidclient.ui.app.model.PlayerWithResult -import com.github.feelbeatapp.androidclient.ui.app.model.Playlist -import com.github.feelbeatapp.androidclient.ui.app.model.Room -import com.github.feelbeatapp.androidclient.ui.app.model.Song +import com.github.feelbeatapp.androidclient.ui.app.uimodel.PlayerWithResult +import com.github.feelbeatapp.androidclient.ui.app.uimodel.Playlist +import com.github.feelbeatapp.androidclient.ui.app.uimodel.Room +import com.github.feelbeatapp.androidclient.ui.app.uimodel.Song data class GuessState( val players: List = emptyList(), diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/game/startgame/StartGameScreen.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/game/startgame/StartGameScreen.kt index 7f597ce..f8b4d6d 100644 --- a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/game/startgame/StartGameScreen.kt +++ b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/game/startgame/StartGameScreen.kt @@ -28,7 +28,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.github.feelbeatapp.androidclient.R -import com.github.feelbeatapp.androidclient.ui.app.model.Player +import com.github.feelbeatapp.androidclient.ui.app.uimodel.Player import com.github.feelbeatapp.androidclient.ui.app.navigation.AppRoute @Composable diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/game/startgame/StartGameViewModel.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/game/startgame/StartGameViewModel.kt index e168834..1af68cd 100644 --- a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/game/startgame/StartGameViewModel.kt +++ b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/game/startgame/StartGameViewModel.kt @@ -3,7 +3,7 @@ package com.github.feelbeatapp.androidclient.ui.app.game.startgame import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.github.feelbeatapp.androidclient.R -import com.github.feelbeatapp.androidclient.ui.app.model.Player +import com.github.feelbeatapp.androidclient.ui.app.uimodel.Player import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/home/HomeScreen.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/home/HomeScreen.kt index 0894ee0..7de5b31 100644 --- a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/home/HomeScreen.kt +++ b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/home/HomeScreen.kt @@ -2,27 +2,34 @@ package com.github.feelbeatapp.androidclient.ui.app.home import androidx.compose.foundation.background import androidx.compose.foundation.border -import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton +import androidx.compose.material3.ListItem import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text +import androidx.compose.material3.pulltorefresh.PullToRefreshBox import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource @@ -30,15 +37,18 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import com.github.feelbeatapp.androidclient.R -import com.github.feelbeatapp.androidclient.ui.app.model.Room +import com.github.feelbeatapp.androidclient.model.RoomListView @Composable fun HomeScreen( - onRoomSelect: (Room) -> Unit, + onRoomSelect: (String) -> Unit, onNewRoom: () -> Unit, homeViewModel: HomeViewModel = hiltViewModel(), ) { val rooms by homeViewModel.rooms.collectAsState() + val loading by homeViewModel.loading.collectAsState() + + LaunchedEffect(null) { homeViewModel.loadRooms() } Column(modifier = Modifier.fillMaxSize()) { Text( @@ -46,11 +56,21 @@ fun HomeScreen( style = MaterialTheme.typography.titleMedium, modifier = Modifier.padding(16.dp), ) - LazyColumn( - modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp).weight(1f), - verticalArrangement = Arrangement.spacedBy(8.dp), - ) { - items(rooms) { room -> RoomItem(room = room, onClick = { onRoomSelect(room) }) } + + if (loading) { + CircularProgressIndicator( + color = MaterialTheme.colorScheme.secondary, + trackColor = MaterialTheme.colorScheme.surfaceVariant, + strokeWidth = 4.dp, + modifier = Modifier.width(50.dp).height(50.dp), + ) + } else { + RoomList( + items = rooms, + isRefreshing = loading, + onRefresh = { homeViewModel.loadRooms() }, + onRoomSelect = onRoomSelect, + ) } Box( @@ -78,8 +98,24 @@ fun HomeScreen( } } +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun RoomList( + items: List, + isRefreshing: Boolean, + onRefresh: () -> Unit, + onRoomSelect: (String) -> Unit, + modifier: Modifier = Modifier, +) { + PullToRefreshBox(isRefreshing = isRefreshing, onRefresh = onRefresh, modifier = modifier) { + LazyColumn(Modifier.fillMaxSize()) { + items(items) { ListItem({ RoomItem(room = it, onClick = { onRoomSelect(it.id) }) }) } + } + } +} + @Composable -fun RoomItem(room: Room, onClick: () -> Unit) { +fun RoomItem(room: RoomListView, onClick: () -> Unit) { Card( onClick = onClick, colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surface), diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/home/HomeViewModel.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/home/HomeViewModel.kt index db8b6c5..5a11a97 100644 --- a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/home/HomeViewModel.kt +++ b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/home/HomeViewModel.kt @@ -2,37 +2,42 @@ package com.github.feelbeatapp.androidclient.ui.app.home import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.github.feelbeatapp.androidclient.ui.app.model.Room +import com.github.feelbeatapp.androidclient.error.ErrorReceiver +import com.github.feelbeatapp.androidclient.error.FeelBeatException +import com.github.feelbeatapp.androidclient.model.RoomListView +import com.github.feelbeatapp.androidclient.network.api.FeelBeatApi import dagger.hilt.android.lifecycle.HiltViewModel -import javax.inject.Inject import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch +import javax.inject.Inject @HiltViewModel -class HomeViewModel @Inject constructor() : ViewModel() { - private val _rooms = MutableStateFlow>(emptyList()) - val rooms: StateFlow> = _rooms.asStateFlow() +class HomeViewModel +@Inject +constructor(private val feelBeatApi: FeelBeatApi, private val errorReceiver: ErrorReceiver) : + ViewModel() { + private val _rooms = MutableStateFlow>(listOf()) + val rooms: StateFlow> = _rooms.asStateFlow() - init { - loadRooms() - } + private val _loading = MutableStateFlow(false) + val loading = _loading.asStateFlow() @SuppressWarnings("MagicNumber") - private fun loadRooms() { + fun loadRooms() { + _loading.value = true viewModelScope.launch { - val exampleRooms = - listOf( - Room(1, "Pokój 1", 4, 30, 10, "https://example.com/playlist1"), - Room(2, "Pokój 2", 5, 20, 5, "https://example.com/playlist2"), - Room(3, "Pokój 3", 2, 25, 3, "https://example.com/playlist3"), - Room(4, "Pokój 4", 4, 30, 4, "https://example.com/playlist4"), - Room(5, "Pokój 5", 5, 25, 4, "https://example.com/playlist5"), - Room(6, "Pokój 6", 2, 25, 10, "https://example.com/playlist6"), - Room(7, "Pokój 7", 4, 30, 9, "https://example.com/playlist7"), - ) - _rooms.value = exampleRooms + val roomsFromServer = + try { + feelBeatApi.fetchRooms() + } catch (e: FeelBeatException) { + errorReceiver.submitError(e) + listOf() + } + + _rooms.value = roomsFromServer + _loading.value = false } } } diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/lobby/acceptgame/AcceptGameScreen.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/lobby/acceptgame/AcceptGameScreen.kt index eed9fb0..46a2ffe 100644 --- a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/lobby/acceptgame/AcceptGameScreen.kt +++ b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/lobby/acceptgame/AcceptGameScreen.kt @@ -24,7 +24,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.github.feelbeatapp.androidclient.R import com.github.feelbeatapp.androidclient.ui.app.game.startgame.PlayerCard -import com.github.feelbeatapp.androidclient.ui.app.model.Song +import com.github.feelbeatapp.androidclient.ui.app.uimodel.Song @Composable fun AcceptGameScreen( diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/lobby/acceptgame/AcceptGameViewModel.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/lobby/acceptgame/AcceptGameViewModel.kt index c0aa530..7c34015 100644 --- a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/lobby/acceptgame/AcceptGameViewModel.kt +++ b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/lobby/acceptgame/AcceptGameViewModel.kt @@ -3,8 +3,8 @@ package com.github.feelbeatapp.androidclient.ui.app.lobby.acceptgame import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.github.feelbeatapp.androidclient.R -import com.github.feelbeatapp.androidclient.ui.app.model.Player -import com.github.feelbeatapp.androidclient.ui.app.model.Song +import com.github.feelbeatapp.androidclient.ui.app.uimodel.Player +import com.github.feelbeatapp.androidclient.ui.app.uimodel.Song import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/lobby/acceptgame/GameState.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/lobby/acceptgame/GameState.kt index 2997039..15ea3d7 100644 --- a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/lobby/acceptgame/GameState.kt +++ b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/lobby/acceptgame/GameState.kt @@ -1,9 +1,9 @@ package com.github.feelbeatapp.androidclient.ui.app.lobby.acceptgame -import com.github.feelbeatapp.androidclient.ui.app.model.Player -import com.github.feelbeatapp.androidclient.ui.app.model.Playlist -import com.github.feelbeatapp.androidclient.ui.app.model.Room -import com.github.feelbeatapp.androidclient.ui.app.model.Song +import com.github.feelbeatapp.androidclient.ui.app.uimodel.Player +import com.github.feelbeatapp.androidclient.ui.app.uimodel.Playlist +import com.github.feelbeatapp.androidclient.ui.app.uimodel.Room +import com.github.feelbeatapp.androidclient.ui.app.uimodel.Song data class GameState( diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/model/Player.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/model/Player.kt deleted file mode 100644 index ce0244e..0000000 --- a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/model/Player.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.github.feelbeatapp.androidclient.ui.app.model - -data class Player(val name: String, val image: Int) diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/model/RoomSettings.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/model/RoomSettings.kt deleted file mode 100644 index 6fdd6df..0000000 --- a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/model/RoomSettings.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.github.feelbeatapp.androidclient.ui.app.model - -data class RoomSettings( - val maxPlayers: Int, - val turnCount: Int, - val timePenaltyPerSecond: Int, - val basePoints: Int, - val incorrectGuessPenalty: Int, - val playlistLink: String, -) diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/model/Song.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/model/Song.kt deleted file mode 100644 index 5398a45..0000000 --- a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/model/Song.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.github.feelbeatapp.androidclient.ui.app.model - -data class Song(val id: Int, val title: String) diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/navigation/AppGraph.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/navigation/AppGraph.kt index 83d7ba9..4f33c04 100644 --- a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/navigation/AppGraph.kt +++ b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/navigation/AppGraph.kt @@ -43,9 +43,9 @@ fun AppGraph(onLogout: () -> Unit) { NavHost(navController = navController, startDestination = AppRoute.HOME.route) { composable(route = AppRoute.HOME.route) { HomeScreen( - onRoomSelect = { room -> + onRoomSelect = { roomId -> navController.navigate( - AppRoute.ROOM_LOBBY.withArgs(mapOf("roomId" to room.id.toString())) + AppRoute.ROOM_LOBBY.withArgs(mapOf("roomId" to roomId)) ) }, onNewRoom = { navController.navigate(AppRoute.NEW_ROOM.route) }, diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/roomsettings/viewmodels/NewRoomSettingsViewModel.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/roomsettings/viewmodels/NewRoomSettingsViewModel.kt index 23a7b88..cc48d63 100644 --- a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/roomsettings/viewmodels/NewRoomSettingsViewModel.kt +++ b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/roomsettings/viewmodels/NewRoomSettingsViewModel.kt @@ -38,7 +38,7 @@ constructor(private val feelBeatApi: FeelBeatApi, private val errorReceiver: Err _loading.value = true try { - val roomId = feelBeatApi.createRoom(roomSettings.value) + val roomId = feelBeatApi.createRoom(roomSettings.value.toCreateRoomPayload()) _roomCreated.emit(roomId) } catch (e: FeelBeatException) { errorReceiver.submitError(e) diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/roomsettings/viewmodels/RoomSettingsViewModel.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/roomsettings/viewmodels/RoomSettingsViewModel.kt index 8b8fb80..2315a0a 100644 --- a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/roomsettings/viewmodels/RoomSettingsViewModel.kt +++ b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/roomsettings/viewmodels/RoomSettingsViewModel.kt @@ -1,7 +1,7 @@ package com.github.feelbeatapp.androidclient.ui.app.roomsettings.viewmodels import androidx.lifecycle.ViewModel -import com.github.feelbeatapp.androidclient.ui.app.model.RoomSettings +import com.github.feelbeatapp.androidclient.ui.app.uimodel.RoomSettings import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/uimodel/Player.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/uimodel/Player.kt new file mode 100644 index 0000000..3bd9c3f --- /dev/null +++ b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/uimodel/Player.kt @@ -0,0 +1,3 @@ +package com.github.feelbeatapp.androidclient.ui.app.uimodel + +data class Player(val name: String, val image: Int) diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/model/PlayerWithResult.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/uimodel/PlayerWithResult.kt similarity index 74% rename from app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/model/PlayerWithResult.kt rename to app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/uimodel/PlayerWithResult.kt index 91d1ec5..8100ba5 100644 --- a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/model/PlayerWithResult.kt +++ b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/uimodel/PlayerWithResult.kt @@ -1,4 +1,4 @@ -package com.github.feelbeatapp.androidclient.ui.app.model +package com.github.feelbeatapp.androidclient.ui.app.uimodel import com.github.feelbeatapp.androidclient.ui.app.game.guesssong.ResultStatus diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/model/Playlist.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/uimodel/Playlist.kt similarity index 50% rename from app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/model/Playlist.kt rename to app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/uimodel/Playlist.kt index a2b21be..c6cf8d8 100644 --- a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/model/Playlist.kt +++ b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/uimodel/Playlist.kt @@ -1,3 +1,3 @@ -package com.github.feelbeatapp.androidclient.ui.app.model +package com.github.feelbeatapp.androidclient.ui.app.uimodel data class Playlist(val name: String, val songs: List) diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/model/Room.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/uimodel/Room.kt similarity index 73% rename from app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/model/Room.kt rename to app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/uimodel/Room.kt index c9c762c..c2795d4 100644 --- a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/model/Room.kt +++ b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/uimodel/Room.kt @@ -1,4 +1,4 @@ -package com.github.feelbeatapp.androidclient.ui.app.model +package com.github.feelbeatapp.androidclient.ui.app.uimodel data class Room( val id: Int, diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/uimodel/RoomSettings.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/uimodel/RoomSettings.kt new file mode 100644 index 0000000..3719d01 --- /dev/null +++ b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/uimodel/RoomSettings.kt @@ -0,0 +1,24 @@ +package com.github.feelbeatapp.androidclient.ui.app.uimodel + +import com.github.feelbeatapp.androidclient.model.CreateRoomPayload +import io.ktor.http.Url + +data class RoomSettings( + val maxPlayers: Int, + val turnCount: Int, + val timePenaltyPerSecond: Int, + val basePoints: Int, + val incorrectGuessPenalty: Int, + val playlistLink: String, +) { + fun toCreateRoomPayload(): CreateRoomPayload { + return CreateRoomPayload( + maxPlayers = maxPlayers, + turnCount = turnCount, + timePenaltyPerSecond = timePenaltyPerSecond, + basePoints = basePoints, + incorrectGuessPenalty = incorrectGuessPenalty, + playListId = Url(playlistLink).segments.last(), + ) + } +} diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/uimodel/Song.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/uimodel/Song.kt new file mode 100644 index 0000000..a0d33f0 --- /dev/null +++ b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/app/uimodel/Song.kt @@ -0,0 +1,3 @@ +package com.github.feelbeatapp.androidclient.ui.app.uimodel + +data class Song(val id: Int, val title: String)