feat: display solved problems

This commit is contained in:
Alexander Klee 2024-05-29 13:37:01 +02:00
parent e57112b7c4
commit d8ea951492
6 changed files with 71 additions and 17 deletions

View File

@ -10,6 +10,7 @@ import com.intellij.openapi.project.Project
import io.gitlab.jfronny.sdom.actions.SDGetContestsAction import io.gitlab.jfronny.sdom.actions.SDGetContestsAction
import io.gitlab.jfronny.sdom.actions.SDGetProblemsAction import io.gitlab.jfronny.sdom.actions.SDGetProblemsAction
import io.gitlab.jfronny.sdom.model.* import io.gitlab.jfronny.sdom.model.*
import io.gitlab.jfronny.sdom.model.scoreboard.Scoreboard
import io.gitlab.jfronny.sdom.util.notify import io.gitlab.jfronny.sdom.util.notify
import io.ktor.client.* import io.ktor.client.*
import io.ktor.client.call.* import io.ktor.client.call.*
@ -29,7 +30,7 @@ import java.util.*
import java.util.zip.ZipEntry import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream import java.util.zip.ZipOutputStream
typealias ResultFlowListener = (SharedFlow<Result<SDJudgement>>, Contest, Problem, String) -> Unit typealias ResultFlowListener = (SharedFlow<Result<SDJudgement>>, Contest, SDProblem, String) -> Unit
object SDom { object SDom {
private const val CONTEST_ID_PROPERTY = "io.gitlab.jfronny.sdom.contestId" private const val CONTEST_ID_PROPERTY = "io.gitlab.jfronny.sdom.contestId"
@ -125,8 +126,9 @@ object SDom {
field = value field = value
propertiesComponent?.setValue(CONTEST_ID_PROPERTY, value?.id, "") propertiesComponent?.setValue(CONTEST_ID_PROPERTY, value?.id, "")
} }
var problems: List<Problem> = listOf()
var currentProblem: Problem? = null var problems: Map<String, SDProblem>? = null
var currentProblem: SDProblem? = null
var judgementTypes: Map<String, SDJudgementType>? = null var judgementTypes: Map<String, SDJudgementType>? = null
private var languages: Map<String, SDLanguage>? = null private var languages: Map<String, SDLanguage>? = null
@ -154,7 +156,12 @@ object SDom {
} }
} }
suspend fun fetchProblems() { suspend fun loadProblems() {
fetchProblems()
getSolvedProblems()
}
private suspend fun fetchProblems() {
val contest = currentContest ?: return val contest = currentContest ?: return
val result = authenticatedClient.get(SDCredentials.url) { val result = authenticatedClient.get(SDCredentials.url) {
url { url {
@ -163,13 +170,35 @@ object SDom {
} }
if (result.status.isSuccess()) { if (result.status.isSuccess()) {
problems = result.body<List<Problem>>() problems = result.body<List<Problem>>()
.map { SDProblem.of(it, false) }
.associateBy { it.id }
if (!problems.contains(currentProblem)) { if (problems?.containsValue(currentProblem) != true) {
currentProblem = null currentProblem = null
} }
} }
} }
private suspend fun getSolvedProblems() {
val teamId = SDCredentials.teamId ?: return // TODO ??
val contest = currentContest ?: return // TODO ??
val result = authenticatedClient.get(SDCredentials.url) {
url {
appendPathSegments("contests", contest.id, "scoreboard")
}
}
if (result.status.isSuccess()) {
val scoreboard = result.body<Scoreboard>()
val solvedProblems = scoreboard.rows
.firstOrNull { it.teamId == teamId }
?.let { row ->
row.problems.associateBy { it.problemId }
}
problems?.values?.forEach { it.solved = solvedProblems?.get(it.id)?.solved ?: false }
}
}
suspend fun selectContest(contest: Contest, context: Project?) { suspend fun selectContest(contest: Contest, context: Project?) {
currentContest = contest currentContest = contest
@ -212,7 +241,7 @@ object SDom {
} }
} }
suspend fun downloadProblemStatement(contest: Contest, problem: Problem): ByteArray { suspend fun downloadProblemStatement(contest: Contest, problem: SDProblem): ByteArray {
val response: ByteArray = authenticatedClient.get(SDCredentials.url) { val response: ByteArray = authenticatedClient.get(SDCredentials.url) {
url { url {
appendPathSegments("contests", contest.id, "problems", problem.id, "statement") appendPathSegments("contests", contest.id, "problems", problem.id, "statement")
@ -228,7 +257,7 @@ object SDom {
} }
suspend fun submitSolution( suspend fun submitSolution(
contest: Contest, problem: Problem, solution: String, fileName: String, language: SDLanguage contest: Contest, problem: SDProblem, solution: String, fileName: String, language: SDLanguage
): SharedFlow<Result<SDJudgement>> = coroutineScope { ): SharedFlow<Result<SDJudgement>> = coroutineScope {
val resultFlow: MutableSharedFlow<Result<SDJudgement>> = MutableSharedFlow() val resultFlow: MutableSharedFlow<Result<SDJudgement>> = MutableSharedFlow()

View File

@ -19,7 +19,7 @@ class SDGetProblemsAction : DumbAwareAction() {
override fun actionPerformed(e: AnActionEvent) { override fun actionPerformed(e: AnActionEvent) {
CoroutineScope(Job() + Dispatchers.IO).launch { CoroutineScope(Job() + Dispatchers.IO).launch {
SDom.fetchProblems() SDom.loadProblems()
} }
} }
} }

View File

@ -11,7 +11,7 @@ import com.intellij.openapi.ui.popup.JBPopupFactory
import com.intellij.openapi.util.Condition import com.intellij.openapi.util.Condition
import com.intellij.util.ui.ColorIcon import com.intellij.util.ui.ColorIcon
import io.gitlab.jfronny.sdom.SDom import io.gitlab.jfronny.sdom.SDom
import io.gitlab.jfronny.sdom.model.Problem import io.gitlab.jfronny.sdom.model.SDProblem
import java.awt.Color import java.awt.Color
import java.awt.Dimension import java.awt.Dimension
import javax.swing.JComponent import javax.swing.JComponent
@ -28,7 +28,13 @@ class SDProblemSelectionComboBoxAction : ComboBoxAction(), DumbAware {
override fun createPopupActionGroup(button: JComponent, dataContext: DataContext): DefaultActionGroup { override fun createPopupActionGroup(button: JComponent, dataContext: DataContext): DefaultActionGroup {
val actionGroup = DefaultActionGroup() val actionGroup = DefaultActionGroup()
actionGroup.addAll(SDom.problems.map { SelectProblemAction(it, it == SDom.currentProblem) }) actionGroup.addAll(
SDom.problems
?.values
?.sorted()
?.map { SelectProblemAction(it, it == SDom.currentProblem) }
?: emptyList()
)
return actionGroup return actionGroup
} }
@ -59,11 +65,11 @@ class SDProblemSelectionComboBoxAction : ComboBoxAction(), DumbAware {
override fun shouldShowDisabledActions(): Boolean = true override fun shouldShowDisabledActions(): Boolean = true
private class SelectProblemAction( private class SelectProblemAction(
private val problem: Problem, private val problem: SDProblem,
val isSelected: Boolean val isSelected: Boolean
) : DumbAwareAction() { ) : DumbAwareAction() {
init { init {
val name = problem.name val name = (if (problem.solved) "" else "") + problem.name
templatePresentation.setText(name, false) templatePresentation.setText(name, false)
templatePresentation.icon = ColorIcon(13, Color.decode(problem.rgb)) templatePresentation.icon = ColorIcon(13, Color.decode(problem.rgb))
} }

View File

@ -0,0 +1,15 @@
package io.gitlab.jfronny.sdom.model
data class SDProblem(val id: String, val name: String, val rgb: String, var solved: Boolean) : Comparable<SDProblem> {
companion object {
fun of(problem: Problem, solved: Boolean): SDProblem {
return SDProblem(problem.id, problem.name, problem.rgb, solved)
}
}
override fun compareTo(other: SDProblem): Int {
if (solved && !other.solved) return 1
if (!solved && other.solved) return -1
return name.compareTo(other.name)
}
}

View File

@ -7,8 +7,8 @@ import com.intellij.openapi.wm.ToolWindow
import com.intellij.openapi.wm.ToolWindowFactory import com.intellij.openapi.wm.ToolWindowFactory
import io.gitlab.jfronny.sdom.SDom import io.gitlab.jfronny.sdom.SDom
import io.gitlab.jfronny.sdom.model.Contest import io.gitlab.jfronny.sdom.model.Contest
import io.gitlab.jfronny.sdom.model.Problem
import io.gitlab.jfronny.sdom.model.SDJudgement import io.gitlab.jfronny.sdom.model.SDJudgement
import io.gitlab.jfronny.sdom.model.SDProblem
import io.gitlab.jfronny.sdom.ui.SDSubmitPanel import io.gitlab.jfronny.sdom.ui.SDSubmitPanel
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -37,7 +37,7 @@ class SDToolWindowFactory : ToolWindowFactory, DumbAware {
contentManager.addContent(loggedOutContent) contentManager.addContent(loggedOutContent)
} }
fun showResultContent(resultFlow: Flow<Result<SDJudgement>>, contest: Contest, problem: Problem, filename: String) { fun showResultContent(resultFlow: Flow<Result<SDJudgement>>, contest: Contest, problem: SDProblem, filename: String) {
submitPanel.logSubmission(contest, problem, filename) submitPanel.logSubmission(contest, problem, filename)
CoroutineScope(Job() + Dispatchers.IO).launch { CoroutineScope(Job() + Dispatchers.IO).launch {

View File

@ -7,8 +7,8 @@ import com.intellij.openapi.ui.ComponentContainer
import com.intellij.openapi.util.Disposer import com.intellij.openapi.util.Disposer
import io.gitlab.jfronny.sdom.SDom import io.gitlab.jfronny.sdom.SDom
import io.gitlab.jfronny.sdom.model.Contest import io.gitlab.jfronny.sdom.model.Contest
import io.gitlab.jfronny.sdom.model.Problem
import io.gitlab.jfronny.sdom.model.SDJudgement import io.gitlab.jfronny.sdom.model.SDJudgement
import io.gitlab.jfronny.sdom.model.SDProblem
import io.gitlab.jfronny.sdom.util.OutputType import io.gitlab.jfronny.sdom.util.OutputType
import io.gitlab.jfronny.sdom.util.println import io.gitlab.jfronny.sdom.util.println
import java.awt.BorderLayout import java.awt.BorderLayout
@ -36,7 +36,7 @@ class SDSubmitPanel (
panel.isVisible = true panel.isVisible = true
} }
fun logSDJudgement(judgement: Result<SDJudgement>, contest: Contest, problem: Problem, filename: String) { fun logSDJudgement(judgement: Result<SDJudgement>, contest: Contest, problem: SDProblem, filename: String) {
judgement.fold( judgement.fold(
onSuccess = { result -> onSuccess = { result ->
val parsedResult = val parsedResult =
@ -48,6 +48,10 @@ class SDSubmitPanel (
"Submission of \"$filename\" to problem \"${problem.name}\", got result: ${parsedResult.first}", "Submission of \"$filename\" to problem \"${problem.name}\", got result: ${parsedResult.first}",
if (parsedResult.second) OutputType.SUCCESS else OutputType.ERROR if (parsedResult.second) OutputType.SUCCESS else OutputType.ERROR
) )
if (parsedResult.second) {
problem.solved = true
}
}, },
onFailure = { e -> onFailure = { e ->
console.println("Judgement failed: ${e.message}", OutputType.ERROR) console.println("Judgement failed: ${e.message}", OutputType.ERROR)
@ -56,7 +60,7 @@ class SDSubmitPanel (
panel.revalidate() panel.revalidate()
} }
fun logSubmission(contest: Contest, problem: Problem, filename: String) { fun logSubmission(contest: Contest, problem: SDProblem, filename: String) {
console.println("Submitted file \"$filename\" to problem \"${problem.name}\", Waiting for result...", OutputType.OUTPUT) console.println("Submitted file \"$filename\" to problem \"${problem.name}\", Waiting for result...", OutputType.OUTPUT)
panel.revalidate() panel.revalidate()
} }