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:
Mapp/src/main/kotlin/me/rhunk/snapenhance/ui/manager/pages/TasksRootSection.kt | 21++++++++++++---------
Mapp/src/main/kotlin/me/rhunk/snapenhance/ui/manager/pages/features/FeaturesRootSection.kt | 29++++++++++++++++++++---------
Mapp/src/main/kotlin/me/rhunk/snapenhance/ui/manager/pages/home/HomeRootSection.kt | 81+++++++++++++++++++++++++++++++++++++++----------------------------------------
Mapp/src/main/kotlin/me/rhunk/snapenhance/ui/manager/pages/scripting/ScriptingRootSection.kt | 32+++++++++++++-------------------
Mcommon/src/main/assets/lang/en_US.json | 4+++-
Mcommon/src/main/kotlin/me/rhunk/snapenhance/common/ui/Components.kt | 28++++++++++++++++++++++++++++
Mcommon/src/main/kotlin/me/rhunk/snapenhance/common/util/ktx/AndroidCompatExtensions.kt | 15+++++++++++++++
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])