Fix loadBefore and Rimworld and expansions
This commit is contained in:
245
lib/main.dart
245
lib/main.dart
@@ -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
|
||||
|
Reference in New Issue
Block a user