From 12993a209d5888498fe267ce0f364da3cbaafdf6 Mon Sep 17 00:00:00 2001 From: Dane Madsen Date: Wed, 24 Apr 2024 23:19:57 +1000 Subject: [PATCH] Improvements to character loading / saving (#512) * url setState * fixes to model dropdown * work on saving * fixes to character loading / saving * small improverments --- lib/providers/character.dart | 1 + .../character_customization_page.dart | 187 ++++++++++-------- .../mobile/widgets/appbars/home_app_bar.dart | 5 +- 3 files changed, 109 insertions(+), 84 deletions(-) diff --git a/lib/providers/character.dart b/lib/providers/character.dart index ef133c6f..139964a4 100644 --- a/lib/providers/character.dart +++ b/lib/providers/character.dart @@ -10,6 +10,7 @@ import 'package:maid/static/logger.dart'; import 'package:image/image.dart'; import 'package:maid/static/utilities.dart'; import 'package:path_provider/path_provider.dart'; +import 'package:shared_preferences/shared_preferences.dart'; class Character extends ChangeNotifier { File? _profile; diff --git a/lib/ui/mobile/pages/character/character_customization_page.dart b/lib/ui/mobile/pages/character/character_customization_page.dart index b94eb166..3c175ba0 100644 --- a/lib/ui/mobile/pages/character/character_customization_page.dart +++ b/lib/ui/mobile/pages/character/character_customization_page.dart @@ -20,54 +20,58 @@ class CharacterCustomizationPage extends StatefulWidget { } class _CharacterCustomizationPageState extends State { - bool _regenerate = true; + bool regenerate = true; - late TextEditingController _nameController; - late TextEditingController _descriptionController; - late TextEditingController _personalityController; - late TextEditingController _scenarioController; - late TextEditingController _systemController; - late List _greetingControllers; - late List _exampleControllers; + late TextEditingController nameController; + late TextEditingController descriptionController; + late TextEditingController personalityController; + late TextEditingController scenarioController; + late TextEditingController systemController; + late List greetingControllers; + late List exampleControllers; + + Future save() async { + final prefs = await SharedPreferences.getInstance(); + + final characterString = prefs.getString("last_character"); + final character = Character.fromMap(json.decode(characterString ?? "{}")); + + final String charactersJson = prefs.getString("characters") ?? '[]'; + final List charactersList = json.decode(charactersJson); + + List characters; + characters = charactersList.map((characterMap) { + return Character.fromMap(characterMap); + }).toList(); + + characters.removeWhere((listCharacter) { + return character.hash == listCharacter.hash; + }); + characters.insert(0, character); + + final String newCharactersJson = + json.encode(characters.map((character) => character.toMap()).toList()); + + prefs.setString("characters", newCharactersJson); + } @override void dispose() { super.dispose(); - _nameController.dispose(); - _descriptionController.dispose(); - _personalityController.dispose(); - _scenarioController.dispose(); - _systemController.dispose(); + nameController.dispose(); + descriptionController.dispose(); + personalityController.dispose(); + scenarioController.dispose(); + systemController.dispose(); - for (var controller in _greetingControllers) { + for (var controller in greetingControllers) { controller.dispose(); } - for (var controller in _exampleControllers) { + for (var controller in exampleControllers) { controller.dispose(); } - SharedPreferences.getInstance().then((prefs) { - final characterString = prefs.getString("last_character"); - final character = Character.fromMap(json.decode(characterString ?? "{}")); - - final String charactersJson = prefs.getString("characters") ?? '[]'; - final List charactersList = json.decode(charactersJson); - - List characters; - characters = charactersList.map((characterMap) { - return Character.fromMap(characterMap); - }).toList(); - - characters.removeWhere((listCharacter) { - return character.hash == listCharacter.hash; - }); - characters.insert(0, character); - - final String newCharactersJson = - json.encode(characters.map((character) => character.toMap()).toList()); - - prefs.setString("characters", newCharactersJson); - }); + save(); } @override @@ -76,25 +80,27 @@ class _CharacterCustomizationPageState extends State appBar: const GenericAppBar(title: "Character Customization"), body: Consumer( builder: (context, character, child) { - if (_regenerate) { - _nameController = TextEditingController(text: character.name); - _descriptionController = TextEditingController(text: character.description); - _personalityController = TextEditingController(text: character.personality); - _scenarioController = TextEditingController(text: character.scenario); - _systemController = TextEditingController(text: character.system); + if (regenerate) { + nameController = TextEditingController(text: character.name); + descriptionController = TextEditingController(text: character.description); + personalityController = TextEditingController(text: character.personality); + scenarioController = TextEditingController(text: character.scenario); + systemController = TextEditingController(text: character.system); - _greetingControllers = List.generate( + greetingControllers = List.generate( character.greetings.length, (index) => TextEditingController(text: character.greetings[index]), ); - _exampleControllers = List.generate( + exampleControllers = List.generate( character.examples.length, (index) => TextEditingController(text: character.examples[index]["content"]), ); - _regenerate = false; + save(); + + regenerate = false; } SharedPreferences.getInstance().then((prefs) { @@ -122,21 +128,17 @@ class _CharacterCustomizationPageState extends State children: [ FilledButton( onPressed: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => - const CharacterBrowserPage())); + save(); }, child: Text( - "Switch Character", + "Save Changes", style: Theme.of(context).textTheme.labelLarge, ), ), const SizedBox(width: 10.0), FilledButton( onPressed: () { - _regenerate = true; + regenerate = true; character.reset(); }, child: Text( @@ -151,9 +153,9 @@ class _CharacterCustomizationPageState extends State mainAxisAlignment: MainAxisAlignment.center, children: [ FilledButton( - onPressed: () async { - _regenerate = true; - await storageOperationDialog(context, character.importImage); + onPressed: () { + regenerate = true; + storageOperationDialog(context, character.importImage); }, child: Text( "Load Image", @@ -162,8 +164,8 @@ class _CharacterCustomizationPageState extends State ), const SizedBox(width: 10.0), FilledButton( - onPressed: () async { - await storageOperationDialog(context, character.exportImage); + onPressed: () { + storageOperationDialog(context, character.exportImage); }, child: Text( "Save Image", @@ -177,8 +179,8 @@ class _CharacterCustomizationPageState extends State mainAxisAlignment: MainAxisAlignment.center, children: [ FilledButton( - onPressed: () async { - await storageOperationDialog(context, character.exportSTV2); + onPressed: () { + storageOperationDialog(context, character.exportSTV2); }, child: Text( "Save STV2 JSON", @@ -187,8 +189,8 @@ class _CharacterCustomizationPageState extends State ), const SizedBox(width: 10.0), FilledButton( - onPressed: () async { - await storageOperationDialog(context, character.exportMCF); + onPressed: () { + storageOperationDialog(context, character.exportMCF); }, child: Text( "Save MCF JSON", @@ -198,15 +200,34 @@ class _CharacterCustomizationPageState extends State ], ), const SizedBox(height: 15.0), - FilledButton( - onPressed: () async { - _regenerate = true; - await storageOperationDialog(context, character.importJSON); - }, - child: Text( - "Load JSON", - style: Theme.of(context).textTheme.labelLarge, - ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + FilledButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + const CharacterBrowserPage())); + }, + child: Text( + "Switch Character", + style: Theme.of(context).textTheme.labelLarge, + ), + ), + const SizedBox(width: 10.0), + FilledButton( + onPressed: () { + regenerate = true; + storageOperationDialog(context, character.importJSON); + }, + child: Text( + "Load JSON", + style: Theme.of(context).textTheme.labelLarge, + ), + ), + ], ), const SizedBox(height: 20.0), Divider( @@ -228,7 +249,7 @@ class _CharacterCustomizationPageState extends State decoration: const InputDecoration( labelText: "Name", ), - controller: _nameController, + controller: nameController, onChanged: (value) { character.name = value; }, @@ -240,7 +261,7 @@ class _CharacterCustomizationPageState extends State TextFieldListTile( headingText: 'Description', labelText: 'Description', - controller: _descriptionController, + controller: descriptionController, onChanged: (value) { character.description = value; }, @@ -249,7 +270,7 @@ class _CharacterCustomizationPageState extends State TextFieldListTile( headingText: 'Personality', labelText: 'Personality', - controller: _personalityController, + controller: personalityController, onChanged: (value) { character.personality = value; }, @@ -258,7 +279,7 @@ class _CharacterCustomizationPageState extends State TextFieldListTile( headingText: 'Scenario', labelText: 'Scenario', - controller: _scenarioController, + controller: scenarioController, onChanged: (value) { character.scenario = value; }, @@ -267,7 +288,7 @@ class _CharacterCustomizationPageState extends State TextFieldListTile( headingText: 'System Prompt', labelText: 'System Prompt', - controller: _systemController, + controller: systemController, onChanged: (value) { character.system = value; }, @@ -312,7 +333,7 @@ class _CharacterCustomizationPageState extends State TextFieldListTile( headingText: 'Greeting $i', labelText: 'Greeting $i', - controller: _greetingControllers[i], + controller: greetingControllers[i], onChanged: (value) { character.updateGreeting(i, value); }, @@ -337,7 +358,7 @@ class _CharacterCustomizationPageState extends State children: [ FilledButton( onPressed: () { - _regenerate = true; + regenerate = true; character.newExample(true); }, child: Text( @@ -348,7 +369,7 @@ class _CharacterCustomizationPageState extends State const SizedBox(width: 10.0), FilledButton( onPressed: () { - _regenerate = true; + regenerate = true; character.newExample(false); }, child: Text( @@ -364,7 +385,7 @@ class _CharacterCustomizationPageState extends State children: [ FilledButton( onPressed: () { - _regenerate = true; + regenerate = true; character.newExample(null); }, child: Text( @@ -375,8 +396,8 @@ class _CharacterCustomizationPageState extends State const SizedBox(width: 10.0), FilledButton( onPressed: () { - if (_exampleControllers.length >= 2) { - _regenerate = true; + if (exampleControllers.length >= 2) { + regenerate = true; character.removeLastExample(); } }, @@ -393,7 +414,7 @@ class _CharacterCustomizationPageState extends State headingText: '${character.examples[i]["role"]} content', labelText: character.examples[i]["role"], - controller: _exampleControllers[i], + controller: exampleControllers[i], onChanged: (value) { character.updateExample(i, value); }, diff --git a/lib/ui/mobile/widgets/appbars/home_app_bar.dart b/lib/ui/mobile/widgets/appbars/home_app_bar.dart index 886c777c..ebf5e197 100644 --- a/lib/ui/mobile/widgets/appbars/home_app_bar.dart +++ b/lib/ui/mobile/widgets/appbars/home_app_bar.dart @@ -50,8 +50,11 @@ class _HomeAppBarState extends State { final RenderBox renderBox = iconButtonKey.currentContext!.findRenderObject() as RenderBox; final Offset offset = renderBox.localToGlobal(Offset.zero); final Size size = renderBox.size; + final Session session = context.read(); - List options = context.read().model.options; + session.model.updateOptions(); + + List options = session.model.options; List> modelOptions = options.map((String modelName) => PopupMenuItem( padding: EdgeInsets.zero,