commit 23666e55283a5b1f76f2533dff78d0154464707e
parent f854b217a2510ce5822717abc10fcc9ad190b289
Author: rhunk <101876869+rhunk@users.noreply.github.com>
Date: Thu, 2 Jan 2025 18:32:37 +0100
feat(app/ui): top bar action button text
Signed-off-by: rhunk <101876869+rhunk@users.noreply.github.com>
Diffstat:
7 files changed, 131 insertions(+), 79 deletions(-)
diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/ui/manager/pages/TasksRootSection.kt b/app/src/main/kotlin/me/rhunk/snapenhance/ui/manager/pages/TasksRootSection.kt
@@ -36,6 +36,7 @@ import me.rhunk.snapenhance.bridge.DownloadCallback
import me.rhunk.snapenhance.common.data.download.DownloadMetadata
import me.rhunk.snapenhance.common.data.download.MediaDownloadSource
import me.rhunk.snapenhance.common.data.download.createNewFilePath
+import me.rhunk.snapenhance.common.ui.TopBarActionButton
import me.rhunk.snapenhance.common.ui.rememberAsyncMutableState
import me.rhunk.snapenhance.common.util.ktx.longHashCode
import me.rhunk.snapenhance.download.DownloadProcessor
@@ -149,13 +150,15 @@ class TasksRootSection : Routes.Route() {
}
if (canMergeSelection) {
- IconButton(onClick = {
- mergeSelection(taskSelection.toList().also {
- taskSelection.clear()
- }.map { it.first to it.second!! })
- }) {
- Icon(Icons.Filled.Merge, contentDescription = "Merge")
- }
+ TopBarActionButton(
+ onClick = {
+ mergeSelection(taskSelection.toList().also {
+ taskSelection.clear()
+ }.map { it.first to it.second!! })
+ },
+ icon = Icons.Filled.Merge,
+ text = translation["merge_button"]
+ )
}
}
@@ -312,14 +315,14 @@ class TasksRootSection : Routes.Route() {
.pointerInput(Unit) {
detectTapGestures(
onTap = {
- if (taskSelection.size > 0) {
+ if (taskSelection.isNotEmpty()) {
toggleSelection()
return@detectTapGestures
}
openFile()
},
onLongPress = {
- if (taskSelection.size > 0) {
+ if (taskSelection.isNotEmpty()) {
openFile()
return@detectTapGestures
}
diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/ui/manager/pages/features/FeaturesRootSection.kt b/app/src/main/kotlin/me/rhunk/snapenhance/ui/manager/pages/features/FeaturesRootSection.kt
@@ -37,6 +37,7 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import me.rhunk.snapenhance.common.config.*
+import me.rhunk.snapenhance.common.ui.TopBarActionButton
import me.rhunk.snapenhance.common.ui.rememberAsyncMutableStateList
import me.rhunk.snapenhance.common.ui.transparentTextFieldColors
import me.rhunk.snapenhance.ui.manager.MainActivity
@@ -531,16 +532,26 @@ class FeaturesRootSection : Routes.Route() {
}
}
- IconButton(onClick = {
- showSearchBar = showSearchBar.not()
- if (!showSearchBar && routes.currentDestination == SEARCH_FEATURE_ROUTE) {
- navigateToMainRoot()
+
+ if (showSearchBar) {
+ IconButton(onClick = {
+ showSearchBar = false
+ if (routes.currentDestination == SEARCH_FEATURE_ROUTE) {
+ navigateToMainRoot()
+ }
+ }) {
+ Icon(
+ imageVector = Icons.Filled.Close,
+ contentDescription = null
+ )
}
- }) {
- Icon(
- imageVector = if (showSearchBar) Icons.Filled.Close
- else Icons.Filled.Search,
- contentDescription = null
+ } else {
+ TopBarActionButton(
+ onClick = {
+ showSearchBar = true
+ },
+ icon = Icons.Filled.Search,
+ text = translation["search_button"]
)
}
diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/ui/manager/pages/home/HomeRootSection.kt b/app/src/main/kotlin/me/rhunk/snapenhance/ui/manager/pages/home/HomeRootSection.kt
@@ -1,7 +1,5 @@
package me.rhunk.snapenhance.ui.manager.pages.home
-import android.content.Intent
-import android.net.Uri
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
@@ -38,8 +36,10 @@ import me.rhunk.snapenhance.R
import me.rhunk.snapenhance.action.EnumQuickActions
import me.rhunk.snapenhance.common.BuildConfig
import me.rhunk.snapenhance.common.action.EnumAction
+import me.rhunk.snapenhance.common.ui.TopBarActionButton
import me.rhunk.snapenhance.common.ui.rememberAsyncMutableState
import me.rhunk.snapenhance.common.ui.rememberAsyncMutableStateList
+import me.rhunk.snapenhance.common.util.ktx.openLink
import me.rhunk.snapenhance.core.ui.Snapenhance
import me.rhunk.snapenhance.storage.getQuickTiles
import me.rhunk.snapenhance.storage.setQuickTiles
@@ -55,7 +55,6 @@ class HomeRootSection : Routes.Route() {
private lateinit var activityLauncherHelper: ActivityLauncherHelper
-
private val cards by lazy {
EnumQuickActions.entries.map {
(context.translation["actions.${it.key}.name"] to it.icon) to it.action
@@ -93,24 +92,11 @@ class HomeRootSection : Routes.Route() {
}
}
- private fun openExternalLink(link: String) {
- kotlin.runCatching {
- context.activity?.startActivity(Intent(Intent.ACTION_VIEW).apply {
- flags = Intent.FLAG_ACTIVITY_NEW_TASK
- data = Uri.parse(link)
- })
- }.onFailure {
- context.log.error("Failed to open external link", it)
- context.shortToast("Failed to open external link. Check logs for more details.")
- }
- }
-
@Composable
fun ExternalLinkIcon(
modifier: Modifier = Modifier,
size: Dp = 32.dp,
imageVector: ImageVector,
- link: String
) {
Icon(
imageVector = imageVector,
@@ -120,31 +106,41 @@ class HomeRootSection : Routes.Route() {
.size(size)
.clip(RoundedCornerShape(50))
.then(modifier)
- .clickable { openExternalLink(link) }
)
}
+ override val title: @Composable (() -> Unit)? = {}
override val init: () -> Unit = {
activityLauncherHelper = ActivityLauncherHelper(context.activity!!)
}
override val topBarActions: @Composable (RowScope.() -> Unit) = {
- IconButton(onClick = {
- routes.homeLogs.navigate()
- }) {
- Icon(Icons.Filled.BugReport, contentDescription = null)
- }
- IconButton(onClick = {
- routes.settings.navigate()
- }) {
- Icon(Icons.Filled.Settings, contentDescription = null)
- }
+ TopBarActionButton(
+ onClick = {
+ routes.homeLogs.navigate()
+ },
+ icon = Icons.Filled.BugReport,
+ text = context.translation["manager.routes.home_logs"]
+ )
+ Spacer(modifier = Modifier.width(8.dp))
+ TopBarActionButton(
+ onClick = {
+ routes.settings.navigate()
+ },
+ icon = Icons.Filled.Settings,
+ text = context.translation["manager.routes.home_settings"]
+ )
}
-
@OptIn(ExperimentalLayoutApi::class)
override val content: @Composable (NavBackStackEntry) -> Unit = {
+ val avenirNext = remember {
+ FontFamily(
+ Font(R.font.avenir_next_medium, FontWeight.Medium)
+ )
+ }
+
Column(
modifier = Modifier
.fillMaxSize()
@@ -164,12 +160,8 @@ class HomeRootSection : Routes.Route() {
"version_title",
"versionName" to BuildConfig.VERSION_NAME
),
- fontSize = 12.sp,
- fontFamily = remember {
- FontFamily(
- Font(R.font.avenir_next_medium, FontWeight.Medium)
- )
- },
+ fontSize = 14.sp,
+ fontFamily = avenirNext,
modifier = Modifier.align(Alignment.CenterHorizontally),
)
@@ -183,25 +175,32 @@ class HomeRootSection : Routes.Route() {
.padding(all = 5.dp)
) {
ExternalLinkIcon(
+ modifier = Modifier.clickable {
+ context.androidContext.openLink("https://codeberg.org/SnapEnhance/SnapEnhance")
+ },
imageVector = ImageVector.vectorResource(id = R.drawable.ic_codeberg),
- link = "https://codeberg.org/SnapEnhance/SnapEnhance"
)
ExternalLinkIcon(
+ modifier = Modifier.clickable {
+ context.androidContext.openLink("https://t.me/snapenhance")
+ },
imageVector = ImageVector.vectorResource(id = R.drawable.ic_telegram),
- link = "https://t.me/snapenhance"
)
ExternalLinkIcon(
+ modifier = Modifier.clickable {
+ context.androidContext.openLink("https://github.com/rhunk/SnapEnhance")
+ },
imageVector = ImageVector.vectorResource(id = R.drawable.ic_github),
- link = "https://github.com/rhunk/SnapEnhance"
)
ExternalLinkIcon(
- modifier = Modifier.offset(x = (-3).dp),
+ modifier = Modifier.offset(x = (-3).dp).clickable {
+ context.androidContext.openLink("https://github.com/rhunk/SnapEnhance/wiki")
+ },
size = 40.dp,
imageVector = Icons.AutoMirrored.Default.Help,
- link = "https://github.com/rhunk/SnapEnhance/wiki",
)
}
@@ -238,7 +237,7 @@ class HomeRootSection : Routes.Route() {
Button(
modifier = Modifier.height(40.dp),
onClick = {
- latestUpdate?.releaseUrl?.let { openExternalLink(it) }
+ latestUpdate?.releaseUrl?.let { context.androidContext.openLink(it) }
}
) {
Text(text = translation["update_button"])
@@ -294,7 +293,7 @@ class HomeRootSection : Routes.Route() {
buildSummary.getStringAnnotations(
tag = "git_hash", start = offset, end = offset
).firstOrNull()?.let {
- openExternalLink("https://codeberg.org/SnapEnhance/SnapEnhance/commit/${it.item}")
+ context.androidContext.openLink("https://codeberg.org/SnapEnhance/SnapEnhance/commit/${it.item}")
}
}
)
diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/ui/manager/pages/scripting/ScriptingRootSection.kt b/app/src/main/kotlin/me/rhunk/snapenhance/ui/manager/pages/scripting/ScriptingRootSection.kt
@@ -5,7 +5,6 @@ import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.automirrored.filled.LibraryBooks
import androidx.compose.material.icons.filled.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
@@ -20,7 +19,6 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
-import androidx.core.net.toUri
import androidx.navigation.NavBackStackEntry
import kotlinx.coroutines.*
import me.rhunk.snapenhance.common.scripting.type.ModuleInfo
@@ -28,9 +26,11 @@ import me.rhunk.snapenhance.common.scripting.ui.EnumScriptInterface
import me.rhunk.snapenhance.common.scripting.ui.InterfaceManager
import me.rhunk.snapenhance.common.scripting.ui.ScriptInterface
import me.rhunk.snapenhance.common.ui.AsyncUpdateDispatcher
+import me.rhunk.snapenhance.common.ui.TopBarActionButton
import me.rhunk.snapenhance.common.ui.rememberAsyncMutableState
import me.rhunk.snapenhance.common.ui.rememberAsyncUpdateDispatcher
import me.rhunk.snapenhance.common.util.ktx.getUrlFromClipboard
+import me.rhunk.snapenhance.common.util.ktx.openLink
import me.rhunk.snapenhance.storage.isScriptEnabled
import me.rhunk.snapenhance.storage.setScriptEnabled
import me.rhunk.snapenhance.ui.manager.Routes
@@ -395,6 +395,9 @@ class ScriptingRootSection : Routes.Route() {
) {
ExtendedFloatingActionButton(
onClick = {
+ if (context.scriptManager.getScriptsFolder() == null) {
+ return@ExtendedFloatingActionButton
+ }
showImportDialog = true
},
icon = { Icon(imageVector = Icons.Default.Link, contentDescription = "Link") },
@@ -405,12 +408,7 @@ class ScriptingRootSection : Routes.Route() {
ExtendedFloatingActionButton(
onClick = {
context.scriptManager.getScriptsFolder()?.let {
- context.androidContext.startActivity(
- Intent(Intent.ACTION_VIEW).apply {
- data = it.uri
- flags = Intent.FLAG_ACTIVITY_NEW_TASK
- }
- )
+ context.androidContext.openLink(it.uri.toString())
}
},
icon = {
@@ -576,16 +574,12 @@ class ScriptingRootSection : Routes.Route() {
}
override val topBarActions: @Composable() (RowScope.() -> Unit) = {
- IconButton(onClick = {
- context.androidContext.startActivity(Intent(Intent.ACTION_VIEW).apply {
- data = "https://codeberg.org/SnapEnhance/scripting-docs".toUri()
- flags = Intent.FLAG_ACTIVITY_NEW_TASK
- })
- }) {
- Icon(
- imageVector = Icons.AutoMirrored.Default.LibraryBooks,
- contentDescription = "Documentation"
- )
- }
+ TopBarActionButton(
+ onClick = {
+ context.androidContext.openLink("https://codeberg.org/SnapEnhance/scripting-docs")
+ },
+ icon = Icons.Default.CollectionsBookmark,
+ text = "Documentation",
+ )
}
}
\ No newline at end of file
diff --git a/common/src/main/assets/lang/en_US.json b/common/src/main/assets/lang/en_US.json
@@ -77,6 +77,7 @@
},
"tasks": {
"no_tasks": "No tasks",
+ "merge_button": "Merge",
"failed_to_open_file": "Failed to open file",
"merge_files_toast": "Merging {count} files",
"remove_selected_tasks_title": "Are you sure you want to remove selected tasks?",
@@ -96,7 +97,8 @@
"config_export_failure_toast": "Failed to export config {error}",
"saved_config_snackbar": "Config saved",
"older_required": "This feature requires Snapchat v{version} or older to work correctly",
- "newer_required": "This feature requires Snapchat v{version} or newer to work correctly"
+ "newer_required": "This feature requires Snapchat v{version} or newer to work correctly",
+ "search_button": "Search"
},
"manage_rule_feature": {
"disable_state_option": "Disabled",
diff --git a/common/src/main/kotlin/me/rhunk/snapenhance/common/ui/Components.kt b/common/src/main/kotlin/me/rhunk/snapenhance/common/ui/Components.kt
@@ -1,15 +1,22 @@
package me.rhunk.snapenhance.common.ui
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.heightIn
+import androidx.compose.material3.ElevatedButton
+import androidx.compose.material3.Icon
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import me.rhunk.snapenhance.common.bridge.wrapper.LocaleWrapper
@@ -44,4 +51,25 @@ fun EditNoteTextField(
textStyle = LocalTextStyle.current.copy(fontSize = 12.sp, color = primaryColor),
placeholder = { Text(text = translation["manager.sections.manage_scope.notes_placeholder"], fontSize = 12.sp) }
)
+}
+
+@Composable
+fun TopBarActionButton(
+ modifier: Modifier = Modifier,
+ icon: ImageVector,
+ text: String,
+ onClick: () -> Unit = {}
+) {
+ ElevatedButton(
+ modifier = modifier,
+ onClick = onClick
+ ) {
+ Row(
+ horizontalArrangement = Arrangement.spacedBy(3.dp),
+ verticalAlignment = Alignment.CenterVertically
+ ){
+ Icon(icon, contentDescription = null)
+ Text(text = text, overflow = TextOverflow.Ellipsis)
+ }
+ }
}
\ No newline at end of file
diff --git a/common/src/main/kotlin/me/rhunk/snapenhance/common/util/ktx/AndroidCompatExtensions.kt b/common/src/main/kotlin/me/rhunk/snapenhance/common/util/ktx/AndroidCompatExtensions.kt
@@ -2,10 +2,13 @@ package me.rhunk.snapenhance.common.util.ktx
import android.content.ClipData
import android.content.Context
+import android.content.Intent
import android.content.pm.PackageManager
import android.content.pm.PackageManager.ApplicationInfoFlags
import android.os.Build
import android.os.ParcelFileDescriptor
+import android.widget.Toast
+import androidx.core.net.toUri
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@@ -39,6 +42,18 @@ fun Context.getUrlFromClipboard(): String? {
return getTextFromClipboard()?.takeIf { it.startsWith("http") }
}
+fun Context.openLink(url: String, shouldThrow: Boolean = false) {
+ runCatching {
+ startActivity(Intent(Intent.ACTION_VIEW).apply {
+ data = url.toUri()
+ flags = Intent.FLAG_ACTIVITY_NEW_TASK
+ })
+ }.onFailure {
+ if (shouldThrow) throw it
+ Toast.makeText(this, "Failed to open link", Toast.LENGTH_SHORT).show()
+ }
+}
+
fun InputStream.toParcelFileDescriptor(coroutineScope: CoroutineScope): ParcelFileDescriptor {
val pfd = ParcelFileDescriptor.createPipe()
val fos = ParcelFileDescriptor.AutoCloseOutputStream(pfd[1])