diff --git a/CLAUDE.md b/CLAUDE.md index 2b8c39d..ea62adb 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -37,6 +37,7 @@ Always stage newly created files that permanently belong to the project with `gi - One class per file — file name matches the class name. - No wildcard imports (`import foo.*`). - Code, comments, and documentation in English. +- Exceptions: always handle or at least log them (with full stacktrace). ## macOS Notes diff --git a/build.gradle.kts b/build.gradle.kts index 62a6c24..ed942ac 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -41,6 +41,9 @@ compose.desktop { application { mainClass = "ch.ergon.anytask.MainKt" + // Allow access to AWT Classes to control the window + jvmArgs("--add-opens", "java.desktop/com.apple.eawt=ALL-UNNAMED") + nativeDistributions { targetFormats(TargetFormat.Dmg) packageName = "AnyTask" diff --git a/src/main/kotlin/ch/ergon/anytask/Main.kt b/src/main/kotlin/ch/ergon/anytask/Main.kt index 08e3b66..5f9514e 100644 --- a/src/main/kotlin/ch/ergon/anytask/Main.kt +++ b/src/main/kotlin/ch/ergon/anytask/Main.kt @@ -61,14 +61,33 @@ fun main() { alwaysOnTop = true, undecorated = false, ) { + LaunchedEffect(isVisible) { + if (isVisible) { + activateMacOsApp() + window.toFront() + window.requestFocus() + } + } TaskWindow( client = client, + isVisible = isVisible, onDismiss = { isVisible = false } ) } } } +private fun activateMacOsApp() { + if (!System.getProperty("os.name").contains("Mac", ignoreCase = true)) return + try { + val appClass = Class.forName("com.apple.eawt.Application") + val app = appClass.getMethod("getApplication").invoke(null) + appClass.getMethod("requestForeground", Boolean::class.java).invoke(app, true) + } catch (e: Exception) { + logger.error("Failed to activate macOS app", e) + } +} + private fun setupSystemTray(onShow: () -> Unit, onExit: () -> Unit) { if (!SystemTray.isSupported()) return diff --git a/src/main/kotlin/ch/ergon/anytask/ui/TaskWindow.kt b/src/main/kotlin/ch/ergon/anytask/ui/TaskWindow.kt index c7c02aa..db8e115 100644 --- a/src/main/kotlin/ch/ergon/anytask/ui/TaskWindow.kt +++ b/src/main/kotlin/ch/ergon/anytask/ui/TaskWindow.kt @@ -13,7 +13,7 @@ import ch.ergon.anytask.api.AnyTypeApi import kotlinx.coroutines.launch @Composable -fun TaskWindow(client: AnyTypeApi, onDismiss: () -> Unit) { +fun TaskWindow(client: AnyTypeApi, isVisible: Boolean, onDismiss: () -> Unit) { val scope = rememberCoroutineScope() var title by remember { mutableStateOf("") } var details by remember { mutableStateOf("") } @@ -43,7 +43,7 @@ fun TaskWindow(client: AnyTypeApi, onDismiss: () -> Unit) { Column( modifier = Modifier .padding(24.dp) - .onKeyEvent { event -> + .onPreviewKeyEvent { event -> when { event.type == KeyEventType.KeyDown && event.key == Key.Escape -> { onDismiss(); true @@ -96,5 +96,5 @@ fun TaskWindow(client: AnyTypeApi, onDismiss: () -> Unit) { } } - LaunchedEffect(Unit) { focusRequester.requestFocus() } + LaunchedEffect(isVisible) { if (isVisible) focusRequester.requestFocus() } }