From 0fdcb2a75451c4f224436e3a18c1613c17e75e2c Mon Sep 17 00:00:00 2001 From: Gauthier Roebroeck Date: Mon, 11 Dec 2023 16:52:23 +0800 Subject: [PATCH] feat(komga-tray): display dialog with error detail on application startup failure Closes: #1336 --- komga-tray/build.gradle.kts | 2 +- .../org/gotson/komga/DesktopApplication.kt | 18 ++- .../komga/application/gui/ErrorDialog.kt | 104 ++++++++++++++++++ .../org/gotson/komga/messages.properties | 5 + 4 files changed, 125 insertions(+), 4 deletions(-) create mode 100644 komga-tray/src/main/kotlin/org/gotson/komga/application/gui/ErrorDialog.kt diff --git a/komga-tray/build.gradle.kts b/komga-tray/build.gradle.kts index d00979a0..b3088191 100644 --- a/komga-tray/build.gradle.kts +++ b/komga-tray/build.gradle.kts @@ -32,7 +32,7 @@ tasks { dependencies { implementation(project(":komga")) - implementation(compose.desktop.common) + implementation(compose.desktop.currentOs) linuxAmd64(compose.desktop.linux_x64) macAmd64(compose.desktop.macos_x64) diff --git a/komga-tray/src/main/kotlin/org/gotson/komga/DesktopApplication.kt b/komga-tray/src/main/kotlin/org/gotson/komga/DesktopApplication.kt index aa97987c..2d7c74a9 100644 --- a/komga-tray/src/main/kotlin/org/gotson/komga/DesktopApplication.kt +++ b/komga-tray/src/main/kotlin/org/gotson/komga/DesktopApplication.kt @@ -1,7 +1,10 @@ package org.gotson.komga +import org.gotson.komga.application.gui.showErrorDialog import org.gotson.komga.infrastructure.util.checkTempDirectory import org.springframework.boot.builder.SpringApplicationBuilder +import org.springframework.boot.web.server.PortInUseException +import org.springframework.context.ApplicationContextException import org.springframework.scheduling.annotation.EnableAsync @EnableAsync @@ -14,8 +17,17 @@ fun main(args: Array) { System.setProperty("org.jooq.no-logo", "true") System.setProperty("org.jooq.no-tips", "true") - SpringApplicationBuilder(DesktopApplication::class.java).apply { - headless(false) - run(*args) + try { + SpringApplicationBuilder(DesktopApplication::class.java).apply { + headless(false) + run(*args) + } + } catch (e: ApplicationContextException) { + val (message, stackTrace) = when (e.cause) { + is PortInUseException -> RB.getString("error_message.port_in_use", (e.cause as PortInUseException).port) to null + else -> RB.getString("error_message.unexpected") to e.stackTraceToString() + } + + showErrorDialog(message, stackTrace) } } diff --git a/komga-tray/src/main/kotlin/org/gotson/komga/application/gui/ErrorDialog.kt b/komga-tray/src/main/kotlin/org/gotson/komga/application/gui/ErrorDialog.kt new file mode 100644 index 00000000..8f5e99c4 --- /dev/null +++ b/komga-tray/src/main/kotlin/org/gotson/komga/application/gui/ErrorDialog.kt @@ -0,0 +1,104 @@ +package org.gotson.komga.application.gui + +import androidx.compose.desktop.ui.tooling.preview.Preview +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.material.Button +import androidx.compose.material.Text +import androidx.compose.material.TextButton +import androidx.compose.material.TextField +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalClipboardManager +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.res.loadSvgPainter +import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.DpSize +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Window +import androidx.compose.ui.window.WindowPlacement +import androidx.compose.ui.window.WindowPosition +import androidx.compose.ui.window.WindowState +import androidx.compose.ui.window.application +import org.gotson.komga.RB +import org.springframework.core.io.ClassPathResource + +@Preview +fun showErrorDialog(text: String, stackTrace: String? = null) { + application { + Window( + title = RB.getString("dialog_error.title"), + onCloseRequest = ::exitApplication, + visible = true, + resizable = false, + state = WindowState( + placement = WindowPlacement.Floating, + position = WindowPosition(alignment = Alignment.Center), + size = DpSize( + if (stackTrace != null) 800.dp else Dp.Unspecified, + Dp.Unspecified, + ), + ), + icon = loadSvgPainter(ClassPathResource("icons/komga-color.svg").inputStream, LocalDensity.current), + ) { + Column( + modifier = Modifier.padding(16.dp), + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.padding(bottom = 16.dp), + ) { + Image( + painter = loadSvgPainter(ClassPathResource("icons/komga-color.svg").inputStream, LocalDensity.current), + contentDescription = "Komga logo", + modifier = Modifier + .size(96.dp) + .align(Alignment.Top), + ) + Text( + text, + modifier = Modifier.padding(start = 32.dp), + ) + } + if (stackTrace != null) + TextField( + value = stackTrace, + onValueChange = {}, + singleLine = false, + maxLines = 15, + modifier = Modifier.fillMaxWidth(), + ) + + Row( + horizontalArrangement = if (stackTrace != null) Arrangement.SpaceBetween else Arrangement.End, + modifier = if (stackTrace != null) + Modifier.align(Alignment.End).fillMaxWidth() + else + Modifier.align(Alignment.End), + ) { + if (stackTrace != null) { + val clipboardManager = LocalClipboardManager.current + TextButton( + onClick = { + clipboardManager.setText(AnnotatedString(stackTrace)) + }, + ) { + Text(RB.getString("dialog_error.copy_clipboard")) + } + } + Button( + onClick = { exitApplication() }, + ) { + Text(RB.getString("dialog_error.close")) + } + } + } + } + } +} diff --git a/komga-tray/src/main/resources/org/gotson/komga/messages.properties b/komga-tray/src/main/resources/org/gotson/komga/messages.properties index 6c1b55f6..a0388e12 100644 --- a/komga-tray/src/main/resources/org/gotson/komga/messages.properties +++ b/komga-tray/src/main/resources/org/gotson/komga/messages.properties @@ -1,3 +1,8 @@ +dialog_error.close=Close +dialog_error.copy_clipboard=Copy to clipboard +dialog_error.title=Komga failed to start +error_message.port_in_use=Port {} is already in use.\nKomga is probably already running.\nCheck the tray icon or menu bar for the Komga icon. +error_message.unexpected=An unexpected error occurred. menu.open_komga=Open Komga menu.quit=Quit Komga menu.show_conf_dir=Open configuration directory