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.SDGetProblemsAction
import io.gitlab.jfronny.sdom.model.*
import io.gitlab.jfronny.sdom.model.scoreboard.Scoreboard
import io.gitlab.jfronny.sdom.util.notify
import io.ktor.client.*
import io.ktor.client.call.*
@ -29,7 +30,7 @@ import java.util.*
import java.util.zip.ZipEntry
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 {
private const val CONTEST_ID_PROPERTY = "io.gitlab.jfronny.sdom.contestId"
@ -125,8 +126,9 @@ object SDom {
field = value
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
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 result = authenticatedClient.get(SDCredentials.url) {
url {
@ -163,13 +170,35 @@ object SDom {
}
if (result.status.isSuccess()) {
problems = result.body<List<Problem>>()
.map { SDProblem.of(it, false) }
.associateBy { it.id }
if (!problems.contains(currentProblem)) {
if (problems?.containsValue(currentProblem) != true) {
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?) {
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) {
url {
appendPathSegments("contests", contest.id, "problems", problem.id, "statement")
@ -228,7 +257,7 @@ object SDom {
}
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 {
val resultFlow: MutableSharedFlow<Result<SDJudgement>> = MutableSharedFlow()

View File

@ -19,7 +19,7 @@ class SDGetProblemsAction : DumbAwareAction() {
override fun actionPerformed(e: AnActionEvent) {
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.util.ui.ColorIcon
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.Dimension
import javax.swing.JComponent
@ -28,7 +28,13 @@ class SDProblemSelectionComboBoxAction : ComboBoxAction(), DumbAware {
override fun createPopupActionGroup(button: JComponent, dataContext: DataContext): 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
}
@ -59,11 +65,11 @@ class SDProblemSelectionComboBoxAction : ComboBoxAction(), DumbAware {
override fun shouldShowDisabledActions(): Boolean = true
private class SelectProblemAction(
private val problem: Problem,
private val problem: SDProblem,
val isSelected: Boolean
) : DumbAwareAction() {
init {
val name = problem.name
val name = (if (problem.solved) "" else "") + problem.name
templatePresentation.setText(name, false)
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 io.gitlab.jfronny.sdom.SDom
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.SDProblem
import io.gitlab.jfronny.sdom.ui.SDSubmitPanel
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@ -37,7 +37,7 @@ class SDToolWindowFactory : ToolWindowFactory, DumbAware {
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)
CoroutineScope(Job() + Dispatchers.IO).launch {

View File

@ -7,8 +7,8 @@ import com.intellij.openapi.ui.ComponentContainer
import com.intellij.openapi.util.Disposer
import io.gitlab.jfronny.sdom.SDom
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.SDProblem
import io.gitlab.jfronny.sdom.util.OutputType
import io.gitlab.jfronny.sdom.util.println
import java.awt.BorderLayout
@ -36,7 +36,7 @@ class SDSubmitPanel (
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(
onSuccess = { result ->
val parsedResult =
@ -48,6 +48,10 @@ class SDSubmitPanel (
"Submission of \"$filename\" to problem \"${problem.name}\", got result: ${parsedResult.first}",
if (parsedResult.second) OutputType.SUCCESS else OutputType.ERROR
)
if (parsedResult.second) {
problem.solved = true
}
},
onFailure = { e ->
console.println("Judgement failed: ${e.message}", OutputType.ERROR)
@ -56,7 +60,7 @@ class SDSubmitPanel (
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)
panel.revalidate()
}