feat: update navigation logic in MainApp and enhance ListDetailScreen interactions; externalize strings in SettingsScreen and strings.xml
This commit is contained in:
@@ -74,11 +74,16 @@ fun MainApp() {
|
||||
NavigationBarItem(
|
||||
selected = currentRoute == Routes.TABLES || currentRoute?.startsWith("list/") == true,
|
||||
onClick = {
|
||||
if (currentRoute?.startsWith("list/") == true) {
|
||||
// If we're in a list detail, pop back to the tables root instead of creating a new entry
|
||||
navController.popBackStack(Routes.TABLES, inclusive = false)
|
||||
} else if (currentRoute != Routes.TABLES) {
|
||||
navController.navigate(Routes.TABLES) {
|
||||
popUpTo(navController.graph.findStartDestination().id) { saveState = true }
|
||||
launchSingleTop = true
|
||||
restoreState = true
|
||||
}
|
||||
}
|
||||
},
|
||||
icon = { androidx.compose.material3.Icon(Icons.Default.Home, contentDescription = null) },
|
||||
label = { Text("Tables") },
|
||||
@@ -87,11 +92,16 @@ fun MainApp() {
|
||||
// Highlight settings tab for both Settings screen and Logs screen
|
||||
selected = currentRoute == Routes.SETTINGS || currentRoute == Routes.LOGS,
|
||||
onClick = {
|
||||
if (currentRoute == Routes.LOGS) {
|
||||
// Return to Settings without rebuilding entire graph
|
||||
navController.popBackStack(Routes.SETTINGS, inclusive = false)
|
||||
} else if (currentRoute != Routes.SETTINGS) {
|
||||
navController.navigate(Routes.SETTINGS) {
|
||||
popUpTo(navController.graph.findStartDestination().id) { saveState = true }
|
||||
launchSingleTop = true
|
||||
restoreState = true
|
||||
}
|
||||
}
|
||||
},
|
||||
icon = { androidx.compose.material3.Icon(Icons.Default.Settings, contentDescription = null) },
|
||||
label = { Text("Settings") },
|
||||
|
||||
+49
-50
@@ -202,7 +202,13 @@ fun ListDetailScreen(
|
||||
val localCtx = LocalContext.current
|
||||
val localPrefs = remember { PreferencesManager.getInstance(localCtx) }
|
||||
ConnectionStatusAction(prefs = localPrefs)
|
||||
IconButton(onClick = { showAddItemDialog = true }) {
|
||||
IconButton(onClick = {
|
||||
if (stableFields.isEmpty()) {
|
||||
showManageColumnsDialog = true
|
||||
} else {
|
||||
showAddItemDialog = true
|
||||
}
|
||||
}) {
|
||||
Icon(Icons.Default.Add, contentDescription = stringResource(R.string.add_item))
|
||||
}
|
||||
},
|
||||
@@ -253,7 +259,7 @@ fun ListDetailScreen(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Text(
|
||||
text = "No fields yet. Add fields to get started!",
|
||||
text = "No columns yet. Add columns to get started!",
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
@@ -463,7 +469,7 @@ fun ListDetailScreen(
|
||||
}
|
||||
prefs.setColumnWidths(listId, fieldWidths.mapValues { it.value.value })
|
||||
},
|
||||
label = { Text("Auto-fit") },
|
||||
label = { Text(stringResource(R.string.auto_fit)) },
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
Icons.Default.FitScreen,
|
||||
@@ -476,44 +482,10 @@ fun ListDetailScreen(
|
||||
|
||||
// Header will be rendered as a stickyHeader inside the LazyColumn below
|
||||
|
||||
// Items list with synchronized scrolling
|
||||
if (stableItems.isEmpty()) {
|
||||
Box(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.no_items),
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
}
|
||||
} else if (processedItems.isEmpty()) {
|
||||
Box(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
Text(
|
||||
text = "No items match the current filter",
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
TextButton(onClick = {
|
||||
filterField = null
|
||||
filterValue = ""
|
||||
}) {
|
||||
Text("Clear Filter")
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Unified layout: always render headers, then content state/messages
|
||||
val listState = rememberLazyListState()
|
||||
// If a new item was just added, scroll to bottom after composition
|
||||
LaunchedEffect(processedItems.size, pendingScrollToBottom) {
|
||||
if (pendingScrollToBottom) {
|
||||
// Scroll to the last real item index
|
||||
if (pendingScrollToBottom && processedItems.isNotEmpty()) {
|
||||
val lastIndex = (listState.layoutInfo.totalItemsCount - 1).coerceAtLeast(0)
|
||||
try {
|
||||
listState.animateScrollToItem(lastIndex)
|
||||
@@ -529,7 +501,7 @@ fun ListDetailScreen(
|
||||
.fillMaxSize()
|
||||
.horizontalScroll(horizontalScrollState),
|
||||
) {
|
||||
// Fixed header (does not participate in vertical scroll)
|
||||
// Fixed header (always visible even with zero items)
|
||||
Row(
|
||||
modifier =
|
||||
Modifier
|
||||
@@ -556,7 +528,6 @@ fun ListDetailScreen(
|
||||
onHeaderClick = { showManageColumnsDialog = true },
|
||||
alignment = columnAlignments[field.id] ?: "start",
|
||||
onAlignmentChange = { newAlign ->
|
||||
// Update local state and persist via ViewModel + cache to prefs for backward-compat
|
||||
columnAlignments[field.id] = newAlign
|
||||
viewModel.updateFieldAlignment(field.id, newAlign)
|
||||
prefs.setColumnAlignments(listId, columnAlignments.toMap())
|
||||
@@ -564,28 +535,55 @@ fun ListDetailScreen(
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Loading overlay only while nothing is available to render yet
|
||||
if (isLoading && stableFields.isEmpty() && stableItems.isEmpty()) {
|
||||
when {
|
||||
isLoading && stableItems.isEmpty() -> {
|
||||
Box(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentAlignment = Alignment.Center,
|
||||
) { androidx.compose.material3.CircularProgressIndicator() }
|
||||
}
|
||||
stableItems.isEmpty() -> {
|
||||
Box(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
androidx.compose.material3.CircularProgressIndicator()
|
||||
Text(
|
||||
text = stringResource(R.string.no_items),
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
}
|
||||
}
|
||||
processedItems.isEmpty() -> {
|
||||
Box(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
Text(
|
||||
text = "No items match the current filter",
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
TextButton(onClick = {
|
||||
filterField = null
|
||||
filterValue = ""
|
||||
}) { Text(stringResource(R.string.clear_filter)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Items list below the fixed header
|
||||
else -> {
|
||||
LazyColumn(
|
||||
modifier =
|
||||
Modifier
|
||||
.fillMaxSize(),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
state = listState,
|
||||
contentPadding = PaddingValues(0.dp),
|
||||
) {
|
||||
groupedItems.entries.forEach { (_, groupItems) ->
|
||||
// Show items in the group
|
||||
items(
|
||||
items = groupItems,
|
||||
key = { it.item.id },
|
||||
@@ -606,6 +604,7 @@ fun ListDetailScreen(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (showManageColumnsDialog) {
|
||||
ManageColumnsDialog(
|
||||
|
||||
+37
-40
@@ -153,7 +153,7 @@ fun SettingsScreen(
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp),
|
||||
) {
|
||||
Text(
|
||||
text = "Server Connection",
|
||||
text = stringResource(R.string.server_connection),
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
)
|
||||
|
||||
@@ -169,7 +169,7 @@ fun SettingsScreen(
|
||||
verticalArrangement = Arrangement.spacedBy(4.dp),
|
||||
) {
|
||||
Text(
|
||||
text = "Connected to",
|
||||
text = stringResource(R.string.connected_to),
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
@@ -186,7 +186,7 @@ fun SettingsScreen(
|
||||
// Authentication section removed
|
||||
|
||||
Text(
|
||||
text = "Appearance",
|
||||
text = stringResource(R.string.appearance),
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
)
|
||||
|
||||
@@ -198,19 +198,19 @@ fun SettingsScreen(
|
||||
FilterChip(
|
||||
selected = themeMode == PreferencesManager.THEME_MODE_SYSTEM,
|
||||
onClick = { preferencesManager.setThemeMode(PreferencesManager.THEME_MODE_SYSTEM) },
|
||||
label = { Text("System") },
|
||||
label = { Text(stringResource(R.string.theme_system)) },
|
||||
leadingIcon = { Icon(Icons.Filled.SettingsBrightness, contentDescription = null) },
|
||||
)
|
||||
FilterChip(
|
||||
selected = themeMode == PreferencesManager.THEME_MODE_LIGHT,
|
||||
onClick = { preferencesManager.setThemeMode(PreferencesManager.THEME_MODE_LIGHT) },
|
||||
label = { Text("Light") },
|
||||
label = { Text(stringResource(R.string.theme_light)) },
|
||||
leadingIcon = { Icon(Icons.Filled.Brightness7, contentDescription = null) },
|
||||
)
|
||||
FilterChip(
|
||||
selected = themeMode == PreferencesManager.THEME_MODE_DARK,
|
||||
onClick = { preferencesManager.setThemeMode(PreferencesManager.THEME_MODE_DARK) },
|
||||
label = { Text("Dark") },
|
||||
label = { Text(stringResource(R.string.theme_dark)) },
|
||||
leadingIcon = { Icon(Icons.Filled.Brightness4, contentDescription = null) },
|
||||
)
|
||||
}
|
||||
@@ -222,9 +222,9 @@ fun SettingsScreen(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
Text("Use Material 3 colors")
|
||||
Text(stringResource(R.string.use_material3_colors))
|
||||
Text(
|
||||
text = "Dynamic colors on supported devices",
|
||||
text = stringResource(R.string.dynamic_colors_desc),
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
@@ -239,9 +239,9 @@ fun SettingsScreen(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
Text("AMOLED dark")
|
||||
Text(stringResource(R.string.amoled_dark))
|
||||
Text(
|
||||
text = "Pure black background in dark mode",
|
||||
text = stringResource(R.string.amoled_dark_desc),
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
@@ -251,7 +251,7 @@ fun SettingsScreen(
|
||||
|
||||
// Sync settings
|
||||
Text(
|
||||
text = "Sync",
|
||||
text = stringResource(R.string.sync),
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
)
|
||||
|
||||
@@ -267,7 +267,7 @@ fun SettingsScreen(
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
Text(
|
||||
text = "HTTP polling interval (ms)",
|
||||
text = stringResource(R.string.http_polling_interval_ms),
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
@@ -296,7 +296,7 @@ fun SettingsScreen(
|
||||
syncIntervalError = null
|
||||
}
|
||||
}) {
|
||||
Text("Apply")
|
||||
Text(stringResource(R.string.apply))
|
||||
}
|
||||
}
|
||||
if (syncIntervalError != null) {
|
||||
@@ -307,7 +307,7 @@ fun SettingsScreen(
|
||||
)
|
||||
} else {
|
||||
Text(
|
||||
text = "Current: $syncIntervalMs ms (min 250, max 600000)",
|
||||
text = stringResource(R.string.current_interval, syncIntervalMs),
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
@@ -317,7 +317,7 @@ fun SettingsScreen(
|
||||
|
||||
// Notifications section (moved inside the main scroll column so it doesn't overlay other content)
|
||||
Text(
|
||||
text = "Notifications",
|
||||
text = stringResource(R.string.notifications),
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
)
|
||||
Card(
|
||||
@@ -334,9 +334,9 @@ fun SettingsScreen(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
Text("List added")
|
||||
Text(stringResource(R.string.notify_list_added_title))
|
||||
Text(
|
||||
text = "Notify when a new list/table is created",
|
||||
text = stringResource(R.string.notify_list_added_desc),
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
@@ -360,9 +360,9 @@ fun SettingsScreen(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
Text("List edited")
|
||||
Text(stringResource(R.string.notify_list_edited_title))
|
||||
Text(
|
||||
text = "Notify when a list/table name changes",
|
||||
text = stringResource(R.string.notify_list_edited_desc),
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
@@ -386,9 +386,9 @@ fun SettingsScreen(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
Text("List content updated")
|
||||
Text(stringResource(R.string.notify_list_content_title))
|
||||
Text(
|
||||
text = "Notify when fields or items change (add/edit/delete)",
|
||||
text = stringResource(R.string.notify_list_content_desc),
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
@@ -412,9 +412,9 @@ fun SettingsScreen(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
Text("List removed")
|
||||
Text(stringResource(R.string.notify_list_removed_title))
|
||||
Text(
|
||||
text = "Notify when a list/table is deleted",
|
||||
text = stringResource(R.string.notify_list_removed_desc),
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
@@ -433,7 +433,7 @@ fun SettingsScreen(
|
||||
)
|
||||
}
|
||||
Text(
|
||||
text = "Notifications fire only when the app is in background or not visible.",
|
||||
text = stringResource(R.string.notifications_footer),
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
@@ -461,14 +461,14 @@ fun SettingsScreen(
|
||||
Button(onClick = onNavigateToLogs, modifier = Modifier.fillMaxWidth()) {
|
||||
Icon(Icons.AutoMirrored.Filled.List, contentDescription = null)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Text("Open Logs")
|
||||
Text(stringResource(R.string.open_logs))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Leave Server section
|
||||
Text(
|
||||
text = "Leave Server",
|
||||
text = stringResource(R.string.leave_server_section),
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
)
|
||||
Card(
|
||||
@@ -481,27 +481,27 @@ fun SettingsScreen(
|
||||
) {
|
||||
// Warning/info text appears above the action button
|
||||
Text(
|
||||
text = "Leaving removes local data",
|
||||
text = stringResource(R.string.leaving_removes_local_data),
|
||||
style = MaterialTheme.typography.labelLarge,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
)
|
||||
Text(
|
||||
text = "Disconnects and clears local database",
|
||||
text = stringResource(R.string.disconnects_and_clears_db),
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
Text(
|
||||
text = "Clears stored server URL and password",
|
||||
text = stringResource(R.string.clears_server_settings),
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
Text(
|
||||
text = "Deletes all local data (tables, fields, items)",
|
||||
text = stringResource(R.string.deletes_all_local),
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
Text(
|
||||
text = "Returns to server setup screen",
|
||||
text = stringResource(R.string.returns_to_setup),
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
@@ -524,9 +524,9 @@ fun SettingsScreen(
|
||||
strokeWidth = 2.dp,
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Text("Leaving...")
|
||||
Text(stringResource(R.string.leaving_progress))
|
||||
} else {
|
||||
Text("Leave Server")
|
||||
Text(stringResource(R.string.leave_server))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -536,12 +536,9 @@ fun SettingsScreen(
|
||||
if (showLeaveDialog) {
|
||||
AlertDialog(
|
||||
onDismissRequest = { showLeaveDialog = false },
|
||||
title = { Text("Leave Server?") },
|
||||
title = { Text(stringResource(R.string.leave_server_dialog_title)) },
|
||||
text = {
|
||||
Text(
|
||||
"All your data will be synced to the server before disconnecting. " +
|
||||
"After leaving, all local data will be deleted and you'll need to set up a new connection. " +
|
||||
"This action cannot be undone.",
|
||||
Text(stringResource(R.string.leave_server_dialog_body),
|
||||
)
|
||||
},
|
||||
confirmButton = {
|
||||
@@ -589,12 +586,12 @@ fun SettingsScreen(
|
||||
contentColor = MaterialTheme.colorScheme.error,
|
||||
),
|
||||
) {
|
||||
Text("Leave Server")
|
||||
Text(stringResource(R.string.leave_server))
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = { showLeaveDialog = false }) {
|
||||
Text("Cancel")
|
||||
Text(stringResource(R.string.cancel))
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
<string name="lists">Tables</string>
|
||||
<string name="create_list">Create Table</string>
|
||||
<string name="list_name">Table Name</string>
|
||||
<string name="add_field">Add Field</string>
|
||||
<string name="field_name">Field Name</string>
|
||||
<string name="add_field">Add Column</string>
|
||||
<string name="field_name">Column Name</string>
|
||||
<string name="add_item">Add Item</string>
|
||||
<string name="add">Add</string>
|
||||
<string name="delete">Delete</string>
|
||||
@@ -20,7 +20,67 @@
|
||||
<string name="syncing">Syncing…</string>
|
||||
<string name="sync_error">Sync error</string>
|
||||
<string name="delete_list">Delete Table</string>
|
||||
<string name="delete_field">Delete Field</string>
|
||||
<string name="delete_field">Delete Column</string>
|
||||
<string name="delete_item">Delete Item</string>
|
||||
<string name="confirm_delete">Are you sure you want to delete this?</string>
|
||||
<!-- Newly externalized strings -->
|
||||
<string name="theme_system">System</string>
|
||||
<string name="theme_light">Light</string>
|
||||
<string name="theme_dark">Dark</string>
|
||||
<string name="appearance">Appearance</string>
|
||||
<string name="use_material3_colors">Use Material 3 colors</string>
|
||||
<string name="amoled_dark">AMOLED dark</string>
|
||||
<string name="dynamic_colors_desc">Dynamic colors on supported devices</string>
|
||||
<string name="amoled_dark_desc">Pure black background in dark mode</string>
|
||||
<string name="server_connection">Server Connection</string>
|
||||
<string name="connected_to">Connected to</string>
|
||||
<string name="http_polling_interval_ms">HTTP polling interval (ms)</string>
|
||||
<string name="apply">Apply</string>
|
||||
<string name="current_interval">Current: %1$d ms (min 250, max 600000)</string>
|
||||
<string name="notifications">Notifications</string>
|
||||
<string name="notify_list_added_title">List added</string>
|
||||
<string name="notify_list_added_desc">Notify when a new list/table is created</string>
|
||||
<string name="notify_list_edited_title">List edited</string>
|
||||
<string name="notify_list_edited_desc">Notify when a list/table name changes</string>
|
||||
<string name="notify_list_content_title">List content updated</string>
|
||||
<string name="notify_list_content_desc">Notify when columns or items change (add/edit/delete)</string>
|
||||
<string name="notify_list_removed_title">List removed</string>
|
||||
<string name="notify_list_removed_desc">Notify when a list/table is deleted</string>
|
||||
<string name="notifications_footer">Notifications fire only when the app is in background or not visible.</string>
|
||||
<string name="open_logs">Open Logs</string>
|
||||
<string name="leave_server_section">Leave Server</string>
|
||||
<string name="leaving_removes_local_data">Leaving removes local data</string>
|
||||
<string name="disconnects_and_clears_db">Disconnects and clears local database</string>
|
||||
<string name="clears_server_settings">Clears stored server URL and password</string>
|
||||
<string name="deletes_all_local">Deletes all local data (tables, columns, items)</string>
|
||||
<string name="returns_to_setup">Returns to server setup screen</string>
|
||||
<string name="leave_server">Leave Server</string>
|
||||
<string name="leaving_progress">Leaving...</string>
|
||||
<string name="leave_server_dialog_title">Leave Server?</string>
|
||||
<string name="leave_server_dialog_body">All your data will sync to the server before disconnecting. After leaving, all local data will be deleted and you must set up a new connection. This action cannot be undone.</string>
|
||||
<string name="clear_filter">Clear Filter</string>
|
||||
<string name="no_items_match_filter">No items match the current filter</string>
|
||||
<string name="auto_fit">Auto-fit</string>
|
||||
<string name="resize">Resize</string>
|
||||
<string name="field_type">Field Type</string>
|
||||
<!-- Field type labels -->
|
||||
<string name="ft_text">Text</string>
|
||||
<string name="ft_multiline_text">Multi-line Text</string>
|
||||
<string name="ft_number">Number</string>
|
||||
<string name="ft_currency">Currency</string>
|
||||
<string name="ft_percentage">Percentage</string>
|
||||
<string name="ft_dropdown">Dropdown</string>
|
||||
<string name="ft_autocomplete">Autocomplete</string>
|
||||
<string name="ft_checkbox">Checkbox</string>
|
||||
<string name="ft_switch">Switch</string>
|
||||
<string name="ft_url">URL</string>
|
||||
<string name="ft_email">Email</string>
|
||||
<string name="ft_phone">Phone</string>
|
||||
<string name="ft_date">Date</string>
|
||||
<string name="ft_time">Time</string>
|
||||
<string name="ft_datetime">Date & Time</string>
|
||||
<string name="ft_duration">Duration</string>
|
||||
<string name="ft_image">Image</string>
|
||||
<string name="ft_file">File</string>
|
||||
<!-- Additional existing types could be added similarly -->
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user