Implement incremental loading via streaming
This commit is contained in:
143
lib/main.dart
143
lib/main.dart
@@ -1,9 +1,15 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:rimworld_modman/modloader.dart';
|
import 'package:rimworld_modman/modloader.dart';
|
||||||
|
|
||||||
|
// Global variable to store loaded mods for access across the app
|
||||||
|
late ModList modManager;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
ModList(path: modsRoot).load();
|
modManager = ModList(path: modsRoot);
|
||||||
ConfigFile(path: configPath).load();
|
modManager.load().listen((mod) {
|
||||||
|
print(mod);
|
||||||
|
});
|
||||||
|
|
||||||
// runApp(const RimWorldModManager());
|
// runApp(const RimWorldModManager());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,7 +67,7 @@ class _ModManagerHomePageState extends State<ModManagerHomePage> {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
items: const [
|
items: const [
|
||||||
BottomNavigationBarItem(icon: Icon(Icons.list), label: 'Mods'),
|
BottomNavigationBarItem(icon: Icon(Icons.extension), label: 'Mods'),
|
||||||
BottomNavigationBarItem(
|
BottomNavigationBarItem(
|
||||||
icon: Icon(Icons.reorder),
|
icon: Icon(Icons.reorder),
|
||||||
label: 'Load Order',
|
label: 'Load Order',
|
||||||
@@ -77,11 +83,30 @@ class _ModManagerHomePageState extends State<ModManagerHomePage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Page to display all installed mods with enable/disable toggles
|
// Page to display all installed mods with enable/disable toggles
|
||||||
class ModListPage extends StatelessWidget {
|
class ModListPage extends StatefulWidget {
|
||||||
const ModListPage({super.key});
|
const ModListPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<ModListPage> createState() => _ModListPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ModListPageState extends State<ModListPage> {
|
||||||
|
final List<Mod> _loadedMods = [];
|
||||||
|
bool _isLoading = false;
|
||||||
|
String _loadingStatus = '';
|
||||||
|
int _totalModsFound = 0;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
body:
|
||||||
|
_loadedMods.isEmpty && !_isLoading
|
||||||
|
? _buildEmptyState()
|
||||||
|
: _buildModList(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildEmptyState() {
|
||||||
return Center(
|
return Center(
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
@@ -91,20 +116,122 @@ class ModListPage extends StatelessWidget {
|
|||||||
Text('Mod List', style: Theme.of(context).textTheme.headlineMedium),
|
Text('Mod List', style: Theme.of(context).textTheme.headlineMedium),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
Text(
|
Text(
|
||||||
'Here you\'ll see your installed mods.',
|
'Ready to scan for RimWorld mods.',
|
||||||
style: Theme.of(context).textTheme.bodyLarge,
|
style: Theme.of(context).textTheme.bodyLarge,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: () {
|
onPressed: _startLoadingMods,
|
||||||
// TODO: Implement mod scanning functionality
|
|
||||||
},
|
|
||||||
child: const Text('Scan for Mods'),
|
child: const Text('Scan for Mods'),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _buildModList() {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
if (_isLoading)
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
LinearProgressIndicator(
|
||||||
|
value:
|
||||||
|
_totalModsFound > 0
|
||||||
|
? _loadedMods.length / _totalModsFound
|
||||||
|
: null,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
Text(
|
||||||
|
_loadingStatus,
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
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.isNotEmpty)
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text('${_loadedMods.length} mods loaded'),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: _startLoadingMods,
|
||||||
|
child: const Text('Reload'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _startLoadingMods() {
|
||||||
|
setState(() {
|
||||||
|
_loadedMods.clear();
|
||||||
|
_isLoading = true;
|
||||||
|
_loadingStatus = 'Scanning for mods...';
|
||||||
|
});
|
||||||
|
|
||||||
|
// Use batch loading for better performance
|
||||||
|
modManager
|
||||||
|
.load()
|
||||||
|
.listen(
|
||||||
|
(mod) {
|
||||||
|
setState(() {
|
||||||
|
_loadedMods.add(mod);
|
||||||
|
_loadingStatus = 'Loaded ${_loadedMods.length} 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));
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Page to manage mod load order with dependency visualization
|
// Page to manage mod load order with dependency visualization
|
||||||
|
@@ -177,7 +177,7 @@ class ModList {
|
|||||||
|
|
||||||
ModList({required this.path});
|
ModList({required this.path});
|
||||||
|
|
||||||
void load() {
|
Stream<Mod> load() async* {
|
||||||
final directory = Directory(path);
|
final directory = Directory(path);
|
||||||
print('Loading configuration from: $path');
|
print('Loading configuration from: $path');
|
||||||
|
|
||||||
@@ -187,8 +187,12 @@ class ModList {
|
|||||||
entities.whereType<Directory>().map((dir) => dir.path).toList();
|
entities.whereType<Directory>().map((dir) => dir.path).toList();
|
||||||
|
|
||||||
print('Found ${modDirectories.length} mod directories:');
|
print('Found ${modDirectories.length} mod directories:');
|
||||||
|
|
||||||
for (final modDir in modDirectories) {
|
for (final modDir in modDirectories) {
|
||||||
try {
|
try {
|
||||||
|
// Add a small delay to prevent UI freezing and give time for rendering
|
||||||
|
await Future.delayed(const Duration(milliseconds: 5));
|
||||||
|
|
||||||
final mod = Mod.fromDirectory(modDir);
|
final mod = Mod.fromDirectory(modDir);
|
||||||
mods[mod.id] = mod;
|
mods[mod.id] = mod;
|
||||||
print(
|
print(
|
||||||
@@ -198,6 +202,8 @@ class ModList {
|
|||||||
'Soft Dependencies: ${mod.softDependencies.join(', ')}, '
|
'Soft Dependencies: ${mod.softDependencies.join(', ')}, '
|
||||||
'Incompatibilities: ${mod.incompatabilities.join(', ')}',
|
'Incompatibilities: ${mod.incompatabilities.join(', ')}',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
yield mod;
|
||||||
print('Current total mods loaded: ${mods.length}');
|
print('Current total mods loaded: ${mods.length}');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error loading mod from directory: $modDir');
|
print('Error loading mod from directory: $modDir');
|
||||||
|
Reference in New Issue
Block a user