Rework saving to config

This commit is contained in:
2025-03-18 23:01:10 +01:00
parent 71ad392fb6
commit 1c6af27c7e
3 changed files with 88 additions and 68 deletions

View File

@@ -1325,47 +1325,7 @@ class _ModManagerPageState extends State<ModManagerPage> {
'Saving mod load order for ${_activeMods.length} active mods to $configPath',
);
// Save the mod list to the XML config file
final file = File(configPath);
final buffer = StringBuffer();
buffer.writeln('<?xml version="1.0" encoding="utf-8"?>');
buffer.writeln('<ModsConfigData>');
buffer.writeln(' <version>1</version>');
// Write active mods
buffer.writeln(' <activeMods>');
for (final mod in _activeMods) {
buffer.writeln(' <li>${mod.id}</li>');
logger.info(' - Adding mod to config: ${mod.name} (${mod.id})');
}
buffer.writeln(' </activeMods>');
// Count expansions
final expansions = _availableMods.where((m) => m.isExpansion).toList();
logger.info('Found ${expansions.length} expansions to include in config');
// Add known expansions
buffer.writeln(' <knownExpansions>');
for (final mod in expansions) {
buffer.writeln(' <li>${mod.id}</li>');
logger.info(' - Adding expansion to config: ${mod.name} (${mod.id})');
}
buffer.writeln(' </knownExpansions>');
buffer.writeln('</ModsConfigData>');
// Ensure directory exists
final directory = Directory(configRoot);
if (!directory.existsSync()) {
logger.info('Creating config directory: $configRoot');
directory.createSync(recursive: true);
}
// Write to file
logger.info('Writing config file to $configPath');
await file.writeAsString(buffer.toString());
logger.info('Successfully saved mod configuration');
modManager.saveToConfig(LoadOrder(_activeMods));
setState(() {
_isLoading = false;

View File

@@ -13,7 +13,9 @@ class LoadOrder {
return order.map((mod) => mod.id).toList();
}
LoadOrder();
LoadOrder([List<Mod>? order]) {
this.order = order ?? [];
}
bool get hasErrors => errors.isNotEmpty;
}
@@ -204,6 +206,66 @@ class ModList {
}
}
void saveToConfig(LoadOrder loadOrder) {
final file = File(configPath);
final logger = Logger.instance;
try {
// Create XML builder
final builder = XmlBuilder();
// Add XML declaration
builder.declaration(encoding: 'utf-8');
// Add root element
builder.element(
'ModsConfigData',
nest: () {
// Add version element
builder.element('version', nest: '1.5.4297 rev994');
// Add active mods element
builder.element(
'activeMods',
nest: () {
// Add each mod as a list item
for (final mod in loadOrder.order) {
builder.element('li', nest: mod.id);
logger.info('Adding mod to config: ${mod.name} (${mod.id})');
}
},
);
// Add known expansions element
final expansions = mods.values.where((m) => m.isExpansion).toList();
if (expansions.isNotEmpty) {
builder.element(
'knownExpansions',
nest: () {
for (final mod in expansions) {
builder.element('li', nest: mod.id);
logger.info(
'Adding expansion to config: ${mod.name} (${mod.id})',
);
}
},
);
}
},
);
// Build the XML document
final xmlDocument = builder.buildDocument();
// Write the XML document to file
file.writeAsStringSync(xmlDocument.toString());
logger.info('Successfully saved mod configuration to: $configPath');
} catch (e) {
logger.error('Error saving configuration file: $e');
throw Exception('Failed to save config file: $e');
}
}
void setEnabled(String modId, bool enabled) {
if (mods.containsKey(modId)) {
final mod = mods[modId]!;

View File

@@ -34,7 +34,7 @@ class _ModTroubleshooterWidgetState extends State<ModTroubleshooterWidget> {
final Set<String> _problemMods = {};
// The currently selected mod IDs (for highlighting)
List<String> _selectedMods = [];
LoadOrder _loadOrder = LoadOrder();
// The next potential set of mods (from move calculation)
Move? _nextForwardMove;
@@ -64,7 +64,7 @@ class _ModTroubleshooterWidgetState extends State<ModTroubleshooterWidget> {
// Set initial active mods for highlighting
if (modManager.activeMods.isNotEmpty) {
// Initially select all active mods
_selectedMods = List.from(modManager.activeMods.keys);
_loadOrder = LoadOrder(modManager.activeMods.values.toList());
}
// Calculate initial moves
@@ -100,7 +100,7 @@ class _ModTroubleshooterWidgetState extends State<ModTroubleshooterWidget> {
// Use the mods from the load order result
setState(() {
_selectedMods = loadOrder.loadOrder;
_loadOrder = loadOrder;
_updateNextMoves();
});
}
@@ -118,7 +118,7 @@ class _ModTroubleshooterWidgetState extends State<ModTroubleshooterWidget> {
// Use the mods from the load order result
setState(() {
_selectedMods = loadOrder.loadOrder;
_loadOrder = loadOrder;
_updateNextMoves();
});
}
@@ -155,7 +155,7 @@ class _ModTroubleshooterWidgetState extends State<ModTroubleshooterWidget> {
void _saveTroubleshootingConfig() {
// Only save if we have a valid selection
if (_selectedMods.isEmpty) {
if (_loadOrder.order.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('No mods selected to save'),
@@ -165,17 +165,13 @@ class _ModTroubleshooterWidgetState extends State<ModTroubleshooterWidget> {
return;
}
// First disable all mods
modManager.disableAll();
// Then enable only the selected mods
modManager.enableMods(_selectedMods);
modManager.saveToConfig(_loadOrder);
// Save the configuration (we don't have direct access to save method, so show a message)
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
'${_selectedMods.length} mods prepared for testing. Please use Save button in the Mods tab to save config.',
'${_loadOrder.order.length} mods prepared for testing. Please use Save button in the Mods tab to save config.',
),
backgroundColor: Colors.orange,
duration: const Duration(seconds: 4),
@@ -184,7 +180,7 @@ class _ModTroubleshooterWidgetState extends State<ModTroubleshooterWidget> {
}
void _markSelectedAsGood() {
if (_selectedMods.isEmpty) {
if (_loadOrder.order.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('No mods selected to mark'),
@@ -195,15 +191,15 @@ class _ModTroubleshooterWidgetState extends State<ModTroubleshooterWidget> {
}
setState(() {
for (final modId in _selectedMods) {
_checkedMods.add(modId);
_problemMods.remove(modId);
for (final mod in _loadOrder.order) {
_checkedMods.add(mod.id);
_problemMods.remove(mod.id);
}
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Marked ${_selectedMods.length} mods as good'),
content: Text('Marked ${_loadOrder.order.length} mods as good'),
backgroundColor: Colors.green,
duration: const Duration(seconds: 2),
),
@@ -211,7 +207,7 @@ class _ModTroubleshooterWidgetState extends State<ModTroubleshooterWidget> {
}
void _markSelectedAsProblem() {
if (_selectedMods.isEmpty) {
if (_loadOrder.order.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('No mods selected to mark'),
@@ -222,15 +218,15 @@ class _ModTroubleshooterWidgetState extends State<ModTroubleshooterWidget> {
}
setState(() {
for (final modId in _selectedMods) {
_problemMods.add(modId);
_checkedMods.remove(modId);
for (final mod in _loadOrder.order) {
_problemMods.add(mod.id);
_checkedMods.remove(mod.id);
}
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Marked ${_selectedMods.length} mods as problematic'),
content: Text('Marked ${_loadOrder.order.length} mods as problematic'),
backgroundColor: Colors.orange,
duration: const Duration(seconds: 2),
),
@@ -307,8 +303,8 @@ class _ModTroubleshooterWidgetState extends State<ModTroubleshooterWidget> {
// Compact instruction
Expanded(
child: Text(
_selectedMods.isNotEmpty
? 'Testing ${_selectedMods.length} mods. Tap highlighted mods to navigate. Mark results below:'
_loadOrder.order.isNotEmpty
? 'Testing ${_loadOrder.order.length} mods. Tap highlighted mods to navigate. Mark results below:'
: 'Click highlighted mods to begin testing. Blue→forward, purple←backward.',
style: TextStyle(
fontSize: AppThemeExtension.of(context).textSizeRegular,
@@ -379,7 +375,7 @@ class _ModTroubleshooterWidgetState extends State<ModTroubleshooterWidget> {
const Spacer(),
// Buttons to mark selected mods
if (_selectedMods.isNotEmpty) ...[
if (_loadOrder.order.isNotEmpty) ...[
OutlinedButton.icon(
icon: Icon(
Icons.error,
@@ -427,7 +423,7 @@ class _ModTroubleshooterWidgetState extends State<ModTroubleshooterWidget> {
onPressed: _resetTroubleshooter,
),
if (_selectedMods.isNotEmpty) ...[
if (_loadOrder.order.isNotEmpty) ...[
const SizedBox(width: 4),
// Save config button
OutlinedButton.icon(
@@ -492,7 +488,9 @@ class _ModTroubleshooterWidgetState extends State<ModTroubleshooterWidget> {
if (mod == null) return const SizedBox.shrink();
// Determine if this mod is in the selection range for highlighted navigation
final bool isSelected = _selectedMods.contains(modId);
final bool isSelected = _loadOrder.order.any(
(m) => m.id == modId,
);
// Check if this mod would be included in the next Forward/Backward move
bool isInNextForward = false;