diff --git a/composeApp/src/commonMain/kotlin/com/clipevery/AppConfig.kt b/composeApp/src/commonMain/kotlin/com/clipevery/AppConfig.kt new file mode 100644 index 000000000..90e2de194 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/clipevery/AppConfig.kt @@ -0,0 +1,3 @@ +package com.clipevery + +data class AppConfig(val bindingState: Boolean = false) diff --git a/composeApp/src/commonMain/kotlin/com/clipevery/ClipeveryApp.kt b/composeApp/src/commonMain/kotlin/com/clipevery/ClipeveryApp.kt index c246a406a..924d17a0b 100644 --- a/composeApp/src/commonMain/kotlin/com/clipevery/ClipeveryApp.kt +++ b/composeApp/src/commonMain/kotlin/com/clipevery/ClipeveryApp.kt @@ -1,55 +1,56 @@ package com.clipevery -import androidx.compose.animation.AnimatedVisibility -import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.material.Button import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.MutableState -import androidx.compose.runtime.getValue +import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.toComposeImageBitmap -import com.clipevery.clip.AbstractClipboard -import org.jetbrains.compose.resources.ExperimentalResourceApi -import java.awt.image.BufferedImage -@OptIn(ExperimentalResourceApi::class) @Composable -fun ClipeveryApp(clipboard: AbstractClipboard, copyText: MutableState, generateQRCode: BufferedImage) { +fun ClipeveryApp(dependencies: Dependencies) { MaterialTheme { - val pid: Long = ProcessHandle.current().pid() - var showImage by remember { mutableStateOf(false) } - var start by remember { mutableStateOf(true) } Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) { - Button(onClick = { - showImage = !showImage - }) { - Text(copyText.value) - } - Button(onClick = { - if (start) { - clipboard.stop() - } else { - clipboard.start() - } - start = !start - }) { - Text(start.toString() + " " + pid) - } - AnimatedVisibility(showImage) { - Image( - generateQRCode.toComposeImageBitmap(), -// painterResource("compose-multiplatform.xml"), - null - ) - } + ClipeveryCommon(dependencies) } } +} + + +@Composable +fun ClipeveryCommon(dependencies: Dependencies) { + CompositionLocalProvider( + LocalClipeveryServer provides dependencies.clipServer, + LocalConfigManager provides dependencies.configManager + ) { + ClipeveryWithProvidedDependencies() + } +} + +@Composable +fun ClipeveryWithProvidedDependencies() { + val configManager = LocalConfigManager.current + + val config = remember { mutableStateOf(configManager.config) } + + if (!config.value.bindingState) { + bindingQRCode() + } else { + mainUI() + } +} + + +@Composable +fun bindingQRCode() { + Text("bindingQRCode") +} + +@Composable +fun mainUI() { + Text("mainUI") } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/clipevery/Dependencies.kt b/composeApp/src/commonMain/kotlin/com/clipevery/Dependencies.kt new file mode 100644 index 000000000..9a23370c9 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/clipevery/Dependencies.kt @@ -0,0 +1,22 @@ +package com.clipevery + +import androidx.compose.runtime.staticCompositionLocalOf +import com.clipevery.net.ClipServer +import com.clipevery.net.ConfigManager + +abstract class Dependencies { + abstract val clipServer: ClipServer + abstract val configManager: ConfigManager +} + +internal val LocalClipeveryServer = staticCompositionLocalOf { + noLocalProvidedFor("ClipeveryServer") +} + +internal val LocalConfigManager = staticCompositionLocalOf { + noLocalProvidedFor("ConfigManager") +} + +private fun noLocalProvidedFor(name: String): Nothing { + error("CompositionLocal $name not present") +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/clipevery/clip/ClipboardEvent.kt b/composeApp/src/commonMain/kotlin/com/clipevery/clip/ClipboardEvent.kt deleted file mode 100644 index eaa8f3948..000000000 --- a/composeApp/src/commonMain/kotlin/com/clipevery/clip/ClipboardEvent.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.clipevery.clip - -import java.io.Serial -import java.util.EventObject - -class ClipboardEvent - (source: Any?) : EventObject(source) { - companion object { - @Serial - private val serialVersionUID = 6354639749124932240L - } -} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/clipevery/clip/ClipboardListener.kt b/composeApp/src/commonMain/kotlin/com/clipevery/clip/ClipboardListener.kt deleted file mode 100644 index 62e359949..000000000 --- a/composeApp/src/commonMain/kotlin/com/clipevery/clip/ClipboardListener.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.clipevery.clip - -import java.util.EventListener - - -interface ClipboardListener : EventListener { - fun onEvent(event: ClipboardEvent?) -} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/clipevery/clip/AbstractClipboard.kt b/composeApp/src/commonMain/kotlin/com/clipevery/clip/ClipboardService.kt similarity index 72% rename from composeApp/src/commonMain/kotlin/com/clipevery/clip/AbstractClipboard.kt rename to composeApp/src/commonMain/kotlin/com/clipevery/clip/ClipboardService.kt index 95b15449a..e082b5abe 100644 --- a/composeApp/src/commonMain/kotlin/com/clipevery/clip/AbstractClipboard.kt +++ b/composeApp/src/commonMain/kotlin/com/clipevery/clip/ClipboardService.kt @@ -3,7 +3,7 @@ package com.clipevery.clip import java.awt.datatransfer.Transferable import java.util.function.Consumer -interface AbstractClipboard: Runnable, ClipboardMonitor { +interface ClipboardService: Runnable, ClipboardMonitor { val clipConsumer: Consumer diff --git a/composeApp/src/commonMain/kotlin/com/clipevery/net/ClipServer.kt b/composeApp/src/commonMain/kotlin/com/clipevery/net/ClipServer.kt new file mode 100644 index 000000000..c686dfb27 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/clipevery/net/ClipServer.kt @@ -0,0 +1,10 @@ +package com.clipevery.net + +import com.clipevery.AppConfig + +interface ClipServer { +} + +interface ConfigManager { + val config: AppConfig +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/clipevery/utils/PlatformUtils.kt b/composeApp/src/commonMain/kotlin/com/clipevery/utils/PlatformUtils.kt new file mode 100644 index 000000000..bbcb835c5 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/clipevery/utils/PlatformUtils.kt @@ -0,0 +1,5 @@ +package com.clipevery.utils + +import kotlinx.coroutines.CoroutineDispatcher + +expect val ioDispatcher: CoroutineDispatcher diff --git a/composeApp/src/desktopMain/kotlin/com/clipevery/PlatformClipboard.kt b/composeApp/src/desktopMain/kotlin/com/clipevery/PlatformClipboard.kt index fd3196c6b..faaa9ceac 100644 --- a/composeApp/src/desktopMain/kotlin/com/clipevery/PlatformClipboard.kt +++ b/composeApp/src/desktopMain/kotlin/com/clipevery/PlatformClipboard.kt @@ -1,19 +1,23 @@ package com.clipevery -import com.clipevery.clip.AbstractClipboard -import com.clipevery.macos.MacosClipboard +import com.clipevery.clip.ClipboardService +import com.clipevery.macos.MacosClipboardService import com.clipevery.platform.currentPlatform -import com.clipevery.windows.WindowsClipboard +import com.clipevery.windows.WindowsClipboardService import java.awt.datatransfer.Transferable import java.util.function.Consumer -fun getClipboard(clipConsumer: Consumer): AbstractClipboard { +fun getClipboard(clipConsumer: Consumer): ClipboardService { val platform = currentPlatform() - return if (platform.name == "Macos") { - MacosClipboard(clipConsumer) - } else if (platform.name == "Windows") { - WindowsClipboard(clipConsumer) - } else { - throw Exception("Unknown platform: ${platform.name}") + return when (platform.name) { + "Macos" -> { + MacosClipboardService(clipConsumer) + } + "Windows" -> { + WindowsClipboardService(clipConsumer) + } + else -> { + throw Exception("Unknown platform: ${platform.name}") + } } } \ No newline at end of file diff --git a/composeApp/src/desktopMain/kotlin/com/clipevery/macos/MacosClipboard.kt b/composeApp/src/desktopMain/kotlin/com/clipevery/macos/MacosClipboardService.kt similarity index 92% rename from composeApp/src/desktopMain/kotlin/com/clipevery/macos/MacosClipboard.kt rename to composeApp/src/desktopMain/kotlin/com/clipevery/macos/MacosClipboardService.kt index 06f95eeff..133cdafd5 100644 --- a/composeApp/src/desktopMain/kotlin/com/clipevery/macos/MacosClipboard.kt +++ b/composeApp/src/desktopMain/kotlin/com/clipevery/macos/MacosClipboardService.kt @@ -1,6 +1,6 @@ package com.clipevery.macos -import com.clipevery.clip.AbstractClipboard +import com.clipevery.clip.ClipboardService import com.clipevery.macos.api.MacClipboard import java.awt.Toolkit import java.awt.datatransfer.Clipboard @@ -11,8 +11,8 @@ import java.util.concurrent.TimeUnit import java.util.function.Consumer -class MacosClipboard - (override val clipConsumer: Consumer) : AbstractClipboard { +class MacosClipboardService + (override val clipConsumer: Consumer) : ClipboardService { private var executor: ScheduledExecutorService? = null diff --git a/composeApp/src/desktopMain/kotlin/com/clipevery/utils/PlatformUtils.desktop.kt b/composeApp/src/desktopMain/kotlin/com/clipevery/utils/PlatformUtils.desktop.kt new file mode 100644 index 000000000..4c21c89bc --- /dev/null +++ b/composeApp/src/desktopMain/kotlin/com/clipevery/utils/PlatformUtils.desktop.kt @@ -0,0 +1,6 @@ +package com.clipevery.utils + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers + +actual val ioDispatcher: CoroutineDispatcher = Dispatchers.IO \ No newline at end of file diff --git a/composeApp/src/desktopMain/kotlin/com/clipevery/windows/WindowsClipboard.kt b/composeApp/src/desktopMain/kotlin/com/clipevery/windows/WindowsClipboardService.kt similarity index 96% rename from composeApp/src/desktopMain/kotlin/com/clipevery/windows/WindowsClipboard.kt rename to composeApp/src/desktopMain/kotlin/com/clipevery/windows/WindowsClipboardService.kt index f53fa5db9..8e33e3015 100644 --- a/composeApp/src/desktopMain/kotlin/com/clipevery/windows/WindowsClipboard.kt +++ b/composeApp/src/desktopMain/kotlin/com/clipevery/windows/WindowsClipboardService.kt @@ -1,6 +1,6 @@ package com.clipevery.windows -import com.clipevery.clip.AbstractClipboard +import com.clipevery.clip.ClipboardService import com.clipevery.windows.api.User32 import com.sun.jna.Pointer import com.sun.jna.platform.win32.Kernel32 @@ -17,8 +17,8 @@ import java.util.concurrent.TimeUnit import java.util.function.Consumer -class WindowsClipboard - (override val clipConsumer: Consumer) : AbstractClipboard, User32.WNDPROC { +class WindowsClipboardService + (override val clipConsumer: Consumer) : ClipboardService, User32.WNDPROC { private var systemClipboard: Clipboard = Toolkit.getDefaultToolkit().systemClipboard diff --git a/composeApp/src/desktopMain/kotlin/main.kt b/composeApp/src/desktopMain/kotlin/main.kt index ea589b217..883ca3fb5 100644 --- a/composeApp/src/desktopMain/kotlin/main.kt +++ b/composeApp/src/desktopMain/kotlin/main.kt @@ -1,43 +1,30 @@ -import androidx.compose.desktop.ui.tooling.preview.Preview -import androidx.compose.runtime.Composable +import androidx.compose.runtime.MutableState import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.ui.graphics.painter.BitmapPainter -import androidx.compose.ui.graphics.toComposeImageBitmap +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.res.painterResource import androidx.compose.ui.window.Tray import androidx.compose.ui.window.Window import androidx.compose.ui.window.application +import com.clipevery.AppConfig import com.clipevery.ClipeveryApp -import com.clipevery.getClipboard -import com.clipevery.utils.generateQRCode -import org.jetbrains.skia.Image -import java.awt.datatransfer.DataFlavor -import java.awt.datatransfer.Transferable -import java.awt.image.BufferedImage -import java.io.InputStream -import java.util.function.Consumer +import com.clipevery.Dependencies +import com.clipevery.net.ClipServer +import com.clipevery.net.ConfigManager +import com.clipevery.utils.ioDispatcher +import kotlinx.coroutines.CoroutineScope import kotlin.system.exitProcess fun main() = application { - val copyText = remember { mutableStateOf("Hello World!") } - val consumer = Consumer { - if (it.isDataFlavorSupported(DataFlavor.stringFlavor)) { - try { - copyText.value = it.getTransferData(DataFlavor.stringFlavor).toString() - println(it.getTransferData(DataFlavor.stringFlavor)) - } catch (e: Exception) { - e.printStackTrace() - } - } - } - val clipboard = getClipboard(consumer) - clipboard.start() - - val imageBitmap = loadIconFromResources("clipevery_icon.png") + val ioScope = rememberCoroutineScope { ioDispatcher } + val bingingState = remember { mutableStateOf(false) } + val dependencies = remember { + getDependencies(ioScope, bingingState) + } - Tray(icon = imageBitmap, + Tray(icon = painterResource("clipevery_icon.png"), menu = { Item( "Exit", @@ -46,42 +33,29 @@ fun main() = application { } ) - val generateQRCode: BufferedImage = generateQRCode("Hello World!", 200, 200) - Window(onCloseRequest = ::exitApplication, title = "Clipevery", - icon = imageBitmap, + icon = painterResource("clipevery_icon.png"), undecorated = true, - resizable = false) { - ClipeveryApp(clipboard, copyText, generateQRCode) + resizable = true) { + ClipeveryApp(dependencies) } } -fun loadIconFromResources(resourceName: String): BitmapPainter { - val resourceStream: InputStream? = Thread.currentThread().contextClassLoader.getResourceAsStream(resourceName) - resourceStream?.let { - val image = Image.makeFromEncoded(it.readAllBytes()) - return BitmapPainter(image.toComposeImageBitmap()) +private fun getDependencies( + ioScope: CoroutineScope, + bingingState: MutableState +) = object : Dependencies() { + override val clipServer: ClipServer = object : ClipServer { } - throw IllegalArgumentException("Resource not found: $resourceName") -} -@Preview -@Composable -fun AppDesktopPreview() { - val copyText = remember { mutableStateOf("Hello World!") } - val consumer = Consumer { - if (it.isDataFlavorSupported(DataFlavor.stringFlavor)) { - try { - copyText.value = it.getTransferData(DataFlavor.stringFlavor).toString() - println(it.getTransferData(DataFlavor.stringFlavor)) - } catch (e: Exception) { - e.printStackTrace() - } - } + override val configManager: ConfigManager = object : ConfigManager { + override val config: AppConfig = AppConfig(false) // todo: read from disk config file } - val clipboard = getClipboard(consumer) - val generateQRCode: BufferedImage = generateQRCode("Hello World!", 200, 200) +} - ClipeveryApp(clipboard, copyText, generateQRCode) -} \ No newline at end of file +//@Preview +//@Composable +//fun AppDesktopPreview() { +// ClipeveryApp(clipeveryAppState) +//} \ No newline at end of file