feat(app/ui): top bar action button text
Signed-off-by: rhunk <101876869+rhunk@users.noreply.github.com>
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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"]
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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}")
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
@@ -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",
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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",
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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])
|
||||
|
||||
Reference in New Issue
Block a user