| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296 |
- package org.mjdev.desktop.context
- import androidx.compose.runtime.Composable
- import androidx.compose.runtime.remember
- import androidx.compose.runtime.rememberCoroutineScope
- import androidx.compose.ui.unit.DpSize
- import androidx.compose.ui.unit.dp
- import coil3.Bitmap
- import coil3.ImageLoader
- import coil3.PlatformContext
- import coil3.compose.LocalPlatformContext
- import coil3.request.ImageRequest
- import coil3.toBitmap
- import kotlinx.coroutines.CoroutineScope
- import kotlinx.coroutines.Dispatchers
- import kotlinx.coroutines.launch
- import okio.Path
- import org.mjdev.desktop.data.Category
- import org.mjdev.desktop.data.User
- import org.mjdev.desktop.extensions.Compose.isDesign
- import org.mjdev.desktop.helpers.application.ApplicationScope
- import org.mjdev.desktop.helpers.image.ImageLoader.asyncImageLoader
- import org.mjdev.desktop.managers.palette.Palette
- import org.mjdev.desktop.helpers.system.shell.Shell
- import org.mjdev.desktop.interfaces.IApp
- import org.mjdev.desktop.managers.connectivity.IConnectivityManager
- import org.mjdev.desktop.interfaces.IDesktopContext
- import org.mjdev.desktop.interfaces.IPalette
- import org.mjdev.desktop.interfaces.ITheme
- import org.mjdev.desktop.interfaces.IUser
- import org.mjdev.desktop.managers.language.Translator
- import org.mjdev.desktop.log.Log
- import org.mjdev.desktop.managers.ai.IAiManager
- import org.mjdev.desktop.managers.apps.IAppsManager
- import org.mjdev.desktop.managers.os.IOSManager
- import org.mjdev.desktop.managers.process.IProcessManager
- import org.mjdev.desktop.managers.theme.IThemeManager
- import org.mjdev.desktop.managers.translations.ITranslator
- import org.mjdev.desktop.managers.apps.AppsManager
- import org.mjdev.desktop.managers.ai.AIManager.Companion.AiManager
- import org.mjdev.desktop.managers.ai.plugins.AiPluginGemini
- import org.mjdev.desktop.managers.ai.tts.TTSPluginSwift
- import org.mjdev.desktop.managers.base.IDelegate
- import org.mjdev.desktop.managers.connectivity.ConnectivityManager
- import org.mjdev.desktop.managers.os.OsManager
- import org.mjdev.desktop.managers.processes.ProcessManager
- import org.mjdev.desktop.managers.theme.ThemeManager
- import java.awt.Desktop
- import java.awt.Toolkit
- import java.io.File
- import java.net.URI
- import kotlin.coroutines.CoroutineContext
- import kotlin.reflect.KClass
- import kotlin.reflect.full.companionObject
- class DesktopContext(
- val application: ApplicationScope? = null,
- override val scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
- override val imageLoader: ImageLoader? = null,
- val isInDesign: Boolean = false,
- override val platformContext: PlatformContext? = null
- ) : IDesktopContext() {
- private val toolkit: Toolkit by lazy { Toolkit.getDefaultToolkit() }
- private val desktopUtils: Desktop by lazy { Desktop.getDesktop() }
- // val windowsManager by lazy { WindowsManager(this) }
- // val dbus: DBus by lazy { DBus() }
- override var isFirstStart: Boolean = true // todo
- override var isInstalled: Boolean = false // todo
- override val appArgs: List<String>
- get() = application?.args ?: emptyList()
- override val isDebug: Boolean
- get() = appArgs.contains(APP_PARAM_DEBUG) || isInDesign
- val allUsers
- get() = User.allUsers(this)
- override val currentLocale
- get() = appsManager.currentLocale
- override val machineName
- get() = osManager.machineName
- override val allApps: List<IApp>
- get() = appsManager.allApps
- override val appCategories: List<Category>
- get() = appsManager.categories
- override val favoriteApps: List<IApp>
- get() = appsManager.favoriteApps
- override suspend fun open(what: Any?) {
- open(what.toString())
- }
- // todo state
- override val currentUser: IUser
- get() = allUsers.firstOrNull { u -> u.isLoggedIn } ?: User.DEFAULT
- override val theme: ITheme
- get() = currentUser.theme
- override val containerSize: DpSize
- get() = runCatching {
- toolkit.screenSize.let { screen -> DpSize(screen.width.dp, screen.height.dp) }
- }.getOrNull() ?: DpSize.Zero
- override val isLandscapeMode: Boolean
- get() = containerSize.let { it.width > it.height }
- // init {
- // Log.i("Got app args: $args")
- // runCatching {
- // windowsManager.init()
- // }
- // runCatching {
- // mounts.init()
- // }
- // runCatching {
- // dbus.updateEnvironment()
- // }
- // }
- override fun dispose() {
- Log.i("Cleaning up resources.")
- processManager.dispose()
- palette.dispose()
- theme.dispose()
- // runCatching {
- // mounts.dispose()
- // }
- // runCatching {
- // kcefHelper.dispose()
- // }
- // runCatching {
- // windowsManager.dispose()
- // }
- }
- fun runAsync(
- context: CoroutineContext = Dispatchers.Default,
- block: suspend () -> Unit
- ) {
- scope.launch(context) { block() }
- }
- suspend fun openMail(emailAddress: String) = runCatching {
- desktopUtils.mail(URI.create("mailto:$emailAddress"))
- }
- suspend fun openBrowser(url: String) = runCatching {
- desktopUtils.browse(URI.create(url))
- }
- suspend fun openDirectoryForFile(path: String) = runCatching {
- desktopUtils.browseFileDirectory(File(path))
- }
- suspend fun moveToTrash(file: File) = runCatching {
- desktopUtils.moveToTrash(file)
- }
- suspend fun moveToTrash(filePath: String) = runCatching {
- moveToTrash(File(filePath))
- }
- // todo, may be need another function
- suspend fun open(what: String) {
- Shell.executeAndRead("xdg-open", what)
- }
- suspend fun openFileInAssociated(file: File) = runCatching {
- desktopUtils.open(file)
- }
- suspend fun openFileInAssociated(filePath: String) = runCatching {
- openFileInAssociated(File(filePath))
- }
- // suspend fun beep() = runCatching {
- // toolkit.beep()
- // }
- // suspend fun sync() = runCatching {
- // toolkit.sync()
- // }
- // suspend fun createCustomCursor(cursor: Image, hotSpot: Point, name: String): Cursor? = runCatching {
- // toolkit.createCustomCursor(cursor, hotSpot, name)
- // }.getOrNull()
- // suspend fun createCustomCursor(cursor: Bitmap, hotSpot: Point, name: String): Cursor? = runCatching {
- // toolkit.createCustomCursor(cursor.image, hotSpot, name)
- // }.getOrNull()
- // suspend fun createCustomCursor(cursor: ImageBitmap, hotSpot: Point, name: String): Cursor? = runCatching {
- // toolkit.createCustomCursor(cursor.toAwtImage(), hotSpot, name)
- // }.getOrNull()
- // suspend fun createCustomCursor(cursor: ImageVector, hotSpot: Point, name: String) =
- // toolkit.createCustomCursor(cursor, hotSpot, name)
- // @Suppress("UNUSED_PARAMETER")
- // override suspend fun login(
- // uname: String,
- // upasswd: String
- // ): Boolean = true // todo
- // override suspend fun logout() : Boolean = true // todo
- fun lock() = runAsync {
- Shell.executeAndRead("/usr/bin/loginctl", "lock-sessions")
- }
- override suspend fun logOut(): Unit = runAsync {
- application?.exitApplication()
- }
- override suspend fun suspend() {
- Shell.executeAndRead("/usr/bin/systemctl", "suspend")
- }
- override suspend fun shutdown() {
- Shell.executeAndRead("/usr/sbin/halt", "--poweroff")
- }
- override suspend fun login(uName: String, uPasswd: String): Boolean {
- return false // todo
- }
- override suspend fun logout(): Boolean {
- return false // todo
- }
- override fun createManager(cls: KClass<*>): IDelegate = when (cls) {
- IOSManager::class -> OsManager(this)
- IPalette::class -> Palette(this)
- ITranslator::class -> Translator(this)
- IConnectivityManager::class -> ConnectivityManager(this)
- IAiManager::class -> AiManager(this).apply {
- // todo user can configure
- pluginAI = AiPluginGemini(this@DesktopContext)
- pluginTTS = TTSPluginSwift(this@DesktopContext)
- }
- IAppsManager::class -> AppsManager(this)
- IThemeManager::class -> ThemeManager(this)
- IProcessManager::class -> ProcessManager(this)
- else -> cls.companionObject?.members?.first { it.name == "EMPTY" }?.call() as IDelegate
- }
- override suspend fun restart() {
- Shell.executeAndRead("/usr/sbin/halt", "--reboot")
- }
- // suspend fun Desktop.startApp(app: App) {
- // startApp(app.desktopFile)
- // }
- // suspend fun Desktop.startApp(
- // desktopFile: DesktopFile?
- // ) = withContext(Dispatchers.Default) {
- // open(desktopFile?.file)
- // }
- companion object {
- // todo application
- @Composable
- fun rememberDesktopContext(
- application: ApplicationScope?,
- imageLoader: ImageLoader = asyncImageLoader(),
- platformContext: PlatformContext = LocalPlatformContext.current,
- scope: CoroutineScope = rememberCoroutineScope(),
- isInDesign: Boolean = isDesign,
- ) = remember {
- Log.i("default initialized desktop provider created")
- DesktopContext(
- application = application,
- scope = scope,
- imageLoader = imageLoader,
- isInDesign = isInDesign,
- platformContext = platformContext
- )
- }
- suspend fun IDesktopContext.loadPicture(
- src: Any?
- ): Bitmap? = runCatching {
- ImageRequest.Builder(platformContext!!)
- .data(
- when (src) {
- is Path -> src.toFile()
- else -> src.toString()
- }
- )
- .build().let { req ->
- imageLoader?.execute(req)?.image?.toBitmap()
- }
- }.getOrNull()
- }
- }
|