瀏覽代碼

app tooltips

milan jurkulák 2 年之前
父節點
當前提交
fc3d16eba5

+ 4 - 5
buildSrc/src/main/kotlin/org/mjdev/gradle/extensions/ProjectExt.kt

@@ -1,10 +1,9 @@
 package org.mjdev.gradle.extensions
 
-import org.gradle.accessors.dm.LibrariesForLibs
-import org.gradle.api.*
+import org.gradle.api.Project
+import org.gradle.api.Task
 import org.gradle.internal.impldep.jakarta.xml.bind.DatatypeConverter
 import org.gradle.kotlin.dsl.extra
-import org.gradle.kotlin.dsl.the
 
 @Suppress("HasPlatformType", "unused", "MemberVisibilityCanBePrivate")
 object ProjectExt {
@@ -18,8 +17,8 @@ object ProjectExt {
     val Project.isAndroidStudio
         get() = project.extra.properties.keys.contains("android.studio.version")
 
-    val Project.libs
-        get() = the<LibrariesForLibs>()
+//    val Project.libs
+//        get() = the<LibrariesForLibs>()
 
 //    fun Project.apply(plugin: Provider<*>) =
 //        project.plugins.apply(plugin.get().toString())

+ 71 - 43
src/main/kotlin/eu/mjdev/desktop/components/desktoppanel/DesktopPanel.kt

@@ -1,6 +1,9 @@
 package eu.mjdev.desktop.components.desktoppanel
 
 import androidx.compose.animation.*
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.TooltipArea
+import androidx.compose.foundation.TooltipPlacement
 import androidx.compose.foundation.background
 import androidx.compose.foundation.gestures.Orientation
 import androidx.compose.foundation.layout.*
@@ -8,12 +11,15 @@ import androidx.compose.foundation.lazy.LazyRow
 import androidx.compose.foundation.lazy.items
 import androidx.compose.material.Divider
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.MutableState
 import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.mutableStateOf
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Brush
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.DpOffset
 import androidx.compose.ui.unit.DpSize
 import androidx.compose.ui.unit.dp
 import eu.mjdev.desktop.components.shadow.TopShadow
@@ -23,7 +29,9 @@ import eu.mjdev.desktop.components.slidemenu.VisibilityState.Companion.rememberV
 import eu.mjdev.desktop.extensions.Compose.SuperDarkGray
 import eu.mjdev.desktop.provider.DesktopProvider
 import eu.mjdev.desktop.provider.DesktopProvider.Companion.LocalDesktop
+import eu.mjdev.desktop.provider.data.App
 
+@OptIn(ExperimentalFoundationApi::class)
 @Suppress("FunctionName")
 @Composable
 fun DesktopPanel(
@@ -48,6 +56,8 @@ fun DesktopPanel(
     onVisibilityChange = onVisibilityChange
 ) { isVisible ->
     val favoriteApps = api.appsProvider.favoriteApps.collectAsState(emptyList())
+    val tooltipData: MutableState<Any?> = mutableStateOf(null)
+    val onToolTip: (item: Any?) -> Unit = { item -> tooltipData.value = item }
     if (!isVisible) {
         Divider(
             modifier = Modifier
@@ -62,62 +72,80 @@ fun DesktopPanel(
         enter = fadeIn() + slideInVertically(initialOffsetY = { it }),
         exit = slideOutVertically(targetOffsetY = { it }) + fadeOut(),
     ) {
-        TopShadow(
+        TooltipArea(
+            tooltip = {
+                // todo more types
+                when (tooltipData.value) {
+                    is App -> DesktopPanelAppTooltip(tooltipData.value as App)
+                    else -> {}
+                }
+            },
             modifier = Modifier.fillMaxWidth(),
-            color = shadowColor,
-            contentBackgroundColor = backgroundColor.copy(alpha = panelAlpha)
+            tooltipPlacement = TooltipPlacement.CursorPoint(
+                alignment = Alignment.TopEnd,
+                offset = DpOffset(16.dp, 32.dp)
+            )
         ) {
-            LazyRow(
-                modifier = Modifier.fillMaxWidth().wrapContentHeight().background(
-                    brush = Brush.verticalGradient(
-                        colors = listOf(
-                            backgroundColor.copy(alpha = 0.3f),
-                            backgroundColor.copy(alpha = 0.7f),
-                            backgroundColor.copy(alpha = 0.3f),
-                        )
-                    )
-                ),
-                horizontalArrangement = Arrangement.Start,
-                verticalAlignment = Alignment.CenterVertically
+            TopShadow(
+                modifier = Modifier.fillMaxWidth(),
+                color = shadowColor,
+                contentBackgroundColor = backgroundColor.copy(alpha = panelAlpha)
             ) {
-                if (showMenuIcon) {
-                    item {
+                LazyRow(
+                    modifier = Modifier.fillMaxWidth().wrapContentHeight().background(
+                        brush = Brush.verticalGradient(
+                            colors = listOf(
+                                backgroundColor.copy(alpha = 0.3f),
+                                backgroundColor.copy(alpha = 0.7f),
+                                backgroundColor.copy(alpha = 0.3f),
+                            )
+                        )
+                    ),
+                    horizontalArrangement = Arrangement.Start,
+                    verticalAlignment = Alignment.CenterVertically
+                ) {
+                    if (showMenuIcon) {
+                        item {
+                            DesktopPanelIcon(
+                                icon = "menu",
+                                iconColor = iconColor,
+                                iconBackgroundColor = iconBackgroundColor,
+                                iconBackgroundHover = Color.White.copy(alpha = 0.3f),
+                                iconSize = iconSize,
+                                iconPadding = iconPadding,
+                                onToolTip = onToolTip,
+                                onClick = {
+                                    onMenuIconClicked()
+                                }
+                            )
+                            Divider(
+                                modifier = Modifier
+                                    .padding(2.dp)
+                                    .height(iconSize.height - 8.dp)
+                                    .width(2.dp)
+                                    .background(Color.White.copy(alpha = 0.4f))
+                            )
+                        }
+                    }
+                    items(favoriteApps.value) { app ->
                         DesktopPanelIcon(
-                            icon = "menu",
+                            app = app,
                             iconColor = iconColor,
                             iconBackgroundColor = iconBackgroundColor,
                             iconBackgroundHover = Color.White.copy(alpha = 0.3f),
                             iconSize = iconSize,
                             iconPadding = iconPadding,
-                            onClick = {
-                                onMenuIconClicked()
-                            }
+                            onToolTip = onToolTip
                         )
-                        Divider(
-                            modifier = Modifier
-                                .padding(2.dp)
-                                .height(iconSize.height - 8.dp)
-                                .width(2.dp)
-                                .background(Color.White.copy(alpha = 0.4f))
+                    }
+                    item {
+                        DesktopPanelText(
+                            text = api.appsProvider.currentLocale.country,
+                            backgroundHover = Color.White.copy(alpha = 0.3f),
+                            onToolTip = onToolTip
                         )
                     }
                 }
-                items(favoriteApps.value) { app ->
-                    DesktopPanelIcon(
-                        app = app,
-                        iconColor = iconColor,
-                        iconBackgroundColor = iconBackgroundColor,
-                        iconBackgroundHover = Color.White.copy(alpha = 0.3f),
-                        iconSize = iconSize,
-                        iconPadding = iconPadding,
-                    )
-                }
-                item {
-                    DesktopPanelText(
-                        text = api.appsProvider.currentLocale.country,
-                        backgroundHover = Color.White.copy(alpha = 0.3f),
-                    )
-                }
             }
         }
     }

+ 47 - 0
src/main/kotlin/eu/mjdev/desktop/components/desktoppanel/DesktopPanelAppTooltip.kt

@@ -0,0 +1,47 @@
+package eu.mjdev.desktop.components.desktoppanel
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.wrapContentSize
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import eu.mjdev.desktop.components.text.TextAny
+import eu.mjdev.desktop.provider.DesktopProvider
+import eu.mjdev.desktop.provider.DesktopProvider.Companion.LocalDesktop
+import eu.mjdev.desktop.provider.data.App
+
+@Composable
+fun DesktopPanelAppTooltip(
+    app: App?,
+    api: DesktopProvider = LocalDesktop.current
+) = Box(
+    modifier = Modifier
+        .wrapContentSize()
+        .background(api.currentUser.theme.backgroundColor, RoundedCornerShape(8.dp))
+        .padding(4.dp)
+) {
+    if (app != null) {
+        Column {
+            if (app.name.isNotEmpty()) {
+                TextAny(
+                    text = app.name,
+                    color = Color.White,
+                    fontSize = 14.sp
+                )
+            }
+            if (app.comment.isNotEmpty()) {
+                TextAny(
+                    text = app.comment,
+                    color = Color.White,
+                    fontSize = 12.sp
+                )
+            }
+        }
+    }
+}

+ 4 - 1
src/main/kotlin/eu/mjdev/desktop/components/desktoppanel/DesktopPanelIcon.kt

@@ -1,6 +1,7 @@
 package eu.mjdev.desktop.components.desktoppanel
 
 import androidx.compose.desktop.ui.tooling.preview.Preview
+import androidx.compose.foundation.ExperimentalFoundationApi
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.PaddingValues
 import androidx.compose.foundation.layout.size
@@ -26,7 +27,7 @@ import eu.mjdev.desktop.provider.DesktopProvider
 import eu.mjdev.desktop.provider.DesktopProvider.Companion.LocalDesktop
 import eu.mjdev.desktop.provider.data.App
 
-@OptIn(ExperimentalComposeUiApi::class)
+@OptIn(ExperimentalComposeUiApi::class, ExperimentalFoundationApi::class)
 @Preview
 @Composable
 fun DesktopPanelIcon(
@@ -39,6 +40,7 @@ fun DesktopPanelIcon(
     iconSize: DpSize = DpSize(48.dp, 48.dp),
     iconPadding: PaddingValues = PaddingValues(4.dp),
     iconState: MutableState<Boolean> = remember { mutableStateOf(false) },
+    onToolTip: (item: Any?) -> Unit = {},
     onClick: () -> Unit = { app?.start() },
 ) {
     val materialIcon = api.appsProvider.iconForApp(app?.name ?: icon) ?: "?".toInt()
@@ -49,6 +51,7 @@ fun DesktopPanelIcon(
             .onPointerEvent(PointerEventType.Enter) {
                 if (api.windowFocusState.isFocused) {
                     iconState.value = true
+                    onToolTip(app)
                 }
             }
             .onPointerEvent(PointerEventType.Exit) {

+ 2 - 0
src/main/kotlin/eu/mjdev/desktop/components/desktoppanel/DesktopPanelText.kt

@@ -34,6 +34,7 @@ fun DesktopPanelText(
     textPadding: PaddingValues = PaddingValues(4.dp),
     buttonState: MutableState<Boolean> = remember { mutableStateOf(false) },
     api: DesktopProvider = LocalDesktop.current,
+    onToolTip: (item: Any?) -> Unit = {},
     onClick: () -> Unit = {},
 ) = Box(
     modifier = Modifier
@@ -41,6 +42,7 @@ fun DesktopPanelText(
         .onPointerEvent(PointerEventType.Enter) {
             if (api.windowFocusState.isFocused) {
                 buttonState.value = true
+                onToolTip(text)
             }
         }
         .onPointerEvent(PointerEventType.Exit) {

+ 18 - 14
src/main/kotlin/eu/mjdev/desktop/provider/AppsProvider.kt

@@ -3,6 +3,7 @@ package eu.mjdev.desktop.provider
 import com.google.gson.Gson
 import eu.mjdev.desktop.provider.data.App
 import eu.mjdev.desktop.provider.data.Category
+import eu.mjdev.desktop.provider.data.DesktopFile
 import kotlinx.coroutines.flow.flow
 import me.xdrop.fuzzywuzzy.FuzzySearch
 import java.io.File
@@ -37,17 +38,19 @@ class AppsProvider(
     private val iconThemes by lazy { iconsDir.listFiles() } // folders
     private val systemThemes by lazy { themesDir.listFiles() } // folders
 
-    private val autoStartDesktopFiles: List<File>
-        get() = autostartDesktopFilesDir.listFiles()?.toList() ?: emptyList() // List<DesktopFile>
-    private val allAppsDesktopFiles: List<File>
-        get() = allAppsDesktopFilesDir.listFiles()?.toList() ?: emptyList() // List<DesktopFile>
+    private val autoStartDesktopFiles
+        get() = autostartDesktopFilesDir.listFiles()?.map { DesktopFile(it) } ?: emptyList()
+
+    // todo probably not all here, need usr and local also
+    private val allAppsDesktopFiles
+        get() = allAppsDesktopFilesDir.listFiles()?.map { DesktopFile(it) } ?: emptyList()
 
     val currentLocale: Locale
         get() = userDirsLocale
     val autoStartApps
-        get() = autoStartDesktopFiles.map { file -> App(file) }
+        get() = autoStartDesktopFiles.map { file -> App(desktopFile = file, file = file.file) }
     val allApps
-        get() = allAppsDesktopFiles.map { file -> App(file) }
+        get() = allAppsDesktopFiles.map { file -> App(desktopFile = file, file = file.file) }
     val backgrounds
         get() = backgroundFilesDir.listFiles()?.toList() ?: emptyList<File>()
     val appCategories
@@ -69,8 +72,10 @@ class AppsProvider(
             map
         }
 
+    @Suppress("UNNECESSARY_SAFE_CALL")
     val favoriteApps
         get() = flow {
+            val desktopFiles = allAppsDesktopFiles
             desktopProvider.runCommandForOutput(
                 "gsettings",
                 "get",
@@ -78,15 +83,14 @@ class AppsProvider(
                 "favorite-apps"
             ).let { json ->
                 Gson().fromJson(json, List::class.java)
-            }.mapNotNull { deskFileName ->
-                allAppsDesktopFiles.firstOrNull { deskFile ->
-                    @Suppress("UNNECESSARY_SAFE_CALL")
-                    deskFile?.name?.contentEquals(deskFileName.toString()) == true
-                }.let {
-                    App(it)
+            }.mapNotNull { appName ->
+                desktopFiles.firstOrNull { deskFile ->
+                    deskFile?.file?.name?.contentEquals(appName.toString()) == true
+                }.let { deskFile ->
+                    App(desktopFile = deskFile, file = deskFile?.file)
                 }
-            }.also {
-                emit(it)
+            }.also { list ->
+                emit(list)
             }
         }
 

+ 1 - 1
src/main/kotlin/eu/mjdev/desktop/provider/data/App.kt

@@ -13,7 +13,7 @@ class App(
     val version
         get() = desktopFile?.version ?: ""
     val name
-        get() = desktopFile?.name ?: "-"
+        get() = desktopFile?.name ?: ""
     val comment
         get() = desktopFile?.comment ?: ""
     val path

+ 3 - 3
src/main/kotlin/eu/mjdev/desktop/provider/data/DesktopFile.kt

@@ -4,7 +4,7 @@ import java.io.File
 
 @Suppress("ConstPropertyName", "unused")
 class DesktopFile(
-    private val file: File
+    val file: File
 ) {
     private val props by lazy {
         file.readLines().mapNotNull { line ->
@@ -31,7 +31,7 @@ class DesktopFile(
         get() = props[Prop_Comment] ?: ""
 
     val path
-        get() = props[Prop_Path ] ?: ""
+        get() = props[Prop_Path] ?: ""
 
     val exec
         get() = props[Prop_Exec] ?: ""
@@ -60,7 +60,7 @@ class DesktopFile(
         const val Prop_Icon = "Icon" // string
         const val Prop_Categories = "Categories" // string delimited ;
 
-        private fun String.asBoolean() :Boolean = when(this.lowercase()) {
+        private fun String.asBoolean(): Boolean = when (this.lowercase()) {
             "true" -> true
             "1" -> true
             else -> false