Skip to content

Commit 39d5b20

Browse files
committed
Add multi-season support for V5RC
1 parent 252b1b5 commit 39d5b20

File tree

5 files changed

+467
-266
lines changed

5 files changed

+467
-266
lines changed

app/build.gradle.kts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ android {
1616
minSdk = 30
1717
targetSdk = 34
1818
versionCode = 1
19-
versionName = "1.0.2"
19+
versionName = "1.1.0"
2020

2121
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
2222
vectorDrawables {
@@ -41,6 +41,19 @@ android {
4141
val key8 = properties.getProperty("key8") ?: ""
4242
val key9 = properties.getProperty("key9") ?: ""
4343

44+
// Default season IDs
45+
buildConfigField(
46+
type = "int",
47+
name = "DEFAULT_V5_SEASON_ID",
48+
value = "190"
49+
)
50+
buildConfigField(
51+
type = "int",
52+
name = "DEFAULT_VU_SEASON_ID",
53+
value = "191"
54+
)
55+
56+
// API keys
4457
buildConfigField(
4558
type = "String",
4659
name = "ROBOTEVENTS_API_KEY",

app/src/main/java/com/sunkensplashstudios/VRCRoboScout/LookupView.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.sunkensplashstudios.VRCRoboScout
22

3+
import android.content.Context
34
import androidx.compose.foundation.clickable
45
import androidx.compose.foundation.interaction.FocusInteraction
56
import androidx.compose.foundation.interaction.MutableInteractionSource
@@ -83,6 +84,7 @@ import kotlin.math.abs
8384

8485
class LookupViewModel : ViewModel() {
8586
var lookupType = mutableStateOf("Teams")
87+
var applicationContext: Context? = null
8688

8789
// TeamLookup
8890
var teamTextColor = mutableStateOf(Color.Gray)
@@ -168,7 +170,7 @@ class LookupViewModel : ViewModel() {
168170
return@launch
169171
}
170172
val data = RoboScoutAPI.roboteventsRequest(
171-
requestUrl = "/seasons/${season ?: 181}/events",
173+
requestUrl = "/seasons/${season ?: UserSettings(applicationContext!!)}/events",
172174
params = mapOf("sku" to skuArray)
173175
)
174176
withContext(Dispatchers.Main) {
@@ -189,9 +191,11 @@ class LookupViewModel : ViewModel() {
189191
@Destination
190192
@Composable
191193
fun LookupView(lookupViewModel: LookupViewModel = viewModels["lookup_view"] as LookupViewModel, navController: NavController) {
194+
192195
Column(
193196
modifier = Modifier.fillMaxSize()
194197
) {
198+
lookupViewModel.applicationContext = LocalContext.current.applicationContext
195199
Scaffold(
196200
topBar = {
197201
CenterAlignedTopAppBar(

app/src/main/java/com/sunkensplashstudios/VRCRoboScout/RoboScoutAPI.kt

Lines changed: 84 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,9 @@ class RoboScoutAPI {
165165
var regionsMap: MutableMap<String, Int> = mutableMapOf<String, Int>()
166166
var importedWS: Boolean = false
167167
var importedVDA: Boolean = false
168+
var seasonIdMap: List<MutableList<Season>> = listOf()
169+
var selectedSeasonId: Int = BuildConfig.DEFAULT_V5_SEASON_ID
170+
var gradeLevel: String = "High School"
168171

169172
companion object {
170173

@@ -337,13 +340,70 @@ class RoboScoutAPI {
337340
}
338341
}
339342

340-
suspend fun updateWorldSkillsCache(season: Int? = null) {
343+
suspend fun generateSeasonIdMap() {
344+
this.seasonIdMap = listOf(mutableListOf(), mutableListOf())
345+
val data = roboteventsRequest("/seasons/")
346+
347+
for (seasonData in data) {
348+
val season = jsonWorker.decodeFromJsonElement<Season>(seasonData)
349+
val gradeLevelIndex = if (season.program.id == 1) 0 else if (season.program.id == 4) 1 else -1
350+
if (gradeLevelIndex != -1) {
351+
this.seasonIdMap[gradeLevelIndex].add(season)
352+
}
353+
}
354+
355+
println("Season ID map generated")
356+
/*for (gradeLevel in this.seasonIdMap) {
357+
for (season in gradeLevel) {
358+
println("ID: ${season.id}, Name: ${season.name}")
359+
}
360+
}*/
361+
}
362+
363+
fun selectedProgramId(): Int {
364+
return if (this.gradeLevel == "College") 4 else 1
365+
}
366+
367+
fun selectedSeasonId(): Int {
368+
return this.selectedSeasonId
369+
}
370+
371+
fun activeSeasonId(): Int {
372+
return if (this.seasonIdMap.isNotEmpty()) {
373+
if (this.gradeLevel != "College") {
374+
try {
375+
this.seasonIdMap[0].first().id
376+
}
377+
catch (e: NoSuchElementException) {
378+
BuildConfig.DEFAULT_V5_SEASON_ID
379+
}
380+
}
381+
else {
382+
try {
383+
this.seasonIdMap[1].first().id
384+
}
385+
catch (e: NoSuchElementException) {
386+
BuildConfig.DEFAULT_VU_SEASON_ID
387+
}
388+
}
389+
}
390+
else {
391+
if (this.gradeLevel != "College") {
392+
BuildConfig.DEFAULT_V5_SEASON_ID
393+
}
394+
else {
395+
BuildConfig.DEFAULT_VU_SEASON_ID
396+
}
397+
}
398+
}
399+
400+
suspend fun updateWorldSkillsCache(season: Int? = null) {
341401

342402
this.importedWS = false
343403
this.wsCache.clear()
344404

345405
try {
346-
val response = client.get("https://www.robotevents.com/api/seasons/${season ?: 181}/skills") {
406+
val response = client.get("https://www.robotevents.com/api/seasons/${season ?: API.selectedSeasonId()}/skills") {
347407
url {
348408
parameters.append("grade_level", "High School")
349409
}
@@ -415,10 +475,28 @@ class RoboScoutAPI {
415475

416476
}
417477

478+
@Serializable
479+
class Program {
480+
var id: Int = 0
481+
var name: String = ""
482+
}
483+
418484
@Serializable
419485
class Season {
420486
var id: Int = 0
421487
var name: String = ""
488+
@kotlinx.serialization.Transient var shortName: String = name.replace("VRC ", "").replace("V5RC ", "").replace("VEXU ", "").replace("VURC ", "")
489+
var program: Program = Program()
490+
var start: String = ""
491+
var end: String = ""
492+
@kotlinx.serialization.Transient var startDate: Date? = RoboScoutAPI.roboteventsDate(start, true)
493+
@kotlinx.serialization.Transient var endDate: Date? = RoboScoutAPI.roboteventsDate(end, true)
494+
}
495+
496+
@Serializable
497+
class ShortSeason {
498+
var id: Int = 0
499+
var name: String = ""
422500
}
423501

424502
enum class AllianceColor {
@@ -602,7 +680,7 @@ class Event {
602680
@kotlinx.serialization.Transient var startDate: Date? = null
603681
var end: String = ""
604682
@kotlinx.serialization.Transient var endDate: Date? = null
605-
var season: Season = Season()
683+
var season: ShortSeason = ShortSeason()
606684
var location: Location = Location()
607685
@kotlinx.serialization.Transient var matches: MutableMap<Division, MutableList<Match>> = mutableMapOf<Division, MutableList<Match>>()
608686
var teams: MutableList<Team> = mutableListOf<Team>()
@@ -970,7 +1048,7 @@ class Team : MutableState<Team> {
9701048
}
9711049

9721050
suspend fun fetchEvents(season: Int? = null) {
973-
val data = RoboScoutAPI.roboteventsRequest("/events", mapOf("team" to id, "season" to (season ?: 181)))
1051+
val data = RoboScoutAPI.roboteventsRequest("/events", mapOf("team" to id, "season" to (season ?: API.selectedSeasonId())))
9741052
events.clear()
9751053
for (event in data) {
9761054
val fetchedEvent: Event = jsonWorker.decodeFromJsonElement(event)
@@ -979,7 +1057,7 @@ class Team : MutableState<Team> {
9791057
}
9801058

9811059
suspend fun fetchAwards(season: Int? = null) {
982-
val data = RoboScoutAPI.roboteventsRequest("/teams/${this.id}/awards", mapOf("season" to (season ?: 181)))
1060+
val data = RoboScoutAPI.roboteventsRequest("/teams/${this.id}/awards", mapOf("season" to (season ?: API.selectedSeasonId())))
9831061
awards.clear()
9841062
for (award in data) {
9851063
val fetchedAward: Award = jsonWorker.decodeFromJsonElement(award)
@@ -989,7 +1067,7 @@ class Team : MutableState<Team> {
9891067
}
9901068

9911069
suspend fun averageQualifiersRanking(season: Int? = null): Double {
992-
val data = RoboScoutAPI.roboteventsRequest("/teams/${this.id}/rankings/", mapOf("season" to (season ?: 181)))
1070+
val data = RoboScoutAPI.roboteventsRequest("/teams/${this.id}/rankings/", mapOf("season" to (season ?: API.selectedSeasonId())))
9931071
var total = 0
9941072
for (comp in data) {
9951073
total += comp["rank"]!!.jsonPrimitive.int

app/src/main/java/com/sunkensplashstudios/VRCRoboScout/RootActivity.kt

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,24 @@ class UserSettings(context: Context) {
166166
this.saveData("onTopContainerColor", Color.Unspecified.toArgb().toString())
167167
this.saveData("buttonColor", Color.Unspecified.toArgb().toString())
168168
}
169+
170+
fun setSelectedSeasonId(seasonId: Int) {
171+
this.saveData("selectedSeasonId", seasonId.toString())
172+
API.selectedSeasonId = seasonId
173+
}
174+
175+
fun getSelectedSeasonId(): Int {
176+
return this.getData("selectedSeasonId", BuildConfig.DEFAULT_V5_SEASON_ID.toString()).toInt()
177+
}
178+
179+
fun setGradeLevel(gradeLevel: String) {
180+
this.saveData("gradeLevel", gradeLevel)
181+
API.gradeLevel = gradeLevel
182+
}
183+
184+
fun getGradeLevel(): String {
185+
return this.getData("gradeLevel", "High School")
186+
}
169187
}
170188

171189
class EventDataTransferManager {
@@ -267,13 +285,19 @@ val viewModels = mapOf(
267285

268286
class RootActivity : ComponentActivity() {
269287

270-
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterialNavigationApi::class,
288+
@OptIn(
289+
ExperimentalMaterialNavigationApi::class,
271290
ExperimentalAnimationApi::class
272291
)
273292
override fun onCreate(savedInstanceState: Bundle?) {
274293
super.onCreate(savedInstanceState)
275294
setContent {
276295
LaunchedEffect(Unit) {
296+
if (API.seasonIdMap.isEmpty()) {
297+
CoroutineScope(Dispatchers.Default).launch {
298+
API.generateSeasonIdMap()
299+
}
300+
}
277301
if (!API.importedWS) {
278302
CoroutineScope(Dispatchers.Default).launch {
279303
API.updateWorldSkillsCache()

0 commit comments

Comments
 (0)