feat: add settings UI and allow configuring PDF open mode

Closes #1
This commit is contained in:
Johannes Frohnmeyer 2024-05-29 14:42:24 +02:00
parent cd86b91b10
commit 91b85ed70c
Signed by: Johannes
GPG Key ID: E76429612C2929F4
12 changed files with 138 additions and 27 deletions

View File

@ -13,7 +13,6 @@ You can download the plugin from the [JetBrains Marketplace](https://plugins.jet
<!-- Note to writers: A copy of the feature list exists in plugin.xml, please also add your changes there -->
## Potential future features
- Settings UI (login, PDF mode, ...)
- Display how much time is left in a contest or whether it's already over
- Implement reading detailed results
- Show scoreboards

View File

@ -11,6 +11,7 @@ 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.settings.SDCredentials
import io.gitlab.jfronny.sdom.util.notify
import io.ktor.client.*
import io.ktor.client.call.*

View File

@ -2,8 +2,7 @@ package io.gitlab.jfronny.sdom.actions
import com.intellij.notification.Notification
import com.intellij.notification.NotificationAction
import com.intellij.openapi.actionSystem.ActionUpdateThread
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.*
import io.gitlab.jfronny.sdom.SDom
import io.gitlab.jfronny.sdom.ui.SDLoginDialogWrapper
import kotlinx.coroutines.CoroutineScope
@ -26,4 +25,19 @@ class SDLoginAction(text: String) : NotificationAction(text) {
}
}
}
companion object {
fun perform() {
SDLoginAction().actionPerformed(
AnActionEvent(
null,
DataContext.EMPTY_CONTEXT,
ActionPlaces.UNKNOWN,
Presentation(),
ActionManager.getInstance(),
0
)
)
}
}
}

View File

