diff --git a/src/main/kotlin/io/gitlab/jfronny/sdom/SDom.kt b/src/main/kotlin/io/gitlab/jfronny/sdom/SDom.kt index a378bcf..ce07e1c 100644 --- a/src/main/kotlin/io/gitlab/jfronny/sdom/SDom.kt +++ b/src/main/kotlin/io/gitlab/jfronny/sdom/SDom.kt @@ -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>, Contest, Problem, String) -> Unit +typealias ResultFlowListener = (SharedFlow>, 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 = listOf() - var currentProblem: Problem? = null + + var problems: Map? = null + var currentProblem: SDProblem? = null var judgementTypes: Map? = null private var languages: Map? = 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>() + .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() + 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> = coroutineScope { val resultFlow: MutableSharedFlow> = MutableSharedFlow() diff --git a/src/main/kotlin/io/gitlab/jfronny/sdom/actions/SDGetProblemsAction.kt b/src/main/kotlin/io/gitlab/jfronny/sdom/actions/SDGetProblemsAction.kt index 6597154..2ed7ccb 100644 --- a/src/main/kotlin/io/gitlab/jfronny/sdom/actions/SDGetProblemsAction.kt +++ b/src/main/kotlin/io/gitlab/jfronny/sdom/actions/SDGetProblemsAction.kt @@ -19,7 +19,7 @@ class SDGetProblemsAction : DumbAwareAction() { override fun actionPerformed(e: AnActionEvent) { CoroutineScope(Job() + Dispatchers.IO).launch { - SDom.fetchProblems() + SDom.loadProblems() } } } \ No newline at end of file diff --git a/src/main/kotlin/io/gitlab/jfronny/sdom/actions/SDProblemSelectionAction.kt b/src/main/kotlin/io/gitlab/jfronny/sdom/actions/SDProblemSelectionAction.kt index fa1c212..e7e6be5 100644 --- a/src/main/kotlin/io/gitlab/jfronny/sdom/actions/SDProblemSelectionAction.kt +++ b/src/main/kotlin/io/gitlab/jfronny/sdom/actions/SDProblemSelectionAction.kt @@ -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)) } diff --git a/src/main/kotlin/io/gitlab/jfronny/sdom/model/SDProblem.kt b/src/main/kotlin/io/gitlab/jfronny/sdom/model/SDProblem.kt new file mode 100644 index 0000000..a0e94a8 --- /dev/null +++ b/src/main/kotlin/io/gitlab/jfronny/sdom/model/SDProblem.kt @@ -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 { + 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) + } +} diff --git a/src/main/kotlin/io/gitlab/jfronny/sdom/toolwindow/SDToolWindowFactory.kt b/src/main/kotlin/io/gitlab/jfronny/sdom/toolwindow/SDToolWindowFactory.kt index c1c82ea..eacb76f 100644 --- a/src/main/kotlin/io/gitlab/jfronny/sdom/toolwindow/SDToolWindowFactory.kt +++ b/src/main/kotlin/io/gitlab/jfronny/sdom/toolwindow/SDToolWindowFactory.kt @@ -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>, contest: Contest, problem: Problem, filename: String) { + fun showResultContent(resultFlow: Flow>, contest: Contest, problem: SDProblem, filename: String) { submitPanel.logSubmission(contest, problem, filename) CoroutineScope(Job() + Dispatchers.IO).launch { diff --git a/src/main/kotlin/io/gitlab/jfronny/sdom/ui/SDSubmitPanel.kt b/src/main/kotlin/io/gitlab/jfronny/sdom/ui/SDSubmitPanel.kt index 4806c75..1a49009 100644 --- a/src/main/kotlin/io/gitlab/jfronny/sdom/ui/SDSubmitPanel.kt +++ b/src/main/kotlin/io/gitlab/jfronny/sdom/ui/SDSubmitPanel.kt @@ -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, contest: Contest, problem: Problem, filename: String) { + fun logSDJudgement(judgement: Result, 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() }