Button to trigger nuke reset in dev mode

This commit is contained in:
stopflock
2026-03-14 18:04:57 -05:00
parent 9f72ec9a76
commit ddf7f543ff
2 changed files with 235 additions and 11 deletions

11
COMMENT
View File

@@ -1,11 +0,0 @@
---
An alternative approach to addressing this issue could be adjusting the `optionsBuilder` logic to avoid returning any suggestions when the input text field is empty, rather than guarding `onFieldSubmitted`. For instance:
```dart
optionsBuilder: (TextEditingValue textEditingValue) {
if (textEditingValue.text.isEmpty) return <String>[];
return suggestions.where((s) => s.contains(textEditingValue.text));
}
```
This ensures that the `RawAutocomplete` widget doesn't offer any options to auto-select on submission when the field is cleared, potentially simplifying the implementation and avoiding the need for additional boolean flags (`guardOnSubmitted`). This pattern can be seen in some implementations "in the wild."

View File

@@ -1,6 +1,8 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
import '../services/localization_service.dart';
import '../services/nuclear_reset_service.dart';
import '../widgets/welcome_dialog.dart';
import '../widgets/submission_guide_dialog.dart';
@@ -83,6 +85,13 @@ class AboutScreen extends StatelessWidget {
_buildDialogButtons(context),
const SizedBox(height: 24),
_buildHelpLinks(context),
// Dev-only nuclear reset button at very bottom
if (kDebugMode) ...[
const SizedBox(height: 32),
_buildDevNuclearResetButton(context),
const SizedBox(height: 16),
],
],
),
),
@@ -203,5 +212,231 @@ class AboutScreen extends StatelessWidget {
);
}
/// Dev-only nuclear reset button (only visible in debug mode)
Widget _buildDevNuclearResetButton(BuildContext context) {
return Card(
color: Theme.of(context).colorScheme.errorContainer.withOpacity(0.1),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(
Icons.developer_mode,
color: Theme.of(context).colorScheme.primary,
size: 20,
),
const SizedBox(width: 8),
Text(
'Developer Tools',
style: Theme.of(context).textTheme.titleSmall?.copyWith(
color: Theme.of(context).colorScheme.primary,
fontWeight: FontWeight.bold,
),
),
],
),
const SizedBox(height: 12),
Text(
'These tools are only available in debug mode for development and troubleshooting.',
style: Theme.of(context).textTheme.bodySmall?.copyWith(
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.7),
),
),
const SizedBox(height: 16),
SizedBox(
width: double.infinity,
child: OutlinedButton.icon(
onPressed: () => _showNuclearResetConfirmation(context),
icon: const Icon(Icons.delete_forever, color: Colors.red),
label: const Text(
'Nuclear Reset (Clear All Data)',
style: TextStyle(color: Colors.red),
),
style: OutlinedButton.styleFrom(
side: const BorderSide(color: Colors.red),
),
),
),
],
),
),
);
}
/// Show confirmation dialog for nuclear reset
Future<void> _showNuclearResetConfirmation(BuildContext context) async {
final confirmed = await showDialog<bool>(
context: context,
barrierDismissible: false,
builder: (context) => AlertDialog(
title: const Row(
children: [
Icon(Icons.warning, color: Colors.red),
SizedBox(width: 8),
Text('Nuclear Reset'),
],
),
content: const Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'This will completely clear ALL app data:',
style: TextStyle(fontWeight: FontWeight.w500),
),
SizedBox(height: 12),
Text('• All settings and preferences'),
Text('• OAuth login credentials'),
Text('• Custom profiles and operators'),
Text('• Upload queue and cached data'),
Text('• Downloaded offline areas'),
Text('• Everything else'),
SizedBox(height: 16),
Text(
'The app will behave exactly like a fresh install after this operation.',
style: TextStyle(
fontWeight: FontWeight.w500,
color: Colors.red,
),
),
SizedBox(height: 12),
Text(
'This action cannot be undone.',
style: TextStyle(fontWeight: FontWeight.bold),
),
],
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(false),
child: const Text('Cancel'),
),
TextButton(
onPressed: () => Navigator.of(context).pop(true),
style: TextButton.styleFrom(foregroundColor: Colors.red),
child: const Text('Nuclear Reset'),
),
],
),
);
if (confirmed == true && context.mounted) {
await _performNuclearReset(context);
}
}
/// Perform the nuclear reset operation
Future<void> _performNuclearReset(BuildContext context) async {
// Show progress dialog
if (!context.mounted) return;
showDialog(
context: context,
barrierDismissible: false,
builder: (context) => const AlertDialog(
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
CircularProgressIndicator(),
SizedBox(height: 16),
Text('Clearing all app data...'),
],
),
),
);
try {
// Perform the nuclear reset
await NuclearResetService.clearEverything();
if (!context.mounted) return;
// Close progress dialog
Navigator.of(context).pop();
// Show completion dialog
await showDialog(
context: context,
barrierDismissible: false,
builder: (context) => AlertDialog(
title: const Row(
children: [
Icon(Icons.check_circle, color: Colors.green),
SizedBox(width: 8),
Text('Reset Complete'),
],
),
content: const Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'All app data has been cleared successfully.',
style: TextStyle(fontWeight: FontWeight.w500),
),
SizedBox(height: 12),
Text(
'Please close and restart the app to continue with a fresh state.',
style: TextStyle(fontWeight: FontWeight.w500),
),
],
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text('OK'),
),
],
),
);
} catch (e) {
if (!context.mounted) return;
// Close progress dialog if it's still open
Navigator.of(context).pop();
// Show error dialog
await showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Row(
children: [
Icon(Icons.error, color: Colors.red),
SizedBox(width: 8),
Text('Reset Failed'),
],
),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'An error occurred during the nuclear reset:',
style: TextStyle(fontWeight: FontWeight.w500),
),
const SizedBox(height: 12),
Text(
e.toString(),
style: const TextStyle(fontFamily: 'monospace'),
),
const SizedBox(height: 12),
const Text(
'Some data may have been partially cleared. You may want to manually clear app data through device settings.',
),
],
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text('OK'),
),
],
),
);
}
}
}