Fix up some of the todos
This commit is contained in:
135
lib/main.dart
135
lib/main.dart
@@ -1,8 +1,6 @@
|
||||
import 'dart:io';
|
||||
|
||||
// TODO: Fix "load dependencies", it causes fake errors between expansions and base game
|
||||
// TODO: Add an icon for incompatibilities on the mod list
|
||||
// TODO: Get rid of the demo button WHAT THE FUCK IS THE DEMO BUTTON??
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:rimworld_modman/logger.dart';
|
||||
import 'package:rimworld_modman/components/html_tooltip.dart';
|
||||
@@ -31,6 +29,7 @@ class AppThemeExtension extends ThemeExtension<AppThemeExtension> {
|
||||
final Color linkColor;
|
||||
final Color loadAfterColor;
|
||||
final Color loadBeforeColor;
|
||||
final Color incompatibleColor;
|
||||
|
||||
AppThemeExtension({
|
||||
required this.iconSizeSmall,
|
||||
@@ -52,6 +51,7 @@ class AppThemeExtension extends ThemeExtension<AppThemeExtension> {
|
||||
required this.linkColor,
|
||||
required this.loadAfterColor,
|
||||
required this.loadBeforeColor,
|
||||
required this.incompatibleColor,
|
||||
});
|
||||
|
||||
static AppThemeExtension of(BuildContext context) {
|
||||
@@ -79,6 +79,7 @@ class AppThemeExtension extends ThemeExtension<AppThemeExtension> {
|
||||
Color? linkColor,
|
||||
Color? loadAfterColor,
|
||||
Color? loadBeforeColor,
|
||||
Color? incompatibleColor,
|
||||
}) {
|
||||
return AppThemeExtension(
|
||||
iconSizeSmall: iconSizeSmall ?? this.iconSizeSmall,
|
||||
@@ -101,6 +102,7 @@ class AppThemeExtension extends ThemeExtension<AppThemeExtension> {
|
||||
linkColor: linkColor ?? this.linkColor,
|
||||
loadAfterColor: loadAfterColor ?? this.loadAfterColor,
|
||||
loadBeforeColor: loadBeforeColor ?? this.loadBeforeColor,
|
||||
incompatibleColor: incompatibleColor ?? this.incompatibleColor,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -138,6 +140,7 @@ class AppThemeExtension extends ThemeExtension<AppThemeExtension> {
|
||||
linkColor: Color.lerp(linkColor, other.linkColor, t)!,
|
||||
loadAfterColor: Color.lerp(loadAfterColor, other.loadAfterColor, t)!,
|
||||
loadBeforeColor: Color.lerp(loadBeforeColor, other.loadBeforeColor, t)!,
|
||||
incompatibleColor: Color.lerp(incompatibleColor, other.incompatibleColor, t)!,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -167,6 +170,7 @@ class AppThemeExtension extends ThemeExtension<AppThemeExtension> {
|
||||
linkColor: Colors.orange,
|
||||
loadAfterColor: Colors.blue,
|
||||
loadBeforeColor: Colors.green,
|
||||
incompatibleColor: Colors.red.shade400,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -267,10 +271,6 @@ class _ModManagerHomePageState extends State<ModManagerHomePage> {
|
||||
icon: Icon(Icons.build),
|
||||
label: 'Troubleshoot',
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(Icons.format_paint),
|
||||
label: 'Demo',
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
@@ -302,6 +302,8 @@ class _ModManagerPageState extends State<ModManagerPage> {
|
||||
|
||||
final TextEditingController _searchController = TextEditingController();
|
||||
String _searchQuery = '';
|
||||
bool _useRegex = false;
|
||||
RegExp? _searchRegex;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -310,12 +312,6 @@ class _ModManagerPageState extends State<ModManagerPage> {
|
||||
if (modManager.mods.isNotEmpty) {
|
||||
_loadModsFromGlobalState();
|
||||
}
|
||||
|
||||
_searchController.addListener(() {
|
||||
setState(() {
|
||||
_searchQuery = _searchController.text.toLowerCase();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -409,10 +405,33 @@ class _ModManagerPageState extends State<ModManagerPage> {
|
||||
|
||||
Widget _buildSplitView() {
|
||||
// Filter both available and active mods based on search query
|
||||
final filteredAvailableMods =
|
||||
_searchQuery.isEmpty
|
||||
? _availableMods
|
||||
: _availableMods
|
||||
List<Mod> filteredAvailableMods;
|
||||
List<Mod> filteredActiveMods;
|
||||
|
||||
if (_searchQuery.isEmpty) {
|
||||
filteredAvailableMods = _availableMods;
|
||||
filteredActiveMods = _activeMods;
|
||||
} else {
|
||||
if (_useRegex && _searchRegex != null) {
|
||||
// Use regex pattern for filtering
|
||||
filteredAvailableMods = _availableMods
|
||||
.where(
|
||||
(mod) =>
|
||||
_searchRegex!.hasMatch(mod.name.toLowerCase()) ||
|
||||
_searchRegex!.hasMatch(mod.id.toLowerCase()),
|
||||
)
|
||||
.toList();
|
||||
|
||||
filteredActiveMods = _activeMods
|
||||
.where(
|
||||
(mod) =>
|
||||
_searchRegex!.hasMatch(mod.name.toLowerCase()) ||
|
||||
_searchRegex!.hasMatch(mod.id.toLowerCase()),
|
||||
)
|
||||
.toList();
|
||||
} else {
|
||||
// Use simple string contains for filtering
|
||||
filteredAvailableMods = _availableMods
|
||||
.where(
|
||||
(mod) =>
|
||||
mod.name.toLowerCase().contains(_searchQuery) ||
|
||||
@@ -420,16 +439,15 @@ class _ModManagerPageState extends State<ModManagerPage> {
|
||||
)
|
||||
.toList();
|
||||
|
||||
final filteredActiveMods =
|
||||
_searchQuery.isEmpty
|
||||
? _activeMods
|
||||
: _activeMods
|
||||
filteredActiveMods = _activeMods
|
||||
.where(
|
||||
(mod) =>
|
||||
mod.name.toLowerCase().contains(_searchQuery) ||
|
||||
mod.id.toLowerCase().contains(_searchQuery),
|
||||
)
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
@@ -457,6 +475,51 @@ class _ModManagerPageState extends State<ModManagerPage> {
|
||||
)
|
||||
: null,
|
||||
),
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_searchQuery = value.toLowerCase();
|
||||
|
||||
// Try to compile regex if regex mode is enabled
|
||||
if (_useRegex && _searchQuery.isNotEmpty) {
|
||||
try {
|
||||
_searchRegex = RegExp(_searchQuery, caseSensitive: false);
|
||||
} catch (e) {
|
||||
// If regex is invalid, fallback to normal search
|
||||
_searchRegex = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
// Regex toggle
|
||||
Tooltip(
|
||||
message: 'Use regex pattern matching',
|
||||
child: Row(
|
||||
children: [
|
||||
Checkbox(
|
||||
value: _useRegex,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_useRegex = value ?? false;
|
||||
|
||||
// Try to compile regex if toggled on
|
||||
if (_useRegex && _searchQuery.isNotEmpty) {
|
||||
try {
|
||||
_searchRegex = RegExp(_searchQuery, caseSensitive: false);
|
||||
} catch (e) {
|
||||
// If regex fails, keep checkbox on but disable regex internally
|
||||
_searchRegex = null;
|
||||
}
|
||||
} else {
|
||||
_searchRegex = null;
|
||||
}
|
||||
});
|
||||
},
|
||||
),
|
||||
const Text('Regex'),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
@@ -841,6 +904,22 @@ class _ModManagerPageState extends State<ModManagerPage> {
|
||||
).iconSizeRegular,
|
||||
),
|
||||
),
|
||||
if (mod.incompatibilities.isNotEmpty)
|
||||
Tooltip(
|
||||
message:
|
||||
'Incompatible with:\n${mod.incompatibilities.join('\n')}',
|
||||
child: Icon(
|
||||
Icons.warning_amber_rounded,
|
||||
color:
|
||||
AppThemeExtension.of(
|
||||
context,
|
||||
).incompatibleColor,
|
||||
size:
|
||||
AppThemeExtension.of(
|
||||
context,
|
||||
).iconSizeRegular,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
onTap: () {
|
||||
@@ -1097,6 +1176,22 @@ class _ModManagerPageState extends State<ModManagerPage> {
|
||||
).iconSizeRegular,
|
||||
),
|
||||
),
|
||||
if (mod.incompatibilities.isNotEmpty)
|
||||
Tooltip(
|
||||
message:
|
||||
'Incompatible with:\n${mod.incompatibilities.join('\n')}',
|
||||
child: Icon(
|
||||
Icons.warning_amber_rounded,
|
||||
color:
|
||||
AppThemeExtension.of(
|
||||
context,
|
||||
).incompatibleColor,
|
||||
size:
|
||||
AppThemeExtension.of(
|
||||
context,
|
||||
).iconSizeRegular,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
onTap: () {
|
||||
|
@@ -702,13 +702,76 @@ class ModList {
|
||||
LoadOrder loadRequired([LoadOrder? loadOrder]) {
|
||||
loadOrder ??= LoadOrder();
|
||||
final toEnable = <String>[];
|
||||
final logger = Logger.instance;
|
||||
|
||||
// First, identify all base game and expansion mods
|
||||
final baseGameIds = <String>{};
|
||||
final expansionIds = <String>{};
|
||||
|
||||
for (final entry in mods.entries) {
|
||||
if (entry.value.isBaseGame) {
|
||||
baseGameIds.add(entry.key);
|
||||
} else if (entry.value.isExpansion) {
|
||||
expansionIds.add(entry.key);
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Base game mods: ${baseGameIds.join(', ')}");
|
||||
logger.info("Expansion mods: ${expansionIds.join(', ')}");
|
||||
|
||||
// Load dependencies for all active mods
|
||||
for (final modid in activeMods.keys) {
|
||||
loadDependencies(modid, loadOrder, toEnable);
|
||||
}
|
||||
|
||||
// Enable all required dependencies
|
||||
for (final modid in toEnable) {
|
||||
setEnabled(modid, true);
|
||||
}
|
||||
return generateLoadOrder(loadOrder);
|
||||
|
||||
// Generate the load order
|
||||
final newLoadOrder = generateLoadOrder(loadOrder);
|
||||
|
||||
// Filter out any error messages related to incompatibilities between base game and expansions
|
||||
if (newLoadOrder.hasErrors) {
|
||||
final filteredErrors = <String>[];
|
||||
|
||||
for (final error in newLoadOrder.errors) {
|
||||
// Check if the error is about incompatibility
|
||||
if (error.contains('Incompatibility detected:')) {
|
||||
// Extract the mod IDs from the error message
|
||||
final parts = error.split(' is incompatible with ');
|
||||
if (parts.length == 2) {
|
||||
final firstModId = parts[0].replaceAll('Incompatibility detected: ', '');
|
||||
final secondModId = parts[1];
|
||||
|
||||
// Check if either mod is a base game or expansion
|
||||
final isBaseGameOrExpansion =
|
||||
baseGameIds.contains(firstModId) || baseGameIds.contains(secondModId) ||
|
||||
expansionIds.contains(firstModId) || expansionIds.contains(secondModId);
|
||||
|
||||
// Only keep the error if it's not between base game/expansions
|
||||
if (!isBaseGameOrExpansion) {
|
||||
filteredErrors.add(error);
|
||||
} else {
|
||||
logger.info("Ignoring incompatibility between base game or expansion mods: $error");
|
||||
}
|
||||
} else {
|
||||
// If we can't parse the error, keep it
|
||||
filteredErrors.add(error);
|
||||
}
|
||||
} else {
|
||||
// Keep non-incompatibility errors
|
||||
filteredErrors.add(error);
|
||||
}
|
||||
}
|
||||
|
||||
// Replace the errors with the filtered list
|
||||
newLoadOrder.errors.clear();
|
||||
newLoadOrder.errors.addAll(filteredErrors);
|
||||
}
|
||||
|
||||
return newLoadOrder;
|
||||
}
|
||||
|
||||
LoadOrder loadRequiredBaseGame([LoadOrder? loadOrder]) {
|
||||
|
Reference in New Issue
Block a user