import 'package:flutter/material.dart'; import '../structs/mod.dart'; import '../structs/settings.dart'; class ModManager extends StatefulWidget { Settings settings; ModManager({super.key, required this.settings}); @override ModManagerState createState() => ModManagerState(settings: settings); } class ModManagerState extends State { Settings settings; ModManagerState({required this.settings}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Conan Exiles Server Manager - Mod Manager"), backgroundColor: Color.fromARGB(255, 100, 0, 0), actions: [ IconButton( onPressed: () async { for (Mod M in settings.inst!.mods) { M.enabled = false; await Future.delayed(Duration(milliseconds: 500)); settings.loggedInUser! .sendDiscordActionLog("${M.mod_name} was disabled"); setState(() {}); } }, icon: Icon(Icons.swipe_down)), IconButton( onPressed: () async { for (Mod M in settings.inst!.mods) { M.enabled = true; await Future.delayed(Duration(milliseconds: 500)); settings.loggedInUser! .sendDiscordActionLog("${M.mod_name} was enabled"); setState(() {}); } }, icon: Icon(Icons.swipe_up)) ], ), body: ReorderableListView.builder( onReorder: (oldIndex, newIndex) { if (oldIndex < newIndex) { // From top to Bottom int end = newIndex - 1; Mod item = settings.inst!.mods[oldIndex]; int i = 0; int local = oldIndex; do { settings.inst!.mods[local] = settings.inst!.mods[++local]; i++; } while (i < end - oldIndex); settings.inst!.mods[end] = item; settings.loggedInUser!.sendDiscordActionLog( "Reordered Mod List\n\n${item.mod_name} is now in load order $end"); } else if (oldIndex > newIndex) { //From bottom to top Mod item = settings.inst!.mods[oldIndex]; for (int i = oldIndex; i > newIndex; i--) { settings.inst!.mods[i] = settings.inst!.mods[i - 1]; } settings.inst!.mods[newIndex] = item; settings.loggedInUser!.sendDiscordActionLog( "Reordered Mod List\n\n${item.mod_name} is now in load order $newIndex"); } setState(() { settings.Write(); }); }, itemBuilder: (ctx, idx) { Mod mod = settings.inst!.mods[idx]; return Padding( key: Key(mod.mod_instance_id()), padding: EdgeInsets.all(12), child: ListTile( title: Text(mod.mod_name), subtitle: Text( "ID: ${mod.mod_id}\nLoad Order: $idx\nEnabled: ${mod.enabled}"), onTap: () async { final reply = await Navigator.pushNamed( context, "/server/mods/edit", arguments: Mod( mod_id: mod.mod_id, mod_name: mod.mod_name, mod_pak: mod.mod_pak, mod_hash: mod.mod_hash, newMod: false, enabled: mod.enabled)); if (reply != null) { ModEditReturnArgs MERA = reply as ModEditReturnArgs; if (MERA.delete) { setState(() { settings.loggedInUser!.sendDiscordActionLog( "Deleted Mod: ${settings.inst!.mods[idx].mod_name}"); settings.inst!.mods.removeAt(idx); }); return; } setState(() { settings.inst!.mods[idx] = MERA.mod!; settings.loggedInUser!.sendDiscordActionLog( "Edited Mod: ${MERA.mod!.mod_name}\n${MERA.mod!.comment}"); }); } }, ), ); }, itemCount: settings.inst!.mods.length, ), floatingActionButton: ElevatedButton( child: Icon(Icons.add), onPressed: () async { // Open new mod info screen final reply = await Navigator.pushNamed(context, "/server/mods/edit", arguments: Mod(newMod: true)); if (reply != null) { ModEditReturnArgs MERA = reply as ModEditReturnArgs; setState(() { settings.inst!.mods.add(MERA.mod!); }); settings.loggedInUser! .sendDiscordActionLog("Added Mod: ${MERA.mod!.mod_name}"); } }, ), ); } } class ModPage extends StatefulWidget { @override State createState() => ModPageState(); } class ModPageState extends State { TextEditingController id = TextEditingController(); TextEditingController name = TextEditingController(); String instance = ""; bool isNewMod = false; String pak = "Not initialized"; String hash = ""; bool enabled = false; TextEditingController comment = TextEditingController(); @override void didChangeDependencies() { final args = ModalRoute.of(context)!.settings.arguments as Mod?; if (args != null) { id.text = args.mod_id.toString(); name.text = args.mod_name; isNewMod = args.newMod; instance = args.mod_instance_id(); pak = args.mod_pak; hash = args.mod_hash; enabled = args.enabled; comment.text = args.comment; } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Mod Editor"), backgroundColor: Color.fromARGB(255, 100, 0, 0), ), floatingActionButton: ElevatedButton( child: Text("Save"), onPressed: () { int idVal = 0; try { idVal = int.parse(id.text); } catch (E) {} Navigator.pop( context, ModEditReturnArgs( delete: false, mod: Mod( mod_id: idVal, mod_name: name.text, newMod: false, enabled: enabled, comment: comment.text))); }, ), body: SingleChildScrollView( padding: const EdgeInsets.all(16), child: Column(children: [ Row( children: [ SizedBox( width: 150, child: ListTile( leading: Icon(Icons.abc_rounded), title: Text("Mod Name"), )), Expanded( child: TextField( controller: name, decoration: InputDecoration( border: OutlineInputBorder( borderRadius: BorderRadius.circular(4)))), ) ], ), SizedBox( height: 16, ), Row( children: [ SizedBox( width: 150, child: ListTile( leading: Icon(Icons.perm_identity), title: Text("Mod ID")), ), Expanded( child: TextField( controller: id, keyboardType: TextInputType.number, decoration: InputDecoration( border: OutlineInputBorder( borderRadius: BorderRadius.circular(4))), )) ], ), SizedBox( height: 16, ), ListTile( title: Text("Mod Instance ID"), subtitle: Text(instance), ), ListTile( title: Text("Mod Pak File: $pak"), subtitle: Text("Mod pak file name as detected during downloading"), ), ListTile( title: Text("Mod Hash"), subtitle: Text(hash), ), SwitchListTile( value: enabled, onChanged: (V) { setState(() { enabled = V; }); Settings.Instance.loggedInUser!.sendDiscordActionLog( "${name.text} was ${enabled ? "enabled" : "disabled"}"); }, title: Text("Enabled"), subtitle: Text("Whether mod is enabled or not"), ), Row( children: [ SizedBox( width: 150, child: ListTile( leading: Icon(Icons.comment), title: Text("Comment"), ), ), Expanded( child: TextField( controller: comment, decoration: InputDecoration( border: OutlineInputBorder( borderRadius: BorderRadius.circular(8))), )) ], ), if (!isNewMod) ElevatedButton( onPressed: () { Navigator.pop(context, ModEditReturnArgs(delete: true)); }, child: Row( children: [ Icon(Icons.delete), SizedBox( width: 4, ), Text("Remove Mod") ], )), ]), ), ); } } class ModEditReturnArgs { bool delete; Mod? mod; ModEditReturnArgs({required this.delete, this.mod}); }