Skip to content

Commit

Permalink
Using Id value class for Match entity.
Browse files Browse the repository at this point in the history
  • Loading branch information
AdamMc331 committed Jul 22, 2023
1 parent d80e459 commit 1759043
Show file tree
Hide file tree
Showing 30 changed files with 66 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.adammcneilly.pocketleague.core.models.Match
import com.adammcneilly.pocketleague.shared.screens.eventstagedetail.EventStageDetailViewState
import com.adammcneilly.tournament.bracket.displaymodels.BracketDisplayModel
import com.adammcneilly.tournament.bracket.displaymodels.BracketMatchDisplayModel
Expand All @@ -18,7 +19,7 @@ import com.adammcneilly.tournament.bracket.ui.MultiEliminationBracket
@Composable
fun EventStageDetailContent(
viewState: EventStageDetailViewState,
onMatchClicked: (String) -> Unit,
onMatchClicked: (Match.Id) -> Unit,
modifier: Modifier = Modifier,
) {
val brackets = viewState.getBracket()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import com.adammcneilly.pocketleague.android.designsystem.matches.RecentMatchesE
import com.adammcneilly.pocketleague.core.displaymodels.EventSummaryDisplayModel
import com.adammcneilly.pocketleague.core.displaymodels.MatchDetailDisplayModel
import com.adammcneilly.pocketleague.core.models.Event
import com.adammcneilly.pocketleague.core.models.Match
import com.adammcneilly.pocketleague.feature.feed.FeedViewState
import com.adammcneilly.pocketleague.shared.ui.match.MatchCarousel
import com.adammcneilly.pocketleague.ui.composables.eventsummary.EventSummaryListItem
Expand All @@ -33,7 +34,7 @@ import com.adammcneilly.pocketleague.ui.composables.eventsummary.EventSummaryLis
fun FeedContent(
viewState: FeedViewState,
modifier: Modifier = Modifier,
onMatchClicked: (String) -> Unit = {},
onMatchClicked: (Match.Id) -> Unit = {},
onEventClicked: (Event.Id) -> Unit = {},
) {
Box(
Expand All @@ -50,7 +51,7 @@ fun FeedContent(
@Composable
private fun SuccessContent(
viewState: FeedViewState,
onMatchClicked: (String) -> Unit,
onMatchClicked: (Match.Id) -> Unit,
onEventClicked: (Event.Id) -> Unit,
) {
LazyColumn(
Expand Down Expand Up @@ -112,7 +113,7 @@ private fun FeedSectionTitle(
@Composable
private fun RecentMatchesSection(
recentMatches: List<MatchDetailDisplayModel>,
onMatchClicked: (String) -> Unit,
onMatchClicked: (Match.Id) -> Unit,
) {
if (recentMatches.isNotEmpty()) {
MatchCarousel(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ private const val MATCH_TIME_FORMAT = "HH:mm"
* User friendly presentation of detailed info about a match between two teams.
*/
data class MatchDetailDisplayModel(
val matchId: String,
val matchId: Match.Id,
val localDate: String,
val localTime: String,
val eventName: String,
Expand All @@ -28,7 +28,7 @@ data class MatchDetailDisplayModel(

companion object {
val placeholder = MatchDetailDisplayModel(
matchId = "",
matchId = Match.Id(""),
localDate = "",
localTime = "",
eventName = "",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import com.adammcneilly.pocketleague.core.models.StageRound

val TestModel.matchBlueWinner: Match
get() = Match(
id = "1234",
id = Match.Id("1234"),
event = TestModel.event,
dateUTC = null,
blueTeam = TestModel.matchTeamResultWinner,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package com.adammcneilly.pocketleague.core.models

import kotlin.jvm.JvmInline

/**
* A [Match] is any competition between two teams. Could be a single game, a series,
* or even a best of set.
*/
data class Match(
val id: String,
val id: Id,
val event: Event,
val dateUTC: String?,
val blueTeam: MatchTeamResult,
Expand All @@ -14,4 +16,14 @@ data class Match(
val format: Format,
val gameOverviews: List<GameOverview>,
val round: StageRound,
)
) {

/**
* This value class ensures we can have type safety anywhere we plan to use a
* string identifier for a match.
*/
@JvmInline
value class Id(
val id: String,
)
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.adammcneilly.pocketleague.data.game

import com.adammcneilly.pocketleague.core.models.Match

/**
* Used to request a list of games for the given [matchId].
*/
data class MatchGamesRequest(
val matchId: String,
val matchId: Match.Id,
)
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import com.adammcneilly.pocketleague.sqldelight.LocalMatch

fun Match.toLocalMatch(): LocalMatch {
return LocalMatch(
id = this.id,
id = this.id.id,
dateUTC = this.dateUTC,
eventId = this.event.id,
eventId = this.event.id.id,
blueTeamId = this.blueTeam.team.id,
orangeTeamId = this.orangeTeam.team.id,
blueTeamGameWins = this.blueTeam.score.toLong(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ fun MatchWithEventAndTeams.toMatch(): Match {
val orangeTeamWinner = orangeTeamGameWins > blueTeamGameWins

return Match(
id = this.localMatchId,
id = Match.Id(this.localMatchId),
event = mapEvent(),
dateUTC = this.localMatchDateUTC,
blueTeam = mapBlueTeamResult(blueTeamGameWins, blueTeamWinner),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class FakeMatchRepository : MatchRepository {

lateinit var upcomingMatches: List<Match>

override fun getMatchDetail(matchId: String): Flow<Match> {
override fun getMatchDetail(matchId: Match.Id): Flow<Match> {
return flowOf(matchDetailsById[matchId]!!)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class FakeMatchService : MatchService {
)

override suspend fun fetchMatchDetail(
matchId: String,
matchId: Match.Id,
): Result<Match> {
return matchDetailResponse
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ interface LocalMatchService {
* Fetches detailed information about a [Match] using the supplied [matchId].
*/
fun getMatchDetail(
matchId: String,
matchId: Match.Id,
): Flow<Match>

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ interface MatchRepository {
* Fetches detailed information about a [Match] using the supplied [matchId].
*/
fun getMatchDetail(
matchId: String,
matchId: Match.Id,
): Flow<Match>

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ interface MatchService {
* Fetches detailed information about a [Match] using the supplied [matchId].
*/
suspend fun fetchMatchDetail(
matchId: String,
matchId: Match.Id,
): Result<Match>

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class OctaneGGMatchService(

constructor() : this(OctaneGGAPIClient, defaultClock())

override suspend fun getMatchDetail(matchId: String): Result<Match> {
override suspend fun getMatchDetail(matchId: Match.Id): Result<Match> {
return apiClient.getResponse<OctaneGGMatch>(
endpoint = "$MATCHES_ENDPOINT/$matchId",
).map { octaneMatch ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ class OfflineFirstMatchRepository(
private val remoteDataSource: RemoteMatchService,
) : MatchRepository {

override fun getMatchDetail(matchId: String): Flow<Match> {
override fun getMatchDetail(matchId: Match.Id): Flow<Match> {
return localDataSource
.getMatchDetail(matchId)
.onStart {
fetchAndPersistMatchDetail(matchId)
}
}

private suspend fun fetchAndPersistMatchDetail(matchId: String) {
private suspend fun fetchAndPersistMatchDetail(matchId: Match.Id) {
val remoteResponse = remoteDataSource.getMatchDetail(matchId)

remoteResponse.fold(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ interface RemoteMatchService {
* Fetches detailed information about a [Match] using the supplied [matchId].
*/
suspend fun getMatchDetail(
matchId: String,
matchId: Match.Id,
): Result<Match>

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ class SQLDelightMatchService(
private val database: PocketLeagueDB,
) : LocalMatchService {

override fun getMatchDetail(matchId: String): Flow<Match> {
override fun getMatchDetail(matchId: Match.Id): Flow<Match> {
return database
.localMatchQueries
.selectById(matchId)
.selectById(matchId.id)
.asFlowSingle(MatchWithEventAndTeams::toMatch)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ data class OctaneGGMatch(
*/
fun OctaneGGMatch.toMatch(): Match {
return Match(
id = this.id.orEmpty(),
id = Match.Id(this.id.orEmpty()),
event = this.event.toEvent(),
dateUTC = this.dateUTC,
blueTeam = this.blue.toMatchTeamResult(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ fun SetFragment.toMatch(): Match {
val blueTeamWins = this.games?.size?.minus(orangeTeamWins) ?: 0

return Match(
id = this.id.orEmpty(),
id = Match.Id(this.id.orEmpty()),
event = this.event?.tournament?.tournamentFragment?.toEvent()!!,
dateUTC = startDateUTC,
blueTeam = blueSlot.toMatchTeamResult(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ class FeedPresenter(
}

is FeedScreen.Event.MatchClicked -> {
navigator.goTo(MatchDetailScreen(event.matchId))
navigator.goTo(MatchDetailScreen(event.matchId.id))
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.adammcneilly.pocketleague.shared.app.feed
import com.adammcneilly.pocketleague.core.displaymodels.EventGroupDisplayModel
import com.adammcneilly.pocketleague.core.displaymodels.MatchDetailDisplayModel
import com.adammcneilly.pocketleague.core.models.Event
import com.adammcneilly.pocketleague.core.models.Match
import com.adammcneilly.pocketleague.shared.app.CommonParcelize
import com.adammcneilly.pocketleague.shared.ui.feed.FeedContent
import com.slack.circuit.runtime.CircuitContext
Expand Down Expand Up @@ -46,7 +47,7 @@ object FeedScreen : Screen {
* User tapped on a match item.
*/
data class MatchClicked(
val matchId: String,
val matchId: Match.Id,
) : Event
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import com.adammcneilly.pocketleague.core.displaymodels.GameDetailDisplayModel
import com.adammcneilly.pocketleague.core.displaymodels.MatchDetailDisplayModel
import com.adammcneilly.pocketleague.core.displaymodels.toDetailDisplayModel
import com.adammcneilly.pocketleague.core.models.Game
import com.adammcneilly.pocketleague.core.models.Match
import com.adammcneilly.pocketleague.data.game.MatchGamesRequest
import com.adammcneilly.pocketleague.data.game.OctaneGGGameService
import com.adammcneilly.pocketleague.data.match.OctaneGGMatchService
Expand All @@ -19,7 +20,7 @@ import com.slack.circuit.runtime.presenter.Presenter
* State management container for the [MatchDetailScreen].
*/
class MatchDetailPresenter(
private val matchId: String,
private val matchId: Match.Id,
) : Presenter<MatchDetailScreen.State> {

@Composable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.adammcneilly.pocketleague.shared.app.match

import com.adammcneilly.pocketleague.core.displaymodels.GameDetailDisplayModel
import com.adammcneilly.pocketleague.core.displaymodels.MatchDetailDisplayModel
import com.adammcneilly.pocketleague.core.models.Match
import com.adammcneilly.pocketleague.shared.app.CommonParcelize
import com.adammcneilly.pocketleague.shared.ui.match.MatchDetailContent
import com.slack.circuit.runtime.CircuitContext
Expand All @@ -15,6 +16,8 @@ import com.slack.circuit.runtime.ui.ui

/**
* Shows detailed match information for a match with a given [matchId].
*
* Need to use a string until we can upgrade Kotlin: https://stackoverflow.com/a/75857372/3131147
*/
@CommonParcelize
data class MatchDetailScreen(
Expand Down Expand Up @@ -83,7 +86,7 @@ data class MatchDetailScreen(
override fun create(screen: Screen, navigator: Navigator, context: CircuitContext): Presenter<*>? {
return when (screen) {
is MatchDetailScreen -> MatchDetailPresenter(
matchId = screen.matchId,
matchId = Match.Id(screen.matchId),
)

else -> null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.adammcneilly.pocketleague.shared.screens.matchdetail

import com.adammcneilly.pocketleague.core.displaymodels.toDetailDisplayModel
import com.adammcneilly.pocketleague.core.models.Game
import com.adammcneilly.pocketleague.core.models.Match
import com.adammcneilly.pocketleague.data.game.MatchGamesRequest
import com.adammcneilly.pocketleague.shared.screens.Events
import kotlinx.coroutines.CoroutineScope
Expand All @@ -11,13 +12,13 @@ import kotlinx.coroutines.flow.onEach
/**
* Requests the games for the given [matchId].
*/
fun Events.loadMatchDetail(matchId: String) = screenCoroutine {
fun Events.loadMatchDetail(matchId: Match.Id) = screenCoroutine {
fetchMatchDetail(matchId, it)

fetchGames(matchId)
}

private suspend fun Events.fetchGames(matchId: String) {
private suspend fun Events.fetchGames(matchId: Match.Id) {
val repoResult = appModule
.dataModule
.gameService
Expand All @@ -31,7 +32,7 @@ private suspend fun Events.fetchGames(matchId: String) {
}

private fun Events.fetchMatchDetail(
matchId: String,
matchId: Match.Id,
scope: CoroutineScope,
) {
appModule
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package com.adammcneilly.pocketleague.shared.screens.matchdetail

import com.adammcneilly.pocketleague.core.feature.ScreenParams
import com.adammcneilly.pocketleague.core.models.Match

/**
* Parameters that will be passed into the match detail screen.
*
* @property[matchId] The identifier of the match to request details for.
*/
data class MatchDetailParams(
val matchId: String,
val matchId: Match.Id,
) : ScreenParams
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import com.adammcneilly.pocketleague.core.models.Match
* The UI state for detailed information about a [Match].
*/
data class MatchDetailViewState(
val matchId: String = "",
val matchId: Match.Id = Match.Id(""),
val matchDetail: MatchDetailDisplayModel? = null,
val games: List<GameDetailDisplayModel> = emptyList(),
) : ScreenState {
Expand Down
1 change: 1 addition & 0 deletions shared/ui/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ kotlin {
val commonMain by getting {
dependencies {
implementation(project(":core:displaymodels"))
implementation(project(":core:models"))
implementation(project(":shared:design-system"))
implementation(compose.foundation)
implementation(compose.material3)
Expand Down
Loading

0 comments on commit 1759043

Please sign in to comment.