Skip to content

Commit 7bea066

Browse files
committed
feat: Consolidate import/export settings into grouped rows
1 parent 0f51573 commit 7bea066

4 files changed

Lines changed: 119 additions & 71 deletions

File tree

app/src/main/java/app/morphe/manager/ui/screen/settings/SystemTabContent.kt

Lines changed: 101 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,16 @@ import androidx.compose.foundation.verticalScroll
1616
import androidx.compose.material.icons.Icons
1717
import androidx.compose.material.icons.outlined.*
1818
import androidx.compose.material3.ExperimentalMaterial3Api
19+
import androidx.compose.material3.Icon
1920
import androidx.compose.material3.MaterialTheme
21+
import androidx.compose.material3.Text
2022
import androidx.compose.runtime.*
2123
import androidx.compose.ui.Alignment
2224
import androidx.compose.ui.Modifier
2325
import androidx.compose.ui.platform.LocalContext
26+
import androidx.compose.ui.res.painterResource
2427
import androidx.compose.ui.res.stringResource
28+
import androidx.compose.ui.text.font.FontWeight
2529
import androidx.compose.ui.unit.dp
2630
import androidx.core.net.toUri
2731
import androidx.lifecycle.Lifecycle
@@ -242,72 +246,53 @@ fun SystemTabContent(
242246

243247
SectionCard {
244248
Column {
245-
// Keystore Import
246-
BaseSettingsItem(
247-
onClick = onImportKeystore,
249+
// Keystore
250+
ImportExportRow(
248251
leadingContent = { MorpheIcon(icon = Icons.Outlined.Key) },
249-
title = stringResource(R.string.settings_system_import_keystore),
250-
description = stringResource(R.string.settings_system_import_keystore_description)
251-
)
252-
253-
MorpheSettingsDivider()
254-
255-
// Keystore Export
256-
BaseSettingsItem(
257-
onClick = {
252+
title = stringResource(R.string.settings_system_keystore),
253+
description = stringResource(R.string.settings_system_import_keystore_description),
254+
onImport = onImportKeystore,
255+
onExport = {
258256
if (!importExportViewModel.canExport()) {
259257
context.toast(keystoreUnavailable)
260258
} else {
261259
onExportKeystore()
262260
}
263-
},
264-
leadingContent = { MorpheIcon(icon = Icons.Outlined.Upload) },
265-
title = stringResource(R.string.settings_system_export_keystore),
266-
description = stringResource(R.string.settings_system_export_keystore_description)
261+
}
267262
)
268-
}
269-
}
270263

271-
SectionCard {
272-
Column {
273-
// Manager Settings Import
274-
BaseSettingsItem(
275-
onClick = onImportSettings,
276-
leadingContent = { MorpheIcon(icon = Icons.Outlined.Download) },
277-
title = stringResource(R.string.settings_system_import_manager_settings),
278-
description = stringResource(R.string.settings_system_import_manager_settings_description)
264+
MorpheSettingsDivider()
265+
266+
// Manager Settings
267+
ImportExportRow(
268+
leadingContent = {
269+
Icon(
270+
painter = painterResource(R.drawable.ic_notification),
271+
contentDescription = null,
272+
tint = MaterialTheme.colorScheme.primary,
273+
modifier = Modifier.size(24.dp)
274+
)
275+
},
276+
title = stringResource(R.string.settings_system_morphe_settings),
277+
description = stringResource(R.string.settings_system_import_manager_settings_description),
278+
onImport = onImportSettings,
279+
onExport = onExportSettings
279280
)
280281

281282
MorpheSettingsDivider()
282283

283-
// Manager Settings Export
284-
BaseSettingsItem(
285-
onClick = onExportSettings,
286-
leadingContent = { MorpheIcon(icon = Icons.Outlined.Upload) },
287-
title = stringResource(R.string.settings_system_export_manager_settings),
288-
description = stringResource(R.string.settings_system_export_manager_settings_description)
284+
// Debug Logs
285+
ImportExportRow(
286+
leadingContent = { MorpheIcon(icon = Icons.Outlined.BugReport) },
287+
title = stringResource(R.string.settings_system_debug),
288+
description = stringResource(R.string.settings_system_export_debug_logs_description),
289+
onImport = null,
290+
onExport = onExportDebugLogs
289291
)
290292
}
291293
}
292294
}
293295

294-
// Debug Logs (Expert mode only)
295-
if (useExpertMode) {
296-
SectionTitle(
297-
text = stringResource(R.string.settings_system_debug),
298-
icon = Icons.Outlined.BugReport
299-
)
300-
301-
SectionCard {
302-
BaseSettingsItem(
303-
onClick = onExportDebugLogs,
304-
leadingContent = { MorpheIcon(icon = Icons.Outlined.Upload) },
305-
title = stringResource(R.string.settings_system_export_debug_logs),
306-
description = stringResource(R.string.settings_system_export_debug_logs_description)
307-
)
308-
}
309-
}
310-
311296
// Storage Management Section
312297
SectionTitle(
313298
text = stringResource(R.string.settings_system_storage_management),
@@ -414,6 +399,73 @@ fun SystemTabContent(
414399
}
415400
}
416401

402+
/**
403+
* A settings row with a title, optional description, and import/export action buttons.
404+
*/
405+
@Composable
406+
private fun ImportExportRow(
407+
leadingContent: @Composable () -> Unit,
408+
title: String,
409+
description: String? = null,
410+
onImport: (() -> Unit)?,
411+
onExport: (() -> Unit)?
412+
) {
413+
val hasBoth = onImport != null && onExport != null
414+
Column(
415+
modifier = Modifier
416+
.fillMaxWidth()
417+
.padding(horizontal = 16.dp, vertical = 12.dp),
418+
verticalArrangement = Arrangement.spacedBy(10.dp)
419+
) {
420+
Row(
421+
horizontalArrangement = Arrangement.spacedBy(12.dp),
422+
verticalAlignment = Alignment.CenterVertically
423+
) {
424+
leadingContent()
425+
Column(modifier = Modifier.weight(1f)) {
426+
Text(
427+
text = title,
428+
style = MaterialTheme.typography.bodyMedium,
429+
fontWeight = FontWeight.Medium,
430+
color = MaterialTheme.colorScheme.onSurface
431+
)
432+
if (description != null) {
433+
Text(
434+
text = description,
435+
style = MaterialTheme.typography.bodySmall,
436+
color = MaterialTheme.colorScheme.onSurfaceVariant
437+
)
438+
}
439+
}
440+
}
441+
Row(
442+
modifier = Modifier.fillMaxWidth(),
443+
horizontalArrangement = if (hasBoth) Arrangement.spacedBy(8.dp) else Arrangement.Center
444+
) {
445+
if (onImport != null) {
446+
ActionPillButton(
447+
onClick = onImport,
448+
icon = Icons.Outlined.Download,
449+
contentDescription = stringResource(R.string.import_),
450+
modifier = if (hasBoth) Modifier.weight(1f) else Modifier.fillMaxWidth(0.5f),
451+
large = true,
452+
label = stringResource(R.string.import_)
453+
)
454+
}
455+
if (onExport != null) {
456+
ActionPillButton(
457+
onClick = onExport,
458+
icon = Icons.Outlined.Upload,
459+
contentDescription = stringResource(R.string.export),
460+
modifier = if (hasBoth) Modifier.weight(1f) else Modifier.fillMaxWidth(0.5f),
461+
large = true,
462+
label = stringResource(R.string.export)
463+
)
464+
}
465+
}
466+
}
467+
}
468+
417469
/** Maps a [BytecodeMode] to its short display label string resource. */
418470
private fun BytecodeMode.labelRes(): Int = when (this) {
419471
BytecodeMode.FULL -> R.string.settings_advanced_bytecode_mode_full

app/src/main/java/app/morphe/manager/ui/screen/settings/system/KeystoreCredentialsDialog.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ fun KeystoreCredentialsDialog(
4646
title = stringResource(R.string.settings_system_import_keystore_dialog_title),
4747
footer = {
4848
MorpheDialogButtonRow(
49-
primaryText = stringResource(R.string.settings_system_import_keystore_dialog_button),
49+
primaryText = stringResource(R.string.import_),
5050
onPrimaryClick = { onSubmit(alias, pass, format) },
5151
secondaryText = stringResource(android.R.string.cancel),
5252
onSecondaryClick = onDismiss

app/src/main/java/app/morphe/manager/ui/screen/shared/ActionPillButton.kt

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,32 @@ import androidx.compose.ui.unit.dp
1212
/**
1313
* Pill-shaped action button with an icon, optional text label, and optional long-press tooltip.
1414
*/
15-
@OptIn(ExperimentalMaterial3Api::class)
1615
@Composable
1716
fun ActionPillButton(
1817
onClick: () -> Unit,
1918
icon: ImageVector,
2019
contentDescription: String,
20+
modifier: Modifier = Modifier,
2121
enabled: Boolean = true,
22+
large: Boolean = false,
2223
label: String? = null,
2324
tooltip: String? = null,
2425
colors: IconButtonColors = IconButtonDefaults.filledTonalIconButtonColors()
2526
) {
27+
val height = if (large) 40.dp else 36.dp
28+
val minWidth = if (large) 80.dp else 72.dp
29+
val iconSize = if (large) 20.dp else 18.dp
30+
val textStyle = if (large) MaterialTheme.typography.labelMedium else MaterialTheme.typography.labelSmall
31+
2632
val button: @Composable () -> Unit = {
2733
FilledTonalIconButton(
2834
onClick = onClick,
2935
enabled = enabled,
3036
colors = colors,
3137
shape = RoundedCornerShape(50),
32-
modifier = Modifier
33-
.height(36.dp)
34-
.widthIn(min = 72.dp)
38+
modifier = modifier
39+
.height(height)
40+
.widthIn(min = minWidth)
3541
) {
3642
if (label != null) {
3743
Row(
@@ -42,11 +48,11 @@ fun ActionPillButton(
4248
Icon(
4349
imageVector = icon,
4450
contentDescription = contentDescription,
45-
modifier = Modifier.size(18.dp)
51+
modifier = Modifier.size(iconSize)
4652
)
4753
Text(
4854
text = label,
49-
style = MaterialTheme.typography.labelSmall
55+
style = textStyle
5056
)
5157
}
5258
} else {

app/src/main/res/values/strings.xml

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -633,40 +633,30 @@ The image dimensions must be as follows:
633633
<string name="settings_system_process_runtime_disabled_description">Click to configure</string>
634634
<string name="settings_system_process_runtime_description_not_available">This feature requires Android 11 or greater</string>
635635

636-
<!-- Settings - System Tab - Import and export keystore -->
636+
<!-- Settings - System Tab - Import and Export Section -->
637637
<string name="settings_system_import_export">Import &amp; export</string>
638-
<string name="settings_system_import_keystore">Import keystore</string>
639-
<string name="settings_system_import_keystore_description">Import a custom keystore</string>
638+
<string name="settings_system_keystore">Keystore</string>
639+
<string name="settings_system_import_keystore_description">Import or export your signing keystore</string>
640640
<string name="settings_system_import_keystore_dialog_title">Enter keystore credentials</string>
641641
<string name="settings_system_import_keystore_dialog_description">You\'ll need enter the keystore\'s credentials to import it</string>
642642
<string name="settings_system_import_keystore_dialog_alias_field">Username (Alias)</string>
643643
<string name="settings_system_import_keystore_dialog_password_field">Password</string>
644-
<string name="settings_system_import_keystore_dialog_button">Import</string>
645644
<string name="settings_system_import_keystore_dialog_format_field">Keystore format</string>
646645
<string name="settings_system_import_keystore_wrong_credentials">Incorrect keystore credentials</string>
647646
<string name="settings_system_import_keystore_success">Keystore imported</string>
648647
<string name="settings_system_import_keystore_failed">Failed to import keystore</string>
649-
<string name="settings_system_export_keystore">Export keystore</string>
650-
<string name="settings_system_export_keystore_description">Export the current keystore</string>
651648
<string name="settings_system_export_keystore_unavailable">No keystore available to export</string>
652649
<string name="settings_system_export_keystore_success">Keystore exported</string>
653650
<string name="settings_system_export_keystore_failed">Failed to export keystore</string>
654651
<string name="settings_system_show_password_field">Show password</string>
655652
<string name="settings_system_hide_password_field">Hide password</string>
656-
657-
<!-- Settings - System Tab - Import and Export Manager Settings -->
658-
<string name="settings_system_import_manager_settings">Import Morphe settings</string>
659-
<string name="settings_system_import_manager_settings_description">Restore Morphe settings from a JSON file</string>
653+
<string name="settings_system_morphe_settings">Morphe settings</string>
654+
<string name="settings_system_import_manager_settings_description">Backup and restore your Morphe settings</string>
660655
<string name="settings_system_import_manager_settings_fail">Failed to import Morphe settings: %s</string>
661656
<string name="settings_system_import_manager_settings_success">Morphe settings imported</string>
662-
<string name="settings_system_export_manager_settings">Export Morphe settings</string>
663-
<string name="settings_system_export_manager_settings_description">Save Morphe settings to a JSON file</string>
664657
<string name="settings_system_export_manager_settings_fail">Failed to export Morphe settings: %s</string>
665658
<string name="settings_system_export_manager_settings_success">Morphe settings exported</string>
666-
667-
<!-- Settings - System Tab - Debug Section -->
668659
<string name="settings_system_debug">Debug</string>
669-
<string name="settings_system_export_debug_logs">Export debug logs</string>
670660
<string name="settings_system_export_debug_logs_description">Save system logs for troubleshooting</string>
671661
<string name="settings_system_export_debug_logs_export_read_failed">Failed to read logs (exit code %s)</string>
672662
<string name="settings_system_export_debug_logs_export_failed">Failed to export logs</string>

0 commit comments

Comments
 (0)