From f0fc06ca09abca1fedd20b7d0aa7db6a3bf90cc5 Mon Sep 17 00:00:00 2001 From: vltkv <119106723+vltkv@users.noreply.github.com> Date: Fri, 3 Jan 2025 02:02:25 +0100 Subject: [PATCH 1/5] Display player name --- app/build.gradle.kts | 4 +++ .../androidclient/auth/AuthManager.kt | 2 +- .../auth/spotify/SpotifyAuthManager.kt | 4 +-- .../ui/acceptgame/AcceptGameScreen.kt | 7 +++-- .../androidclient/ui/home/HomeScreen.kt | 31 ++++++++++++------- .../androidclient/ui/home/HomeViewModel.kt | 30 +++++++++++++++--- gradle/libs.versions.toml | 2 ++ 7 files changed, 60 insertions(+), 20 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index cbc7fbf..00a579b 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -108,6 +108,10 @@ dependencies { implementation(libs.coil.compose) implementation(libs.coil.network) + // Coil + implementation(libs.coil.kt.coil.compose) + + // ktor implementation(libs.io.ktor.client) implementation(libs.io.ktor.content.negotiation) diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/auth/AuthManager.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/auth/AuthManager.kt index 5ab89b0..567f534 100644 --- a/app/src/main/java/com/github/feelbeatapp/androidclient/auth/AuthManager.kt +++ b/app/src/main/java/com/github/feelbeatapp/androidclient/auth/AuthManager.kt @@ -17,5 +17,5 @@ interface AuthManager { suspend fun getAccessToken(): String - fun logout(ctx: Context) + fun logout() } diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/auth/spotify/SpotifyAuthManager.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/auth/spotify/SpotifyAuthManager.kt index 370de2d..682f22e 100644 --- a/app/src/main/java/com/github/feelbeatapp/androidclient/auth/spotify/SpotifyAuthManager.kt +++ b/app/src/main/java/com/github/feelbeatapp/androidclient/auth/spotify/SpotifyAuthManager.kt @@ -130,7 +130,7 @@ constructor( } private fun hasExpired(expires: Instant): Boolean { - return expires >= Instant.now() + return expires <= Instant.now() } private suspend fun refreshAccessToken() { @@ -177,7 +177,7 @@ constructor( ) } - override fun logout(ctx: Context) { + override fun logout() { try { authStorage.clearAuthData() authData = null diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/acceptgame/AcceptGameScreen.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/acceptgame/AcceptGameScreen.kt index d6d75cd..e82f163 100644 --- a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/acceptgame/AcceptGameScreen.kt +++ b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/acceptgame/AcceptGameScreen.kt @@ -10,6 +10,7 @@ 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.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons @@ -33,8 +34,8 @@ import androidx.compose.ui.unit.dp import androidx.navigation.NavController import androidx.navigation.compose.rememberNavController import com.github.feelbeatapp.androidclient.R -import com.github.feelbeatapp.androidclient.ui.FeelBeatRoute import com.github.feelbeatapp.androidclient.model.Song +import com.github.feelbeatapp.androidclient.ui.FeelBeatRoute import com.github.feelbeatapp.androidclient.ui.startgame.PlayerCard @Composable @@ -53,10 +54,12 @@ fun AcceptGameScreen( .verticalScroll(rememberScrollState()), horizontalAlignment = Alignment.CenterHorizontally, ) { - IconButton(onClick = { navController.navigate(FeelBeatRoute.ACCEPT_GAME.name) }) { + Spacer(modifier = Modifier.height(24.dp)) + IconButton(onClick = { navController.navigate(FeelBeatRoute.HOME.name) }) { Icon( Icons.AutoMirrored.Filled.KeyboardArrowLeft, contentDescription = stringResource(R.string.back), + modifier = Modifier.size(40.dp), ) } diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/home/HomeScreen.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/home/HomeScreen.kt index f6ed309..917afcd 100644 --- a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/home/HomeScreen.kt +++ b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/home/HomeScreen.kt @@ -35,17 +35,20 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color -import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavController import androidx.navigation.compose.rememberNavController +import coil3.compose.AsyncImage import com.github.feelbeatapp.androidclient.R -import com.github.feelbeatapp.androidclient.ui.FeelBeatRoute import com.github.feelbeatapp.androidclient.model.Room +import com.github.feelbeatapp.androidclient.ui.FeelBeatRoute @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -57,7 +60,8 @@ fun HomeScreen( val title = stringResource(R.string.feel_beat) val rooms by viewModel.rooms.collectAsState() val selectedRoom by viewModel.selectedRoom.collectAsState() - val ctx = LocalContext.current + val playerName by viewModel.playerName.collectAsState() + val playerImageUrl by viewModel.playerImageUrl.collectAsState() var isBottomSheetVisible by remember { mutableStateOf(false) } @@ -65,10 +69,12 @@ fun HomeScreen( ModalBottomSheet(onDismissRequest = { isBottomSheetVisible = false }) { UserAccountBottomSheetContent( onLogoutClick = { - viewModel.logout(ctx) + viewModel.logout() isBottomSheetVisible = false navController.navigate(FeelBeatRoute.LOGIN.name) - } + }, + name = playerName.toString(), + imageUrl = playerImageUrl.toString(), ) } } @@ -145,7 +151,7 @@ fun HomeTopBar(title: String, onAccountClick: () -> Unit) { } @Composable -fun UserAccountBottomSheetContent(onLogoutClick: () -> Unit) { +fun UserAccountBottomSheetContent(onLogoutClick: () -> Unit, name: String, imageUrl: String) { Column( modifier = Modifier.fillMaxWidth().padding(16.dp), horizontalAlignment = Alignment.CenterHorizontally, @@ -156,13 +162,16 @@ fun UserAccountBottomSheetContent(onLogoutClick: () -> Unit) { Modifier.size(80.dp).background(Color.Gray, shape = MaterialTheme.shapes.large), contentAlignment = Alignment.Center, ) { - Text( - text = "U", // Placeholder for user's avatar - style = MaterialTheme.typography.headlineMedium, - color = Color.White, + AsyncImage( + model = imageUrl, + contentDescription = "User Avatar", + modifier = + Modifier.size(80.dp).clip(MaterialTheme.shapes.large).background(Color.Gray), + contentScale = ContentScale.Crop, + placeholder = painterResource(R.drawable.userimage), ) } - Text(text = "User Name", style = MaterialTheme.typography.titleMedium) + Text(text = name, style = MaterialTheme.typography.titleMedium) Box( modifier = Modifier.fillMaxWidth() diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/home/HomeViewModel.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/home/HomeViewModel.kt index 9ecf055..f1efcfd 100644 --- a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/home/HomeViewModel.kt +++ b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/home/HomeViewModel.kt @@ -1,10 +1,10 @@ package com.github.feelbeatapp.androidclient.ui.home -import android.content.Context import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.github.feelbeatapp.androidclient.auth.AuthManager import com.github.feelbeatapp.androidclient.model.Room +import com.github.feelbeatapp.androidclient.network.spotify.KtorSpotifyAPI import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject import kotlinx.coroutines.flow.MutableStateFlow @@ -13,19 +13,41 @@ import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch @HiltViewModel -class HomeViewModel @Inject constructor(private val authManager: AuthManager) : ViewModel() { +class HomeViewModel +@Inject +constructor(private val authManager: AuthManager, private val spotifyAPI: KtorSpotifyAPI) : + ViewModel() { private val _rooms = MutableStateFlow>(emptyList()) val rooms: StateFlow> = _rooms.asStateFlow() private val _selectedRoom = MutableStateFlow(null) val selectedRoom: StateFlow = _selectedRoom.asStateFlow() + private val _playerName = MutableStateFlow(null) + val playerName: StateFlow get() = _playerName + + private val _playerImageUrl = MutableStateFlow(null) + val playerImageUrl: StateFlow get() = _playerImageUrl + init { loadRooms() + loadPlayerData() + } + + private fun loadPlayerData() { + viewModelScope.launch { + try { + val profile = spotifyAPI.getProfile() + _playerName.value = profile.displayName + _playerImageUrl.value = profile.images.first().url + } catch (e: Exception) { + _playerName.value = "Player" + } + } } - fun logout(ctx: Context) { - authManager.logout(ctx) + fun logout() { + authManager.logout() } @SuppressWarnings("MagicNumber") diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3697e18..32b1256 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,6 @@ [versions] agp = "8.7.3" +coilCompose = "2.4.0" fuzzywuzzy = "1.4.0" kotlin = "2.0.21" coreKtx = "1.15.0" @@ -24,6 +25,7 @@ coil = "3.0.4" [libraries] androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } +coil-kt-coil-compose = { module = "io.coil-kt:coil-compose", version.ref = "coilCompose" } fuzzywuzzy = { module = "me.xdrop:fuzzywuzzy", version.ref = "fuzzywuzzy" } junit = { group = "junit", name = "junit", version.ref = "junit" } androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" } From f10ef809bc1987dd656c40b517f8268d9dcd572a Mon Sep 17 00:00:00 2001 From: vltkv <119106723+vltkv@users.noreply.github.com> Date: Fri, 3 Jan 2025 02:42:13 +0100 Subject: [PATCH 2/5] Add loading player image --- app/build.gradle.kts | 1 - .../github/feelbeatapp/androidclient/ui/home/HomeScreen.kt | 5 +++-- .../feelbeatapp/androidclient/ui/home/HomeViewModel.kt | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 00a579b..d97330f 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -111,7 +111,6 @@ dependencies { // Coil implementation(libs.coil.kt.coil.compose) - // ktor implementation(libs.io.ktor.client) implementation(libs.io.ktor.content.negotiation) diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/home/HomeScreen.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/home/HomeScreen.kt index 917afcd..ee4a159 100644 --- a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/home/HomeScreen.kt +++ b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/home/HomeScreen.kt @@ -164,11 +164,12 @@ fun UserAccountBottomSheetContent(onLogoutClick: () -> Unit, name: String, image ) { AsyncImage( model = imageUrl, - contentDescription = "User Avatar", + contentDescription = "Player Image", modifier = - Modifier.size(80.dp).clip(MaterialTheme.shapes.large).background(Color.Gray), + Modifier.size(80.dp).clip(MaterialTheme.shapes.large), contentScale = ContentScale.Crop, placeholder = painterResource(R.drawable.userimage), + error = painterResource(R.drawable.userimage), ) } Text(text = name, style = MaterialTheme.typography.titleMedium) diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/home/HomeViewModel.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/home/HomeViewModel.kt index f1efcfd..9898d98 100644 --- a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/home/HomeViewModel.kt +++ b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/home/HomeViewModel.kt @@ -41,6 +41,7 @@ constructor(private val authManager: AuthManager, private val spotifyAPI: KtorSp _playerName.value = profile.displayName _playerImageUrl.value = profile.images.first().url } catch (e: Exception) { + print(e.message) _playerName.value = "Player" } } From f7a8a29ba33b26a907c719a636428ebf46fe98fa Mon Sep 17 00:00:00 2001 From: vltkv <119106723+vltkv@users.noreply.github.com> Date: Fri, 3 Jan 2025 12:23:55 +0100 Subject: [PATCH 3/5] Display player image in topbar --- .../androidclient/ui/home/HomeScreen.kt | 22 ++++++++++++------- .../androidclient/ui/home/HomeViewModel.kt | 4 ++-- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/home/HomeScreen.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/home/HomeScreen.kt index ee4a159..9d469a4 100644 --- a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/home/HomeScreen.kt +++ b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/home/HomeScreen.kt @@ -15,7 +15,6 @@ 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.material.icons.outlined.Person import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.CenterAlignedTopAppBar @@ -79,7 +78,11 @@ fun HomeScreen( } } - Scaffold(topBar = { HomeTopBar(title) { isBottomSheetVisible = true } }) { innerPadding -> + Scaffold( + topBar = { + HomeTopBar(title, imageUrl = playerImageUrl.toString()) { isBottomSheetVisible = true } + } + ) { innerPadding -> Column(modifier = modifier.padding(innerPadding).fillMaxSize()) { Text( text = stringResource(R.string.current_games), @@ -131,7 +134,7 @@ fun HomeScreen( @OptIn(ExperimentalMaterial3Api::class) @Composable -fun HomeTopBar(title: String, onAccountClick: () -> Unit) { +fun HomeTopBar(title: String, imageUrl: String, onAccountClick: () -> Unit) { CenterAlignedTopAppBar( title = { Text(title) }, colors = @@ -141,9 +144,13 @@ fun HomeTopBar(title: String, onAccountClick: () -> Unit) { ), actions = { IconButton(onClick = onAccountClick) { - Icon( - imageVector = Icons.Outlined.Person, - contentDescription = stringResource(R.string.account), + AsyncImage( + model = imageUrl, + contentDescription = "Player Image", + modifier = Modifier.size(80.dp).clip(MaterialTheme.shapes.large), + contentScale = ContentScale.Crop, + placeholder = painterResource(R.drawable.userimage), + error = painterResource(R.drawable.userimage), ) } }, @@ -165,8 +172,7 @@ fun UserAccountBottomSheetContent(onLogoutClick: () -> Unit, name: String, image AsyncImage( model = imageUrl, contentDescription = "Player Image", - modifier = - Modifier.size(80.dp).clip(MaterialTheme.shapes.large), + modifier = Modifier.size(80.dp).clip(MaterialTheme.shapes.large), contentScale = ContentScale.Crop, placeholder = painterResource(R.drawable.userimage), error = painterResource(R.drawable.userimage), diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/home/HomeViewModel.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/home/HomeViewModel.kt index 9898d98..e884e2c 100644 --- a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/home/HomeViewModel.kt +++ b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/home/HomeViewModel.kt @@ -24,10 +24,10 @@ constructor(private val authManager: AuthManager, private val spotifyAPI: KtorSp val selectedRoom: StateFlow = _selectedRoom.asStateFlow() private val _playerName = MutableStateFlow(null) - val playerName: StateFlow get() = _playerName + val playerName: StateFlow = _playerName.asStateFlow() private val _playerImageUrl = MutableStateFlow(null) - val playerImageUrl: StateFlow get() = _playerImageUrl + val playerImageUrl: StateFlow = _playerImageUrl.asStateFlow() init { loadRooms() From da0a392bc6085aecd123f03f5ea7bb9e8ead6cf1 Mon Sep 17 00:00:00 2001 From: vltkv <119106723+vltkv@users.noreply.github.com> Date: Fri, 3 Jan 2025 14:15:43 +0100 Subject: [PATCH 4/5] Change error image --- .../androidclient/ui/home/HomeScreen.kt | 23 +++++++++++++----- app/src/main/res/drawable/account.png | Bin 0 -> 4412 bytes 2 files changed, 17 insertions(+), 6 deletions(-) create mode 100644 app/src/main/res/drawable/account.png diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/home/HomeScreen.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/home/HomeScreen.kt index 9d469a4..2a11fdc 100644 --- a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/home/HomeScreen.kt +++ b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/home/HomeScreen.kt @@ -15,6 +15,7 @@ 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.material.icons.outlined.Person import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.CenterAlignedTopAppBar @@ -36,6 +37,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource @@ -138,25 +140,34 @@ fun HomeTopBar(title: String, imageUrl: String, onAccountClick: () -> Unit) { CenterAlignedTopAppBar( title = { Text(title) }, colors = - TopAppBarDefaults.topAppBarColors( - containerColor = MaterialTheme.colorScheme.primaryContainer, - titleContentColor = MaterialTheme.colorScheme.primary, - ), + TopAppBarDefaults.topAppBarColors( + containerColor = MaterialTheme.colorScheme.primaryContainer, + titleContentColor = MaterialTheme.colorScheme.primary, + ), actions = { IconButton(onClick = onAccountClick) { AsyncImage( model = imageUrl, contentDescription = "Player Image", - modifier = Modifier.size(80.dp).clip(MaterialTheme.shapes.large), + modifier = Modifier + .size(80.dp) + .clip(MaterialTheme.shapes.large), contentScale = ContentScale.Crop, placeholder = painterResource(R.drawable.userimage), - error = painterResource(R.drawable.userimage), + error = @androidx.compose.runtime.Composable { + Icon( + imageVector = Icons.Outlined.Person, + contentDescription = stringResource(R.string.account), + modifier = Modifier.size(80.dp) + ) + } as Painter? ) } }, ) } + @Composable fun UserAccountBottomSheetContent(onLogoutClick: () -> Unit, name: String, imageUrl: String) { Column( diff --git a/app/src/main/res/drawable/account.png b/app/src/main/res/drawable/account.png new file mode 100644 index 0000000000000000000000000000000000000000..e6298a59504bf8fc27b90f9ecfce9f6c452def1e GIT binary patch literal 4412 zcmds*`8O2a`@k(jcHW8!X-FjA*=KynHlndKS;sO4Eq2)rh8b&86p~%2WW?C_nJghC z`#Mt0gt24|X&Bo_=X}rk{te&n56`{ld7gWobMC$8-skl^Pt0$_c)3Kmn3$M&jg1T} zPv`AZ+2UaTJ07n5bub56!t|Lc2QU0QRRHc#IFyO0CWZU(F59Wj>2G8o#Ka^R{8yMM zZlEwGCV>%S1E_VF)B23*1Js20=dJ4nBG>013bJ})Ag`t08E_O|tryHNQFr|C$nd=< zu-XGyEV#~c`OXMO$0HNh3`0^p_`%&VUZY}`(K16ss@_~F3tZn=GT=fAsI^^nvO~F1 zb*W#QzNJe|alyECb`|t*9uH~IwKRi*f(RnfHhFSwtRBj-Jm>XNnOQkh?l3{wc_ezG znE@h7(Gsle0xlnz{?9pwbMo>Wu3apW*1UdT?>?0Lz-!ZWYP>*%-mLn42*kgwyZY=n z=dfYdW=O$x3VWR4pn)0GcGe~;g_m!ZY**3S{G*cpNcLPC)>g_&2(g7U_}P-L`*+*w zBk>FKg$pq{s*K}f5n!+y2gees9 z2vk^}hqPa;eE&ldh9hv`+&9X4L@mW}avX`lT^&yvYJE|0K^MOBo|z*Me(uN5!kMpM zSFTq!$Z2CY99bNtVo}QS%#?m5zreH0;R3WoJHB5x0ih^on)0Y!!Vp`VNH-oAg@ z95)(Daalqq23Q8sIzK@XYu6I1B0v*-cU3!L&wN~C_>CcN-)FO>4(-#Oom3J0T`ko0 zc8I&Jgy^Mqt6N;#`|eb^g1eRgjDBtgc;`cmEZh?@oze1*&zW)AK_}#1eQfC^t_CEK zadZ#yU|`-UjKQ1xO8~z zqs2f0nx5$JC?G}U>Icy&pY2${0B7Nss7)1Cc=i=oDr>s<90U+nRQp%Gk*b{`G6!J~ zlWGO6+)G!!sh8dLj|;zRyxkF{dx<*mND*t^GU_W@5gIc{`2Ch6=zOdezLvew8aD*e z-q5Kgr%z1F^dEC_oWN2ALge`?c~U*;eOo+))Z^ z3401(X4MGWYkb0p_A*h_+D%cjVHr?#?E-?m392Kgoxu%HdINUNWs9rvMrzY*# z%0}5OSuj5^GOB;wC`S-28O*#Y-clRZ?Ho#V^)*@Q{ay&Hx+AYv(exVqF_+^X6Dv8` zK$n*cdbzXci@ubK`*uGRZO1v{u!loH@Ezgv8`oE zo1F-A7_rTfJ2AxIM45}mfXJ=a=2j=O0|J~Oo!q| zjinv>lUISb9XmdG*@pOfHWZJncM1Vt=l8mEiUrBKojryTRumt@;3K= zfmNqJYoIn~6Cuh|1-?31q}?~Rds4i6`4Mw|-KtTl?H11Oowd5ct!e1#3jBu{5p~U@ zaoyU9v7~PKh0*Ad->nCU?pw>Dn@4-O4|b_L7G;HUb&M8CVBhViUR-JI{5=3hd|;ZZ zG(=P@uqpdeKiQH^R4b%@laf#MZ#R4T-L2@v?JLd=jmb>TPYmgJAfHQSL(C5o zJC#dNx2a9KNGpb=n$4@qn>@J-!r`XIO>6AOvl7cVXFg57)gx%4cT~G;vvk$d%!6a{IJfw zyXQ=br>m9N$Ce)ttzEA@e>!F95f>b{whyd&zVbD~w;PGJZu~lMQr#A~31reGMes^dgCS`VW`zgOTV$sLF=*m&*GFs*!;+v zDy~>=BoS-4<)I}?O9Ur*!^dC*0=_u0jU=S7`yiJVtEKsxTE$5?dShOZy4b+pYMFsL z4W>?526+>ZsQ%C(M!Me(X`l<$s~qz|c~iU!7_mBCYmFYU-^NlMz2!#~xPz%WdiN`ay-2_1YM0(7m6g?am{;(sQCql3)%#AZdUVEt<=ZWiU?~D$ zqN2E>Rk7<3cPTl$M7BaA0`gwJu`tK_#iqTjG8HRDJ>GkFkWOLH>T}6$(8}46)Y#GS z@8;+W<87Lo)JrSp zBTtv*s?3<(4Y>leu@-4Ce<;wz4fW*&*DZl?V8&%3@pq7uW$%a0u4!C>-w(o9>I!kc zGS&`N{W30k%xq|8+0JH*{W`PL;*&jRC|i-Zh7l_&mG=xT#OUznzc&QmeKpBaUWFgr z@g4K&A_bp`>zMDpzf(^S2t8Tot~0e_LorsP65V-UIH%XEc&lM(zvK11RSew2S6Ax} z@{{xZ>G4CLeOt)kPWy~Eyf~?Jb3~^LsM}*>rYJl#`ajr_SMuTjugxbgseiH$bCNG; zNRZ2R&@wLv1j;v`I~0a!G!*sy`1N{jDs1q0dtqerW$N40`vK7!6`qXQMMv6#Gj@x6 zXULKF$Fd3_hDa!%onY2BehL1g)&3sM;s|fzJ+67j7*&=>1jlb)^p?LeDpr$OANx{W z5$6XjCY`ai+Vhk@>1|s#={F4 z$j@#9@KjW4t9nr0I-9s^+?V~fP0^Z4uc39kv0@K%U6!S;!FvTt!bp>g^RM%1+_hrA zwp&Va8Is@7=HNf;pr*UdzwA!U|F%ZH2~)c`V~WQ(R-8V^b19!D$BAK*>Dwah{UOq?IkcfwnU+};Amb(v8!Ca7HabtXFK6h+i@sW zB|J1YHng1Sv`7UbYI@N`q|0k1Zzj)$y`Q}sL+nSbG~GO;=~YumkK};&6Wqe&8T+Ff zU_}DYM)7henP}bj`L-c1+Q{_ku3N)pF_#>oUlf^+s;}g)??lOf^A19t3!`v#7N@8} zi94T1PO!e86ZK26lI?lz+YpZZ#91#gy=6eT!ClEKBvYxx7KGwm=|5b#zOfZ@JwojX zC5|HQ1xBsnt1A~b6{z2Y%RCFYoSH-rGk@43ZpIVbKB~1ln>u8HyO@)l5iZAvNBU)?tFAOqMqdLDb*8$ zus=zb$$VP(+#SY|c5ba_}+_aua@9p<|A0J~I(%kx4R>GTL%W)w$^E%*X^ zE0(*~7$4f3zo6LK&asj5=tVPcU-)$5lU{z}z*;<0ym^`r5yZNPZvzF$ z?na}Op8{jU|Lzkc$UE*H$)}-4b5&pcl%-zTa82ypGahW9+**cudflun1g`14OyDPW z{JT1^9N;Jw_;MKvAva?&^XFJ8}vJ2utr zoh>h+!<=)k;t%LYg(%y@C!n$|TWM`c7b!%-R7s?OwQV~V_6fKM`hSF^15 z^$Tu}tvwk`)uX?;r!yRYiJRpH(PC}~u{PnyG)79zx~I9I6g?>d_cYn#0&es$GG3teyFFVGYgdR=(^GL&SQ~u(`!=C9PUH_ zFk+(Jr$GE{PNZy+(LJPUqRkhJ<@9nYj9RQXwY?D_INwV0&;nq1NKO5ZJ<(+Lre$DC zibRSrT?tI!*z#Nymi%*yz00gOv*$;d?)SplA71Jy;0V%E_}J0}HGGiS;WL4(=tLAtQ>%|tzJ2e1bi`pr zCjHC78XSSf(|Ew?@mEAvYs24Ld$TV{_DGLnEXU|eM~l(o8dk54t6BPA+3a%!0xC<7 z>cmP1SDQ;KVL8kHa6^*~;6CDMc;R4G%U=Bm@dJxaRU>FIbH33M%@G(sKD|Lj`y8VizUZC(!4RN{+HtEfSAw9G_6~W|D|ESLBmo}13QHB! zhn32Xx3az$6ZeV_`MLXIYP1ie`glSDK#a*1_KLSnASt%~{)ZkTmMEbGEMoL3t>klgn#NGNfqn^9E zXYFjdZ!<*|R1}P^0-Ag{YLzvU_E^}k?k8{R%7ZWSK^qcIi|gtdrvDf9_W!mHkcxfB a{7)ZhwvVJusGfE_n2Zf?8&vAwiTy84_C?G9 literal 0 HcmV?d00001 From 358ee75bdefcabb70312dea3a9958fc5995a4d53 Mon Sep 17 00:00:00 2001 From: vltkv <119106723+vltkv@users.noreply.github.com> Date: Fri, 3 Jan 2025 21:32:54 +0100 Subject: [PATCH 5/5] Add internal navigation in HomeScreen --- .../androidclient/ui/FeelBeatApp.kt | 6 - .../androidclient/ui/FeelBeatRoute.kt | 1 - .../ui/acceptgame/AcceptGameScreen.kt | 14 +- .../androidclient/ui/home/HomeRoute.kt | 7 + .../androidclient/ui/home/HomeScreen.kt | 145 ++++++++++-------- .../screens/EditRoomSettingsScreen.kt | 6 +- 6 files changed, 102 insertions(+), 77 deletions(-) create mode 100644 app/src/main/java/com/github/feelbeatapp/androidclient/ui/home/HomeRoute.kt diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/FeelBeatApp.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/FeelBeatApp.kt index 02eb570..fdbc65f 100644 --- a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/FeelBeatApp.kt +++ b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/FeelBeatApp.kt @@ -37,12 +37,6 @@ fun FeelBeatApp( composable(route = FeelBeatRoute.NEW_ROOM_SETTINGS.name) { NewRoomSettingsScreen(navController = navController) } - composable(route = FeelBeatRoute.ROOM_SETTINGS.name) { - EditRoomSettingsScreen(navController = navController) - } - composable(route = FeelBeatRoute.ACCEPT_GAME.name) { - AcceptGameScreen(navController = navController) - } composable(route = FeelBeatRoute.GAME_RESULT.name) { GameResultScreen(navController = navController) } diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/FeelBeatRoute.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/FeelBeatRoute.kt index c62cac5..8e05b4e 100644 --- a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/FeelBeatRoute.kt +++ b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/FeelBeatRoute.kt @@ -6,7 +6,6 @@ enum class FeelBeatRoute { NEW_ROOM_SETTINGS, ROOM_SETTINGS, ACCEPT_GAME, - ACCOUNT_SETTINGS, GAME_RESULT, GUESS_SONG, GUESS_RESULT, diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/acceptgame/AcceptGameScreen.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/acceptgame/AcceptGameScreen.kt index e82f163..936ed73 100644 --- a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/acceptgame/AcceptGameScreen.kt +++ b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/acceptgame/AcceptGameScreen.kt @@ -36,12 +36,14 @@ import androidx.navigation.compose.rememberNavController import com.github.feelbeatapp.androidclient.R import com.github.feelbeatapp.androidclient.model.Song import com.github.feelbeatapp.androidclient.ui.FeelBeatRoute +import com.github.feelbeatapp.androidclient.ui.home.HomeRoute import com.github.feelbeatapp.androidclient.ui.startgame.PlayerCard @Composable fun AcceptGameScreen( viewModel: AcceptGameViewModel = AcceptGameViewModel(), navController: NavController, + internalNavController: NavController, isRoomCreator: Boolean = true, ) { val gameState = viewModel.gameState.collectAsState().value @@ -55,7 +57,7 @@ fun AcceptGameScreen( horizontalAlignment = Alignment.CenterHorizontally, ) { Spacer(modifier = Modifier.height(24.dp)) - IconButton(onClick = { navController.navigate(FeelBeatRoute.HOME.name) }) { + IconButton(onClick = { internalNavController.navigate(HomeRoute.HOME.name) }) { Icon( Icons.AutoMirrored.Filled.KeyboardArrowLeft, contentDescription = stringResource(R.string.back), @@ -113,7 +115,7 @@ fun AcceptGameScreen( if (isRoomCreator) { BottomNavigationBar( - navController = navController, + internalNavController = internalNavController, modifier = Modifier.align(Alignment.BottomCenter), ) } @@ -121,7 +123,7 @@ fun AcceptGameScreen( } @Composable -fun BottomNavigationBar(navController: NavController, modifier: Modifier = Modifier) { +fun BottomNavigationBar(internalNavController: NavController, modifier: Modifier = Modifier) { NavigationBar( modifier = modifier, containerColor = MaterialTheme.colorScheme.surface, @@ -133,7 +135,7 @@ fun BottomNavigationBar(navController: NavController, modifier: Modifier = Modif }, label = { Text(stringResource(R.string.selected_room)) }, selected = false, - onClick = { navController.navigate(FeelBeatRoute.ACCEPT_GAME.name) }, + onClick = { internalNavController.navigate(FeelBeatRoute.ACCEPT_GAME.name) }, ) NavigationBarItem( icon = { @@ -141,7 +143,7 @@ fun BottomNavigationBar(navController: NavController, modifier: Modifier = Modif }, label = { Text(stringResource(R.string.settings)) }, selected = false, - onClick = { navController.navigate(FeelBeatRoute.ROOM_SETTINGS.name) }, + onClick = { internalNavController.navigate(FeelBeatRoute.ROOM_SETTINGS.name) }, ) } } @@ -164,5 +166,5 @@ fun SongItem(song: Song) { @Composable fun PreviewAcceptScreen() { val navController = rememberNavController() - AcceptGameScreen(navController = navController) + AcceptGameScreen(navController = navController, internalNavController = navController) } diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/home/HomeRoute.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/home/HomeRoute.kt new file mode 100644 index 0000000..3e2bd53 --- /dev/null +++ b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/home/HomeRoute.kt @@ -0,0 +1,7 @@ +package com.github.feelbeatapp.androidclient.ui.home + +enum class HomeRoute { + HOME, + ROOM_SETTINGS, + ACCEPT_GAME, +} diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/home/HomeScreen.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/home/HomeScreen.kt index 2a11fdc..bba6293 100644 --- a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/home/HomeScreen.kt +++ b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/home/HomeScreen.kt @@ -15,7 +15,6 @@ 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.material.icons.outlined.Person import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.CenterAlignedTopAppBar @@ -37,7 +36,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource @@ -45,11 +43,15 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavController +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import coil3.compose.AsyncImage import com.github.feelbeatapp.androidclient.R import com.github.feelbeatapp.androidclient.model.Room import com.github.feelbeatapp.androidclient.ui.FeelBeatRoute +import com.github.feelbeatapp.androidclient.ui.acceptgame.AcceptGameScreen +import com.github.feelbeatapp.androidclient.ui.roomsettings.screens.EditRoomSettingsScreen @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -59,10 +61,9 @@ fun HomeScreen( navController: NavController, ) { val title = stringResource(R.string.feel_beat) - val rooms by viewModel.rooms.collectAsState() - val selectedRoom by viewModel.selectedRoom.collectAsState() val playerName by viewModel.playerName.collectAsState() val playerImageUrl by viewModel.playerImageUrl.collectAsState() + val internalNavController = rememberNavController() var isBottomSheetVisible by remember { mutableStateOf(false) } @@ -86,48 +87,22 @@ fun HomeScreen( } ) { innerPadding -> Column(modifier = modifier.padding(innerPadding).fillMaxSize()) { - Text( - text = stringResource(R.string.current_games), - style = MaterialTheme.typography.titleMedium, - modifier = Modifier.padding(16.dp), - ) - LazyColumn( - modifier = Modifier.weight(1f).fillMaxWidth().padding(horizontal = 16.dp), - verticalArrangement = Arrangement.spacedBy(8.dp), - ) { - items(rooms) { room -> - RoomItem( - room = room, - isSelected = room == selectedRoom, - onClick = { navController.navigate(FeelBeatRoute.ACCEPT_GAME.name) }, + NavHost(internalNavController, startDestination = HomeRoute.HOME.name) { + composable(route = HomeRoute.HOME.name) { + HomeBody( + viewModel = viewModel, + internalNavController = internalNavController, + navController = navController, ) } - } - - Box( - modifier = - Modifier.fillMaxWidth().padding(bottom = 80.dp, start = 16.dp, end = 16.dp) - ) { - Box( - modifier = - Modifier.align(Alignment.BottomEnd) - .size(60.dp) - .background( - MaterialTheme.colorScheme.primary, - shape = MaterialTheme.shapes.medium, - ) - ) { - IconButton( - onClick = { navController.navigate(FeelBeatRoute.NEW_ROOM_SETTINGS.name) }, - modifier = Modifier.fillMaxSize(), - ) { - Icon( - imageVector = Icons.Default.Add, - contentDescription = "Add", - modifier = Modifier.size(36.dp), - tint = MaterialTheme.colorScheme.onPrimary, - ) - } + composable(route = HomeRoute.ACCEPT_GAME.name) { + AcceptGameScreen( + internalNavController = internalNavController, + navController = navController, + ) + } + composable(route = HomeRoute.ROOM_SETTINGS.name) { + EditRoomSettingsScreen(internalNavController = internalNavController) } } } @@ -140,33 +115,81 @@ fun HomeTopBar(title: String, imageUrl: String, onAccountClick: () -> Unit) { CenterAlignedTopAppBar( title = { Text(title) }, colors = - TopAppBarDefaults.topAppBarColors( - containerColor = MaterialTheme.colorScheme.primaryContainer, - titleContentColor = MaterialTheme.colorScheme.primary, - ), + TopAppBarDefaults.topAppBarColors( + containerColor = MaterialTheme.colorScheme.primaryContainer, + titleContentColor = MaterialTheme.colorScheme.primary, + ), actions = { IconButton(onClick = onAccountClick) { AsyncImage( model = imageUrl, contentDescription = "Player Image", - modifier = Modifier - .size(80.dp) - .clip(MaterialTheme.shapes.large), + modifier = Modifier.size(80.dp).clip(MaterialTheme.shapes.large), contentScale = ContentScale.Crop, - placeholder = painterResource(R.drawable.userimage), - error = @androidx.compose.runtime.Composable { - Icon( - imageVector = Icons.Outlined.Person, - contentDescription = stringResource(R.string.account), - modifier = Modifier.size(80.dp) - ) - } as Painter? + placeholder = painterResource(R.drawable.account), + error = painterResource(R.drawable.account), ) } }, ) } +@Composable +fun HomeBody( + viewModel: HomeViewModel, + navController: NavController, + internalNavController: NavController, +) { + val rooms by viewModel.rooms.collectAsState() + val selectedRoom by viewModel.selectedRoom.collectAsState() + + Column(modifier = Modifier.fillMaxSize()) { + Text( + text = stringResource(R.string.current_games), + 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, + isSelected = room == selectedRoom, + onClick = { internalNavController.navigate(FeelBeatRoute.ACCEPT_GAME.name) }, + ) + } + } + + Box( + modifier = Modifier.fillMaxWidth().padding(bottom = 16.dp).padding(horizontal = 16.dp) + ) { + Box( + modifier = + Modifier.align(Alignment.BottomEnd) + .size(60.dp) + .background( + MaterialTheme.colorScheme.primary, + shape = MaterialTheme.shapes.medium, + ) + ) { + IconButton( + onClick = { navController.navigate(FeelBeatRoute.NEW_ROOM_SETTINGS.name) }, + modifier = Modifier.fillMaxSize(), + ) { + Icon( + imageVector = Icons.Default.Add, + contentDescription = "Add", + modifier = Modifier.size(36.dp), + tint = MaterialTheme.colorScheme.onPrimary, + ) + } + } + } + } +} @Composable fun UserAccountBottomSheetContent(onLogoutClick: () -> Unit, name: String, imageUrl: String) { @@ -185,8 +208,8 @@ fun UserAccountBottomSheetContent(onLogoutClick: () -> Unit, name: String, image contentDescription = "Player Image", modifier = Modifier.size(80.dp).clip(MaterialTheme.shapes.large), contentScale = ContentScale.Crop, - placeholder = painterResource(R.drawable.userimage), - error = painterResource(R.drawable.userimage), + placeholder = painterResource(R.drawable.account), + error = painterResource(R.drawable.account), ) } Text(text = name, style = MaterialTheme.typography.titleMedium) diff --git a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/roomsettings/screens/EditRoomSettingsScreen.kt b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/roomsettings/screens/EditRoomSettingsScreen.kt index 67cb905..31373ca 100644 --- a/app/src/main/java/com/github/feelbeatapp/androidclient/ui/roomsettings/screens/EditRoomSettingsScreen.kt +++ b/app/src/main/java/com/github/feelbeatapp/androidclient/ui/roomsettings/screens/EditRoomSettingsScreen.kt @@ -34,7 +34,7 @@ import com.github.feelbeatapp.androidclient.ui.roomsettings.viewmodels.RoomSetti @Composable fun EditRoomSettingsScreen( viewModel: RoomSettingsViewModel = EditRoomSettingsViewModel(), - navController: NavController, + internalNavController: NavController, modifier: Modifier = Modifier, isRoomCreator: Boolean = true, ) { @@ -43,7 +43,7 @@ fun EditRoomSettingsScreen( Scaffold( bottomBar = { if (isRoomCreator) { - BottomNavigationBar(navController = navController) + BottomNavigationBar(navController = internalNavController) } }, content = { padding -> @@ -100,5 +100,5 @@ fun BottomNavigationBar(navController: NavController, modifier: Modifier = Modif @Composable fun PreviewRoomSettingsScreen() { val navController = rememberNavController() - EditRoomSettingsScreen(navController = navController) + EditRoomSettingsScreen(internalNavController = navController) }