@ -6,10 +6,14 @@ import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.fileEditor.FileEditorManager
import com.intellij.openapi.project.DumbAwareAction
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.ui.jcef.JBCefApp
import io.gitlab.jfronny.sdom.SDom
import io.gitlab.jfronny.sdom.SDom.currentContest
import io.gitlab.jfronny.sdom.SDom.currentProblem
import io.gitlab.jfronny.sdom.settings.PdfMode
import io.gitlab.jfronny.sdom.settings.SDSettings
import io.gitlab.jfronny.sdom.ui.ByteVirtualFile
import io.gitlab.jfronny.sdom.util.OSUtils
import io.gitlab.jfronny.sdom.util.notify
@ -18,6 +22,8 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.StandardOpenOption
class SDStatementAction(name: String) : DumbAwareAction(name) {
constructor() : this("")
@ -52,16 +58,24 @@ class SDStatementAction(name: String) : DumbAwareAction(name) {
}
CoroutineScope(Job() + Dispatchers.IO).launch {
val data = SDom.downloadProblemStatement(contest, problem)
if (JBCefApp.isSupported()) {
val virtualFile = ByteVirtualFile("${problem.name}_${contest.name}.pdf", data)
ApplicationManager.getApplication().invokeLater {
FileEditorManager.getInstance(e.project!!).openFile(virtualFile)
fun createTmpFile(): Path {
val path = Files.createTempFile("${problem.name}_${contest.name}", ".pdf")
Files.write(path, data, StandardOpenOption.WRITE)
return path
}
fun open(virtualFile: VirtualFile) = ApplicationManager.getApplication().invokeLater {
FileEditorManager.getInstance(e.project!!).openFile(virtualFile)
}
when (SDSettings.getInstance().state.pdfMode) {
PdfMode.INTERNAL_MEMORY -> {
if (JBCefApp.isSupported()) open(ByteVirtualFile("${problem.name}_${contest.name}.pdf", data))
else OSUtils.openFile(createTmpFile().toFile())
}
} else {
val path = Files.createTempFile("sdom", ".pdf")
Files.newOutputStream(path).use { it.write(data) }
OSUtils.openFile(path.toFile())
PdfMode.INTERNAL_FILE -> {
if (JBCefApp.isSupported()) open(VirtualFileManager.getInstance().refreshAndFindFileByNioPath(createTmpFile())!!)
else OSUtils.openFile(createTmpFile().toFile())
}
PdfMode.EXTERNAL_FILE -> OSUtils.openFile(createTmpFile().toFile())
}
}
}

View File

@ -0,0 +1,11 @@
package io.gitlab.jfronny.sdom.settings
enum class PdfMode(private val visual: String) {
INTERNAL_MEMORY("Internal viewer, in-memory"),
INTERNAL_FILE("Internal viewer, as file"),
EXTERNAL_FILE("System-default");
override fun toString(): String {
return visual
}
}

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.sdom
package io.gitlab.jfronny.sdom.settings
import com.intellij.credentialStore.CredentialAttributes
import com.intellij.credentialStore.Credentials
@ -26,9 +26,9 @@ object SDCredentials {
}
var url: String
get() = ApplicationManager.getApplication().getService(SDSettings::class.java).state.url ?: "https://domjudge.iti.kit.edu/main/api/v4"
get() = SDSettings.getInstance().state.url ?: "https://domjudge.iti.kit.edu/main/api/v4"
set(value) {
ApplicationManager.getApplication().getService(SDSettings::class.java).state.url = value
SDSettings.getInstance().state.url = value
}
var teamId: String?

View File

@ -1,5 +1,6 @@
package io.gitlab.jfronny.sdom
package io.gitlab.jfronny.sdom.settings
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.*
@Service
@ -7,5 +8,10 @@ import com.intellij.openapi.components.*
class SDSettings : SimplePersistentStateComponent<SDSettings.SDState>(SDState()) {
class SDState : BaseState() {
var url by string("https://domjudge.iti.kit.edu/main/api/v4")
var pdfMode by enum<PdfMode>(PdfMode.INTERNAL_FILE)
}
companion object {
fun getInstance(): SDSettings = ApplicationManager.getApplication().getService(SDSettings::class.java)
}
}

View File

@ -0,0 +1,34 @@
package io.gitlab.jfronny.sdom.settings
import com.intellij.openapi.ui.ComboBox
import com.intellij.ui.dsl.builder.panel
import io.gitlab.jfronny.sdom.actions.SDLoginAction
import javax.swing.JPanel
class SDSettingsComponent {
val mainPanel: JPanel
val pdfModeBox: ComboBox<PdfMode> = ComboBox(PdfMode.entries.toTypedArray())
init {
// mainPanel = FormBuilder.createFormBuilder()
// .addLabeledComponent("PDF Mode", pdfModeBox)
// .addComponentFillVertically(JPanel(), 0)
// .addComponentFillVertically(ActionManager.getInstance().createActionToolbar(
// "SettingsUI",
// DefaultActionGroup(SDLoginAction("Change Login Credentials")),
// true
// ).component, 0)
// .panel
mainPanel = panel {
row {
label("PDF Mode")
cell(pdfModeBox)
}
row {
button("Change Login Credentials") {
SDLoginAction.perform()
}
}
}
}
}

View File

@ -0,0 +1,37 @@
package io.gitlab.jfronny.sdom.settings
import com.intellij.openapi.options.Configurable
import javax.swing.JComponent
class SDSettingsConfigurable : Configurable {
private var settingsComponent: SDSettingsComponent? = null
override fun getDisplayName(): String = "S-dom"
override fun getPreferredFocusedComponent(): JComponent? {
return settingsComponent!!.pdfModeBox
}
override fun createComponent(): JComponent? {
val component = SDSettingsComponent()
settingsComponent = component
return component.mainPanel
}
override fun isModified(): Boolean {
val state = SDSettings.getInstance().state
return settingsComponent!!.pdfModeBox.selectedItem != state.pdfMode
}
override fun apply() {
val state = SDSettings.getInstance().state
state.pdfMode = settingsComponent!!.pdfModeBox.selectedItem as PdfMode
}
override fun reset() {
val state = SDSettings.getInstance().state
settingsComponent!!.pdfModeBox.selectedItem = state.pdfMode
}
override fun disposeUIResources() {
settingsComponent = null
}
}

View File

@ -19,16 +19,7 @@ fun loggedOutDialogPanel(): DialogPanel = panel {
}
row {
button("Log In") {
SDLoginAction().actionPerformed(
AnActionEvent(
null,
DataContext.EMPTY_CONTEXT,
ActionPlaces.UNKNOWN,
Presentation(),
ActionManager.getInstance(),
0
)
)
SDLoginAction.perform()
}.align(Align.CENTER)
}
}.resizableColumn().align(AlignY.CENTER)

View File

@ -4,7 +4,7 @@ import com.intellij.openapi.ui.DialogWrapper
import com.intellij.ui.dsl.builder.AlignX
import com.intellij.ui.dsl.builder.bindText
import com.intellij.ui.dsl.builder.panel
import io.gitlab.jfronny.sdom.SDCredentials
import io.gitlab.jfronny.sdom.settings.SDCredentials
import javax.swing.JComponent
class SDLoginDialogWrapper : DialogWrapper(true) {

View File

@ -38,6 +38,10 @@
<toolWindow factoryClass="io.gitlab.jfronny.sdom.toolwindow.SDToolWindowFactory"
id="S-DOM" anchor="bottom" canCloseContents="true" icon="io.gitlab.jfronny.sdom.icons.SDIcons.ToolWindow" />
<notificationGroup id="sdom.notifications" displayType="BALLOON" />
<applicationConfigurable parentId="tools" instance="io.gitlab.jfronny.sdom.settings.SDSettingsConfigurable"
id="io.gitlab.jfronny.sdom.settings.SDSettingsConfigurable"
displayName="S-dom"/>
<applicationService serviceImplementation="io.gitlab.jfronny.sdom.settings.SDSettings"/>
</extensions>
<actions>
<group id="io.gitlab.jfronny.sdom.actions.SDToolbarActions" text="S-dom" popup="true"/>