From e60cdf9355c38cfb41d179c432d7c999a35f08ad Mon Sep 17 00:00:00 2001 From: Matt Hills Date: Sat, 27 Dec 2025 19:14:24 -0500 Subject: [PATCH] Add configurable upload parameter defaults with optional prompt Users can now set default upload parameters (max downloads and expiry hours) in settings and choose whether to show the upload parameters dialog or use saved defaults directly. Changes: - Add upload preferences: default max downloads, default expiry hours, and ask before upload toggle - Update SettingsScreen with new upload defaults section - Modify UploadParamsDialog to initialize with saved defaults instead of hardcoded values - Update DumpstateTab and GeneralUploadTab to check askBeforeUpload preference and bypass dialog when disabled --- .../ui/components/UploadParamsDialog.kt | 11 +- .../ui/screens/SettingsScreen.kt | 115 ++++++++++++++++++ .../ui/screens/tabs/DumpstateTab.kt | 11 +- .../ui/screens/tabs/GeneralUploadTab.kt | 13 +- .../simplelogupload/util/PreferencesUtil.java | 77 +++++++++++- 5 files changed, 219 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/mattintech/simplelogupload/ui/components/UploadParamsDialog.kt b/app/src/main/java/com/mattintech/simplelogupload/ui/components/UploadParamsDialog.kt index 4d92b56..cde05f3 100644 --- a/app/src/main/java/com/mattintech/simplelogupload/ui/components/UploadParamsDialog.kt +++ b/app/src/main/java/com/mattintech/simplelogupload/ui/components/UploadParamsDialog.kt @@ -5,8 +5,10 @@ import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.unit.dp +import com.mattintech.simplelogupload.util.PreferencesUtil /** * Dialog for entering upload parameters @@ -19,8 +21,13 @@ fun UploadParamsDialog( onDismiss: () -> Unit, onConfirm: (Int, Int) -> Unit ) { - var maxDownloads by remember { mutableStateOf("5") } - var expiryHours by remember { mutableStateOf("24") } + val context = LocalContext.current + var maxDownloads by remember { + mutableStateOf(PreferencesUtil.getDefaultMaxDownloads(context).toString()) + } + var expiryHours by remember { + mutableStateOf(PreferencesUtil.getDefaultExpiryHours(context).toString()) + } var maxDownloadsError by remember { mutableStateOf(null) } var expiryHoursError by remember { mutableStateOf(null) } diff --git a/app/src/main/java/com/mattintech/simplelogupload/ui/screens/SettingsScreen.kt b/app/src/main/java/com/mattintech/simplelogupload/ui/screens/SettingsScreen.kt index 17c6bc0..0a29f96 100644 --- a/app/src/main/java/com/mattintech/simplelogupload/ui/screens/SettingsScreen.kt +++ b/app/src/main/java/com/mattintech/simplelogupload/ui/screens/SettingsScreen.kt @@ -45,10 +45,21 @@ fun SettingsScreen( var clientKey by remember { mutableStateOf(PreferencesUtil.getClientKey(context)) } + var defaultMaxDownloads by remember { + mutableStateOf(PreferencesUtil.getDefaultMaxDownloads(context).toString()) + } + var defaultExpiryHours by remember { + mutableStateOf(PreferencesUtil.getDefaultExpiryHours(context).toString()) + } + var askBeforeUpload by remember { + mutableStateOf(PreferencesUtil.getAskBeforeUpload(context)) + } var serverAddressError by remember { mutableStateOf(null) } var serverPortError by remember { mutableStateOf(null) } var clientKeyError by remember { mutableStateOf(null) } + var maxDownloadsError by remember { mutableStateOf(null) } + var expiryHoursError by remember { mutableStateOf(null) } // QR scanner launcher val qrScannerLauncher = rememberLauncherForActivityResult( @@ -108,6 +119,8 @@ fun SettingsScreen( serverAddressError = null serverPortError = null clientKeyError = null + maxDownloadsError = null + expiryHoursError = null var hasError = false @@ -135,12 +148,29 @@ fun SettingsScreen( hasError = true } + // Validate max downloads + val maxDl = defaultMaxDownloads.toIntOrNull() + if (maxDl == null || maxDl < 0) { + maxDownloadsError = "Must be 0 or greater (0 = unlimited)" + hasError = true + } + + // Validate expiry hours + val expiry = defaultExpiryHours.toIntOrNull() + if (expiry == null || expiry <= 0 || expiry > 24) { + expiryHoursError = "Must be between 1 and 24 hours" + hasError = true + } + if (hasError) return // Save settings PreferencesUtil.setServerAddress(context, serverAddress) PreferencesUtil.setServerPort(context, serverPort.toInt()) PreferencesUtil.setClientKey(context, clientKey) + PreferencesUtil.setDefaultMaxDownloads(context, maxDl!!) + PreferencesUtil.setDefaultExpiryHours(context, expiry!!) + PreferencesUtil.setAskBeforeUpload(context, askBeforeUpload) Toast.makeText(context, "Settings saved successfully!", Toast.LENGTH_SHORT).show() onNavigateBack() @@ -151,11 +181,16 @@ fun SettingsScreen( serverAddress = PreferencesUtil.getServerAddress(context) serverPort = PreferencesUtil.getServerPort(context).toString() clientKey = PreferencesUtil.getClientKey(context) + defaultMaxDownloads = PreferencesUtil.getDefaultMaxDownloads(context).toString() + defaultExpiryHours = PreferencesUtil.getDefaultExpiryHours(context).toString() + askBeforeUpload = PreferencesUtil.getAskBeforeUpload(context) // Clear errors serverAddressError = null serverPortError = null clientKeyError = null + maxDownloadsError = null + expiryHoursError = null Toast.makeText(context, "Settings reset", Toast.LENGTH_SHORT).show() } @@ -234,8 +269,88 @@ fun SettingsScreen( singleLine = true ) + Spacer(modifier = Modifier.height(24.dp)) + + // Upload Defaults Section + Text( + text = "Upload Defaults", + style = MaterialTheme.typography.titleLarge, + color = MaterialTheme.colorScheme.primary + ) + Spacer(modifier = Modifier.height(8.dp)) + // Default Max Downloads + OutlinedTextField( + value = defaultMaxDownloads, + onValueChange = { + defaultMaxDownloads = it + maxDownloadsError = null + }, + label = { Text("Default Maximum Downloads") }, + placeholder = { Text("5") }, + modifier = Modifier.fillMaxWidth(), + isError = maxDownloadsError != null, + supportingText = { + Text(maxDownloadsError ?: "Set to 0 for unlimited downloads") + }, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), + singleLine = true + ) + + // Default Expiry Hours + OutlinedTextField( + value = defaultExpiryHours, + onValueChange = { + defaultExpiryHours = it + expiryHoursError = null + }, + label = { Text("Default Expiry Time (hours)") }, + placeholder = { Text("24") }, + modifier = Modifier.fillMaxWidth(), + isError = expiryHoursError != null, + supportingText = { + Text(expiryHoursError ?: "Maximum 24 hours (1 day)") + }, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), + singleLine = true + ) + + // Ask Before Upload Switch + Card( + modifier = Modifier.fillMaxWidth(), + colors = CardDefaults.cardColors( + containerColor = MaterialTheme.colorScheme.surfaceVariant + ) + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(16.dp), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = androidx.compose.ui.Alignment.CenterVertically + ) { + Column(modifier = Modifier.weight(1f)) { + Text( + text = "Ask Before Upload", + style = MaterialTheme.typography.titleMedium + ) + Spacer(modifier = Modifier.height(4.dp)) + Text( + text = if (askBeforeUpload) "Show upload parameters dialog" else "Use default settings", + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + Switch( + checked = askBeforeUpload, + onCheckedChange = { askBeforeUpload = it } + ) + } + } + + Spacer(modifier = Modifier.height(24.dp)) + // QR Scan Button OutlinedButton( onClick = { diff --git a/app/src/main/java/com/mattintech/simplelogupload/ui/screens/tabs/DumpstateTab.kt b/app/src/main/java/com/mattintech/simplelogupload/ui/screens/tabs/DumpstateTab.kt index d0c8951..97b5478 100644 --- a/app/src/main/java/com/mattintech/simplelogupload/ui/screens/tabs/DumpstateTab.kt +++ b/app/src/main/java/com/mattintech/simplelogupload/ui/screens/tabs/DumpstateTab.kt @@ -13,6 +13,7 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import com.mattintech.simplelogupload.ui.components.UploadParamsDialog import com.mattintech.simplelogupload.ui.components.UploadResultDialog +import com.mattintech.simplelogupload.util.PreferencesUtil import com.mattintech.simplelogupload.viewmodel.MainViewModel import java.text.SimpleDateFormat import java.util.* @@ -138,7 +139,15 @@ fun DumpstateTab( // Upload button Button( - onClick = { viewModel.showUploadParamsDialog() }, + onClick = { + if (PreferencesUtil.getAskBeforeUpload(context)) { + viewModel.showUploadParamsDialog() + } else { + val maxDownloads = PreferencesUtil.getDefaultMaxDownloads(context) + val expiryHours = PreferencesUtil.getDefaultExpiryHours(context) + viewModel.uploadSelectedDumpstates(maxDownloads, expiryHours) + } + }, modifier = Modifier.fillMaxWidth(), enabled = !uiState.isLoading && uiState.selectedDumpstateIndices.isNotEmpty() ) { diff --git a/app/src/main/java/com/mattintech/simplelogupload/ui/screens/tabs/GeneralUploadTab.kt b/app/src/main/java/com/mattintech/simplelogupload/ui/screens/tabs/GeneralUploadTab.kt index 7f55b5a..49d05cf 100644 --- a/app/src/main/java/com/mattintech/simplelogupload/ui/screens/tabs/GeneralUploadTab.kt +++ b/app/src/main/java/com/mattintech/simplelogupload/ui/screens/tabs/GeneralUploadTab.kt @@ -21,6 +21,7 @@ import androidx.compose.ui.unit.dp import com.mattintech.simplelogupload.ui.components.UploadParamsDialog import com.mattintech.simplelogupload.ui.components.UploadResultDialog import com.mattintech.simplelogupload.util.PermissionUtil +import com.mattintech.simplelogupload.util.PreferencesUtil import com.mattintech.simplelogupload.viewmodel.MainViewModel /** @@ -166,7 +167,17 @@ fun GeneralUploadTab( Spacer(modifier = Modifier.height(16.dp)) Button( - onClick = { viewModel.showUploadParamsDialog() }, + onClick = { + if (PreferencesUtil.getAskBeforeUpload(context)) { + viewModel.showUploadParamsDialog() + } else { + val maxDownloads = PreferencesUtil.getDefaultMaxDownloads(context) + val expiryHours = PreferencesUtil.getDefaultExpiryHours(context) + uiState.selectedFile?.let { file -> + viewModel.uploadFile(file, maxDownloads, expiryHours) + } + } + }, modifier = Modifier.fillMaxWidth(), enabled = !uiState.isLoading ) { diff --git a/app/src/main/java/com/mattintech/simplelogupload/util/PreferencesUtil.java b/app/src/main/java/com/mattintech/simplelogupload/util/PreferencesUtil.java index bacb4ce..6484f98 100644 --- a/app/src/main/java/com/mattintech/simplelogupload/util/PreferencesUtil.java +++ b/app/src/main/java/com/mattintech/simplelogupload/util/PreferencesUtil.java @@ -14,12 +14,18 @@ public class PreferencesUtil { public static final String KEY_SERVER_PORT = "server_port"; public static final String KEY_CLIENT_KEY = "client_key"; public static final String KEY_SETUP_COMPLETED = "setup_completed"; - + public static final String KEY_DEFAULT_MAX_DOWNLOADS = "default_max_downloads"; + public static final String KEY_DEFAULT_EXPIRY_HOURS = "default_expiry_hours"; + public static final String KEY_ASK_BEFORE_UPLOAD = "ask_before_upload"; + // Default values private static final String DEFAULT_SERVER_ADDRESS = ""; private static final int DEFAULT_SERVER_PORT = 0; private static final String DEFAULT_CLIENT_KEY = ""; private static final boolean DEFAULT_SETUP_COMPLETED = false; + private static final int DEFAULT_MAX_DOWNLOADS = 5; + private static final int DEFAULT_EXPIRY_HOURS = 24; + private static final boolean DEFAULT_ASK_BEFORE_UPLOAD = true; /** * Get the shared preferences instance @@ -117,7 +123,7 @@ public class PreferencesUtil { /** * Reset all settings to default values - * + * * @param context The application context */ public static void resetToDefaults(Context context) { @@ -126,6 +132,9 @@ public class PreferencesUtil { editor.putInt(KEY_SERVER_PORT, DEFAULT_SERVER_PORT); editor.putString(KEY_CLIENT_KEY, DEFAULT_CLIENT_KEY); editor.putBoolean(KEY_SETUP_COMPLETED, DEFAULT_SETUP_COMPLETED); + editor.putInt(KEY_DEFAULT_MAX_DOWNLOADS, DEFAULT_MAX_DOWNLOADS); + editor.putInt(KEY_DEFAULT_EXPIRY_HOURS, DEFAULT_EXPIRY_HOURS); + editor.putBoolean(KEY_ASK_BEFORE_UPLOAD, DEFAULT_ASK_BEFORE_UPLOAD); editor.apply(); } @@ -149,9 +158,69 @@ public class PreferencesUtil { getPreferences(context).edit().putBoolean(KEY_SETUP_COMPLETED, completed).apply(); } + /** + * Get the default max downloads from preferences + * + * @param context The application context + * @return The default max downloads + */ + public static int getDefaultMaxDownloads(Context context) { + return getPreferences(context).getInt(KEY_DEFAULT_MAX_DOWNLOADS, DEFAULT_MAX_DOWNLOADS); + } + + /** + * Set the default max downloads in preferences + * + * @param context The application context + * @param maxDownloads The default max downloads to save + */ + public static void setDefaultMaxDownloads(Context context, int maxDownloads) { + getPreferences(context).edit().putInt(KEY_DEFAULT_MAX_DOWNLOADS, maxDownloads).apply(); + } + + /** + * Get the default expiry hours from preferences + * + * @param context The application context + * @return The default expiry hours + */ + public static int getDefaultExpiryHours(Context context) { + return getPreferences(context).getInt(KEY_DEFAULT_EXPIRY_HOURS, DEFAULT_EXPIRY_HOURS); + } + + /** + * Set the default expiry hours in preferences + * + * @param context The application context + * @param expiryHours The default expiry hours to save + */ + public static void setDefaultExpiryHours(Context context, int expiryHours) { + getPreferences(context).edit().putInt(KEY_DEFAULT_EXPIRY_HOURS, expiryHours).apply(); + } + + /** + * Get the ask before upload preference + * + * @param context The application context + * @return True if should ask before upload, false otherwise + */ + public static boolean getAskBeforeUpload(Context context) { + return getPreferences(context).getBoolean(KEY_ASK_BEFORE_UPLOAD, DEFAULT_ASK_BEFORE_UPLOAD); + } + + /** + * Set the ask before upload preference + * + * @param context The application context + * @param askBeforeUpload True if should ask before upload, false otherwise + */ + public static void setAskBeforeUpload(Context context, boolean askBeforeUpload) { + getPreferences(context).edit().putBoolean(KEY_ASK_BEFORE_UPLOAD, askBeforeUpload).apply(); + } + /** * Check if all required server settings are configured - * + * * @param context The application context * @return True if all required settings are configured, false otherwise */ @@ -160,7 +229,7 @@ public class PreferencesUtil { String address = prefs.getString(KEY_SERVER_ADDRESS, DEFAULT_SERVER_ADDRESS); int port = prefs.getInt(KEY_SERVER_PORT, DEFAULT_SERVER_PORT); String clientKey = prefs.getString(KEY_CLIENT_KEY, DEFAULT_CLIENT_KEY); - + return !address.isEmpty() && port > 0 && !clientKey.isEmpty(); } }