Fix loadBefore and Rimworld and expansions

This commit is contained in:
2025-03-15 23:34:55 +01:00
parent 74eec3f3cc
commit 22ec31c2a7
2 changed files with 424 additions and 142 deletions

View File

@@ -91,12 +91,31 @@ class ModListPage extends StatefulWidget {
}
class _ModListPageState extends State<ModListPage> {
final List<Mod> _loadedMods = [];
List<Mod> _loadedMods = [];
bool _isLoading = false;
String _loadingStatus = '';
int _totalModsFound = 0;
bool _skipFileCount = false; // Skip file counting by default for faster loading
@override
void initState() {
super.initState();
// Check if mods are already loaded in the global modManager
if (modManager.modsLoaded) {
_loadModsFromGlobalState();
}
}
void _loadModsFromGlobalState() {
setState(() {
_loadedMods = modManager.mods.values.toList();
_loadedMods.sort((a, b) => a.name.compareTo(b.name));
_isLoading = false;
_loadingStatus = modManager.loadingStatus;
_totalModsFound = modManager.totalModsFound;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
@@ -152,49 +171,71 @@ class _ModListPageState extends State<ModListPage> {
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
LinearProgressIndicator(
value:
_totalModsFound > 0
? _loadedMods.length / _totalModsFound
: null,
),
const SizedBox(height: 8),
const CircularProgressIndicator(),
const SizedBox(height: 16),
Text(
_loadingStatus,
style: Theme.of(context).textTheme.bodyMedium,
textAlign: TextAlign.center,
),
],
),
),
Expanded(
child: ListView.builder(
itemCount: _loadedMods.length,
itemBuilder: (context, index) {
final mod = _loadedMods[index];
return Card(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
child: ListTile(
title: Text(mod.name),
subtitle: Text(
'ID: ${mod.id}\nSize: ${mod.size} files',
style: Theme.of(context).textTheme.bodySmall,
),
trailing: Icon(
Icons.circle,
color:
mod.hardDependencies.isNotEmpty
? Colors.orange
: Colors.green,
size: 12,
),
onTap: () {
// TODO: Show mod details
},
),
);
},
if (!_isLoading && _loadedMods.isEmpty)
Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
'No mods found. Try reloading.',
textAlign: TextAlign.center,
),
),
),
if (_loadedMods.isNotEmpty)
Expanded(
child: ListView.builder(
itemCount: _loadedMods.length,
itemBuilder: (context, index) {
final mod = _loadedMods[index];
return Card(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
child: ListTile(
title: Text(mod.name),
subtitle: Text(
'ID: ${mod.id}\nSize: ${mod.size} files',
style: Theme.of(context).textTheme.bodySmall,
),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
if (mod.isBaseGame)
Tooltip(
message: 'Base Game',
child: Icon(Icons.home, color: Colors.blue, size: 16),
),
if (mod.isExpansion)
Tooltip(
message: 'Expansion',
child: Icon(Icons.star, color: Colors.yellow, size: 16),
),
Icon(
Icons.circle,
color:
mod.hardDependencies.isNotEmpty
? Colors.orange
: Colors.green,
size: 12,
),
],
),
onTap: () {
// TODO: Show mod details
},
),
);
},
),
),
),
if (!_isLoading && _loadedMods.isNotEmpty)
Padding(
padding: const EdgeInsets.all(16.0),
@@ -220,45 +261,23 @@ class _ModListPageState extends State<ModListPage> {
_loadingStatus = 'Scanning for mods...';
});
// First get the mod directories to know the total count
final directory = Directory(modsRoot);
if (directory.existsSync()) {
final List<FileSystemEntity> entities = directory.listSync();
final List<String> modDirectories =
entities.whereType<Directory>().map((dir) => dir.path).toList();
// Use the simplified loading approach
modManager.loadWithConfig(skipFileCount: _skipFileCount).then((_) {
setState(() {
_totalModsFound = modDirectories.length;
_loadingStatus = 'Found $_totalModsFound mod directories. Loading...';
_loadedMods = modManager.mods.values.toList();
_isLoading = false;
_loadingStatus = modManager.loadingStatus;
_totalModsFound = modManager.totalModsFound;
// Sort mods by name for better display
_loadedMods.sort((a, b) => a.name.compareTo(b.name));
});
}
// Use the serial loading with our skipFileCount option
modManager
.load(skipFileCount: _skipFileCount)
.listen(
(mod) {
setState(() {
_loadedMods.add(mod);
_loadingStatus = 'Loaded ${_loadedMods.length}/$_totalModsFound mods...';
});
},
onError: (error) {
setState(() {
_isLoading = false;
_loadingStatus = 'Error loading mods: $error';
});
},
onDone: () {
setState(() {
_isLoading = false;
_loadingStatus = 'Completed! ${_loadedMods.length} mods loaded.';
// Sort mods by name for better display
_loadedMods.sort((a, b) => a.name.compareTo(b.name));
});
},
);
}).catchError((error) {
setState(() {
_isLoading = false;
_loadingStatus = 'Error loading mods: $error';
});
});
}
}
@@ -278,6 +297,17 @@ class _LoadOrderPageState extends State<LoadOrderPage> {
List<String>? _cycleInfo;
List<List<String>> _incompatibleMods = [];
@override
void initState() {
super.initState();
// If we already have loaded mods, update the status message
if (modManager.modsLoaded && modManager.mods.isNotEmpty) {
_statusMessage = 'Ready to sort ${modManager.mods.length} loaded mods';
} else {
_statusMessage = 'No mods have been loaded yet. Please load mods first.';
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
@@ -319,8 +349,27 @@ class _LoadOrderPageState extends State<LoadOrderPage> {
),
const SizedBox(height: 16),
if (_isLoading)
const LinearProgressIndicator(),
if (_statusMessage.isNotEmpty)
Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: Center(
child: Column(
children: [
const CircularProgressIndicator(),
const SizedBox(height: 16),
Text(
_statusMessage,
textAlign: TextAlign.center,
style: TextStyle(
color: _hasCycles || _incompatibleMods.isNotEmpty
? Colors.orange
: Colors.green,
),
),
],
),
),
),
if (!_isLoading && _statusMessage.isNotEmpty)
Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Text(
@@ -376,6 +425,18 @@ class _LoadOrderPageState extends State<LoadOrderPage> {
children: [
Text('Legend:', style: TextStyle(fontWeight: FontWeight.bold)),
const SizedBox(height: 4),
Row(
children: [
Icon(Icons.home, color: Colors.blue, size: 16),
const SizedBox(width: 4),
Text('Base Game', style: TextStyle(fontSize: 12)),
const SizedBox(width: 12),
Icon(Icons.star, color: Colors.yellow, size: 16),
const SizedBox(width: 4),
Text('Expansion', style: TextStyle(fontSize: 12)),
],
),
const SizedBox(height: 4),
Row(
children: [
Icon(Icons.link, color: Colors.orange, size: 16),
@@ -388,6 +449,14 @@ class _LoadOrderPageState extends State<LoadOrderPage> {
],
),
const SizedBox(height: 4),
Row(
children: [
Icon(Icons.arrow_forward, color: Colors.green, size: 16),
const SizedBox(width: 4),
Text('Loads before other mods', style: TextStyle(fontSize: 12)),
],
),
const SizedBox(height: 4),
Row(
children: [
Container(width: 12, height: 12, color: Colors.amber),
@@ -406,7 +475,9 @@ class _LoadOrderPageState extends State<LoadOrderPage> {
child: _sortedMods.isEmpty
? Center(
child: Text(
'Click "Auto-sort Mods" to generate a load order based on dependencies.',
modManager.modsLoaded
? 'Click "Auto-sort Mods" to generate a load order for ${modManager.mods.length} loaded mods.'
: 'Please go to the Mods tab first to load mods.',
textAlign: TextAlign.center,
),
)
@@ -446,12 +517,28 @@ class _LoadOrderPageState extends State<LoadOrderPage> {
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
if (mod.isBaseGame)
Tooltip(
message: 'Base Game',
child: Icon(Icons.home, color: Colors.blue, size: 16),
),
if (mod.isExpansion)
Tooltip(
message: 'Expansion',
child: Icon(Icons.star, color: Colors.yellow, size: 16),
),
if (mod.hardDependencies.isNotEmpty)
Icon(Icons.link, color: Colors.orange, size: 16),
const SizedBox(width: 4),
if (mod.softDependencies.isNotEmpty)
Icon(Icons.link_off, color: Colors.blue, size: 16),
const SizedBox(width: 4),
if (mod.loadBefore.isNotEmpty)
Tooltip(
message: 'Loads before other mods',
child: Icon(Icons.arrow_forward, color: Colors.green, size: 16),
),
const SizedBox(width: 4),
Text(
'${mod.size} files',
style: TextStyle(
@@ -480,7 +567,7 @@ class _LoadOrderPageState extends State<LoadOrderPage> {
void _sortMods() async {
if (modManager.mods.isEmpty) {
setState(() {
_statusMessage = 'No mods have been loaded yet. Please load mods first.';
_statusMessage = 'No mods have been loaded yet. Please go to the Mods tab and load mods first.';
});
return;
}
@@ -493,8 +580,8 @@ class _LoadOrderPageState extends State<LoadOrderPage> {
_incompatibleMods = [];
});
// This could be slow so run in a separate isolate or compute
await Future.delayed(Duration.zero); // Allow UI to update
// Use a Future.delayed to allow the UI to update
await Future.delayed(Duration.zero);
try {
// Check for cycles first