Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ dependencies {
implementation(libs.io.ktor.client)
implementation(libs.io.ktor.content.negotiation)
implementation(libs.io.ktor.json.serialization)
implementation(libs.fuzzywuzzy)

// hilt
implementation(libs.hilt)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ 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.ui.state.Song
import com.github.feelbeatapp.androidclient.ui.startGame.PlayerCard

@Composable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,15 @@ package com.github.feelbeatapp.androidclient.ui.acceptGame
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.github.feelbeatapp.androidclient.R
import com.github.feelbeatapp.androidclient.ui.home.Room
import com.github.feelbeatapp.androidclient.ui.startGame.Player
import com.github.feelbeatapp.androidclient.ui.state.GameState
import com.github.feelbeatapp.androidclient.ui.state.Player
import com.github.feelbeatapp.androidclient.ui.state.Song
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch

data class Song(val id: Int, val title: String)

data class Playlist(val name: String, val songs: List<Song>)

data class GameState(
val players: List<Player> = emptyList(),
val songs: List<Song> = emptyList(),
val selectedRoom: Room? = null,
val playlist: Playlist = Playlist(name = "Playlist #1", songs = emptyList()),
val snippetDuration: Int = 30,
val pointsToWin: Int = 10,
)

class AcceptGameViewModel : ViewModel() {
private val _gameState = MutableStateFlow(GameState())
val gameState: StateFlow<GameState> = _gameState.asStateFlow()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ 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.ui.guessSong.PlayerWithResult
import com.github.feelbeatapp.androidclient.ui.state.PlayerWithResult

@Composable
fun GameResultScreen(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ package com.github.feelbeatapp.androidclient.ui.gameResult
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.github.feelbeatapp.androidclient.R
import com.github.feelbeatapp.androidclient.ui.guessSong.PlayerWithResult
import com.github.feelbeatapp.androidclient.ui.state.Player
import com.github.feelbeatapp.androidclient.ui.state.PlayerWithResult
import com.github.feelbeatapp.androidclient.ui.guessSong.ResultStatus
import com.github.feelbeatapp.androidclient.ui.startGame.Player
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ fun GuessResultScreen(
if (guessState.players.any { it.resultStatus == ResultStatus.CORRECT }) {
stringResource(R.string.you_guessed_song_correctly)
} else {
stringResource(R.string.ups_that_s_not_correct)
stringResource(R.string.ups_that_s_not_correct_answer)
},
style = MaterialTheme.typography.headlineLarge,
fontWeight = FontWeight.Bold,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,8 @@ import androidx.compose.material3.Slider
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
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
Expand All @@ -45,8 +41,8 @@ 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.ui.acceptGame.Song
import kotlinx.coroutines.delay
import com.github.feelbeatapp.androidclient.ui.state.PlayerWithResult
import com.github.feelbeatapp.androidclient.ui.state.Song

@OptIn(ExperimentalMaterial3Api::class)
@Composable
Expand All @@ -55,15 +51,11 @@ fun GuessSongScreen(
viewModel: GuessSongViewModel = GuessSongViewModel(),
) {
val guessState by viewModel.guessState.collectAsState()
var timeLeft by remember { mutableIntStateOf(guessState.snippetDuration) }
val timeLeft by viewModel.timeLeft.collectAsState()
val gameEnded by viewModel.gameEnded.collectAsState()

LaunchedEffect(key1 = timeLeft) {
if (timeLeft > 0) {
delay(timeMillis = 1000)
timeLeft -= 1
} else {
navController.navigate(FeelBeatRoute.GUESS_RESULT.name)
}
if (gameEnded) {
navController.navigate(FeelBeatRoute.GUESS_RESULT.name)
}

Scaffold(
Expand Down Expand Up @@ -111,9 +103,9 @@ fun GuessSongScreen(
verticalArrangement = Arrangement.spacedBy(8.dp),
modifier = Modifier.fillMaxSize(),
) {
items(guessState.songs.size) { index ->
items(guessState.filteredSongs.size) { index ->
SongItem(
song = guessState.songs[index],
song = guessState.filteredSongs[index],
onClick = { navController.navigate(FeelBeatRoute.GUESS_RESULT.name) },
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,31 @@ 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.acceptGame.Playlist
import com.github.feelbeatapp.androidclient.ui.acceptGame.Song
import com.github.feelbeatapp.androidclient.ui.home.Room
import com.github.feelbeatapp.androidclient.ui.startGame.Player
import com.github.feelbeatapp.androidclient.ui.state.GuessState
import com.github.feelbeatapp.androidclient.ui.state.Player
import com.github.feelbeatapp.androidclient.ui.state.PlayerWithResult
import com.github.feelbeatapp.androidclient.ui.state.Song
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch

data class PlayerWithResult(val player: Player, val resultStatus: ResultStatus, val points: Int)

data class GuessState(
val players: List<PlayerWithResult> = emptyList(),
val songs: List<Song> = emptyList(),
val selectedRoom: Room? = null,
val playlist: Playlist = Playlist(name = "Playlist #1", songs = emptyList()),
val snippetDuration: Int = 30,
val pointsToWin: Int = 10,
val searchQuery: TextFieldValue = TextFieldValue(""),
val currentSong: Song? = null,
)
import me.xdrop.fuzzywuzzy.FuzzySearch

class GuessSongViewModel : ViewModel() {
private val _guessState = MutableStateFlow(GuessState())
val guessState: StateFlow<GuessState> = _guessState.asStateFlow()

private val _timeLeft = MutableStateFlow(_guessState.value.snippetDuration)
val timeLeft: StateFlow<Int> = _timeLeft.asStateFlow()

private val _gameEnded = MutableStateFlow(false)
val gameEnded: StateFlow<Boolean> = _gameEnded.asStateFlow()

init {
loadPlayers()
loadPlaylist()
startTimer()
}

private fun loadPlayers() {
Expand Down Expand Up @@ -64,20 +60,53 @@ class GuessSongViewModel : ViewModel() {
viewModelScope.launch {
val examplePlaylist =
listOf(
Song(1, "Song 1"),
Song(2, "Song 2"),
Song(3, "Song 3"),
Song(4, "Song 4"),
Song(5, "Song 5"),
Song(6, "Song 6"),
Song(1, "Hello"),
Song(2, "Highway to Hell"),
Song(3, "Hell's Comin' with Me"),
Song(4, "Riptide"),
Song(5, "Rozmowa"),
Song(6, "Rower"),
Song(7, "R"),
Song(8, "Róż"),
Song(9, "Rota"),
Song(10, "Szarość i Róż"),
)
_guessState.value =
_guessState.value.copy(songs = examplePlaylist, currentSong = examplePlaylist[0])
_guessState.value.copy(
songs = examplePlaylist,
filteredSongs = examplePlaylist,
currentSong = examplePlaylist[0],
)
}
}

@SuppressWarnings("MagicNumber")
private fun startTimer() {
viewModelScope.launch {
while (_timeLeft.value > 0) {
delay(1000L)
_timeLeft.emit(_timeLeft.value - 1)
}
_gameEnded.value = true
}
}

fun updateSearchQuery(newQuery: TextFieldValue) {
_guessState.value = _guessState.value.copy(searchQuery = newQuery)
fun updateSearchQuery(query: TextFieldValue) {
_guessState.value = _guessState.value.copy(searchQuery = query)
performSearch(query.text)
}

@SuppressWarnings("MagicNumber")
private fun performSearch(query: String) {
val sortedList =
if (query.isBlank()) {
_guessState.value.songs
} else {
_guessState.value.songs.sortedByDescending { song ->
FuzzySearch.ratio(song.title.lowercase(), query.lowercase())
}
}
_guessState.value = _guessState.value.copy(filteredSongs = sortedList)
}

fun submitAnswer(playerName: String, isCorrect: Boolean) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ 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.ui.state.Room

@Composable
fun HomeScreen(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,12 @@ package com.github.feelbeatapp.androidclient.ui.home

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.github.feelbeatapp.androidclient.ui.state.Room
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch

data class Room(
val id: Int,
val name: String,
val maxPlayers: Int,
val snippetDuration: Int,
val pointsToWin: Int,
val playlistLink: String,
)

class HomeViewModel : ViewModel() {

private val _rooms = MutableStateFlow<List<Room>>(emptyList())
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.github.feelbeatapp.androidclient.ui.roomSettings

import androidx.lifecycle.ViewModel
import com.github.feelbeatapp.androidclient.ui.home.Room
import com.github.feelbeatapp.androidclient.ui.state.Room
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ 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.ui.state.Player

@Composable
fun StartGameScreen(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@ package com.github.feelbeatapp.androidclient.ui.startGame
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.github.feelbeatapp.androidclient.R
import com.github.feelbeatapp.androidclient.ui.state.Player
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch

data class Player(val name: String, val image: Int)

class StartGameViewModel : ViewModel() {
private val _players = MutableStateFlow<List<Player>>(emptyList())
val players: StateFlow<List<Player>> = _players.asStateFlow()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.github.feelbeatapp.androidclient.ui.state

data class GameState(
val players: List<Player> = emptyList(),
val songs: List<Song> = emptyList(),
val selectedRoom: Room? = null,
val playlist: Playlist = Playlist(name = "Playlist #1", songs = emptyList()),
val snippetDuration: Int = 30,
val pointsToWin: Int = 10,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.github.feelbeatapp.androidclient.ui.state

import androidx.compose.ui.text.input.TextFieldValue

data class GuessState(
val players: List<PlayerWithResult> = emptyList(),
val songs: List<Song> = emptyList(),
val filteredSongs: List<Song> = emptyList(),
val selectedRoom: Room? = null,
val playlist: Playlist = Playlist(name = "Playlist #1", songs = emptyList()),
val snippetDuration: Int = 30,
val pointsToWin: Int = 10,
val searchQuery: TextFieldValue = TextFieldValue(""),
val currentSong: Song? = null,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.github.feelbeatapp.androidclient.ui.state

data class Player(val name: String, val image: Int)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.github.feelbeatapp.androidclient.ui.state

import com.github.feelbeatapp.androidclient.ui.guessSong.ResultStatus

data class PlayerWithResult(val player: Player, val resultStatus: ResultStatus, val points: Int)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.github.feelbeatapp.androidclient.ui.state

data class Playlist(val name: String, val songs: List<Song>)
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.github.feelbeatapp.androidclient.ui.state

data class Room(
val id: Int,
val name: String,
val maxPlayers: Int,
val snippetDuration: Int,
val pointsToWin: Int,
val playlistLink: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.github.feelbeatapp.androidclient.ui.state

data class Song(val id: Int, val title: String)
2 changes: 1 addition & 1 deletion app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
<string name="save_settings">Save Settings</string>
<string name="room_settings">Room Settings</string>
<string name="you_guessed_song_correctly">You guessed song correctly!</string>
<string name="ups_that_s_not_correct">Ups, that\'s not correct</string>
<string name="ups_that_s_not_correct_answer">Ups, that\'s not correct answer</string>
<string name="time_left">time left</string>
<string name="authorization_server_unreachable">Authorization server is unreachable</string>
</resources>
2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
[versions]
agp = "8.7.3"
fuzzywuzzy = "1.4.0"
kotlin = "2.0.21"
coreKtx = "1.15.0"
junit = "4.13.2"
Expand All @@ -23,6 +24,7 @@ coil = "3.0.4"

[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
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" }
mockk = { group = "io.mockk", name = "mockk", version.ref = "mockk" }
Expand Down
Loading