From e6007fc766c7513dd67887075925c6b64d24006b Mon Sep 17 00:00:00 2001 From: danemadsen Date: Fri, 9 Aug 2024 13:35:14 +1000 Subject: [PATCH] refactor --- lib/classes/providers/app_data.dart | 178 ------------------ .../providers/artificial_intelligence.dart | 5 + lib/classes/providers/character.dart | 4 +- lib/classes/providers/characters.dart | 105 +++++++++++ lib/classes/providers/session.dart | 4 +- lib/classes/providers/sessions.dart | 113 +++++++++++ lib/main.dart | 18 +- .../desktop/buttons/new_character_button.dart | 4 +- .../settings_panels/app_settings_panel.dart | 10 +- lib/ui/desktop/settings_panels/log_panel.dart | 9 +- lib/ui/mobile/layout/home_drawer.dart | 8 +- .../mobile/pages/character_browser_page.dart | 4 +- lib/ui/mobile/pages/settings_page.dart | 8 +- .../shared/buttons/clear_sessions_button.dart | 4 +- lib/ui/shared/buttons/new_session_button.dart | 4 +- lib/ui/shared/chat_widgets/chat_body.dart | 24 ++- lib/ui/shared/chat_widgets/chat_field.dart | 14 +- lib/ui/shared/chat_widgets/chat_message.dart | 40 ++-- .../dialogs/storage_operation_dialog.dart | 2 - .../pages/character_customization_page.dart | 52 ++--- lib/ui/shared/tiles/character_tile.dart | 6 +- lib/ui/shared/tiles/session_tile.dart | 19 +- .../utilities/session_busy_overlay.dart | 4 +- lib/ui/shared/views/characters_grid_view.dart | 14 +- lib/ui/shared/views/sessions_list_view.dart | 12 +- 25 files changed, 355 insertions(+), 310 deletions(-) delete mode 100644 lib/classes/providers/app_data.dart create mode 100644 lib/classes/providers/characters.dart create mode 100644 lib/classes/providers/sessions.dart diff --git a/lib/classes/providers/app_data.dart b/lib/classes/providers/app_data.dart deleted file mode 100644 index 71a19d98..00000000 --- a/lib/classes/providers/app_data.dart +++ /dev/null @@ -1,178 +0,0 @@ -import 'dart:convert'; - -import 'package:flutter/material.dart'; -import 'package:maid/classes/providers/character.dart'; -import 'package:maid/classes/providers/session.dart'; -import 'package:provider/provider.dart'; -import 'package:shared_preferences/shared_preferences.dart'; - -class AppData extends ChangeNotifier { - static AppData of(BuildContext context) => Provider.of(context, listen: false); - - AppData(this._sessions, this._characters, this._currentSession, this._currentCharacter) { - _currentSession.addListener(notify); - _currentCharacter.addListener(notify); - } - - final List _sessions; - final List _characters; - Session _currentSession; - Character _currentCharacter; - - List get sessions { - _sessions.removeWhere((element) => element == _currentSession); - - return List.from([_currentSession, ..._sessions]); - } - - List get characters { - _characters.removeWhere((element) => element.key == _currentCharacter.key); - - return List.from([_currentCharacter, ..._characters]); - } - - Session get currentSession => _currentSession; - - Character get currentCharacter => _currentCharacter; - - set currentSession(Session session) { - if (!currentSession.chat.tail.finalised) return; - - _sessions.insert(0, _currentSession); - - _currentSession = session; - - _currentSession.addListener(notify); - - save().then((value) => notifyListeners()); - } - - set currentCharacter(Character character) { - _characters.insert(0, _currentCharacter); - - _currentCharacter = character; - - _currentCharacter.addListener(notify); - - save().then((value) => notifyListeners()); - } - - static Future get last async { - final prefs = await SharedPreferences.getInstance(); - - String? sessionsString = prefs.getString("sessions"); - String? charactersString = prefs.getString("characters"); - - List sessions = []; - List characters = []; - - if (sessionsString != null) { - sessions = (json.decode(sessionsString) as List).map((e) => Session.fromMap(null, e)).toList(); - } - - if (charactersString != null) { - characters = (json.decode(charactersString) as List).map((e) => Character.fromMap(null, e)).toList(); - } - - final session = await Session.last; - final character = await Character.last; - - return AppData( - sessions, - characters, - session, - character - ); - } - - Future save() async { - final prefs = await SharedPreferences.getInstance(); - - _sessions.removeWhere((element) => element.key == _currentSession.key); - final sessionsMaps = _sessions.map((e) => e.toMap()).toList(); - - _characters.removeWhere((element) => element.key == _currentCharacter.key); - final characterMaps = _characters.map((e) => e.toMap()).toList(); - - final futures = [ - prefs.setString("sessions", json.encode(sessionsMaps)), - prefs.setString("characters", json.encode(characterMaps)), - _currentSession.save(), - _currentCharacter.save(), - ]; - - await Future.wait(futures); - } - - void newSession() { - int index = 0; - - for (int i = 1; i <= sessions.length; i++) { - if (!sessions.any((element) => element.name == "New Chat $i")) { - index = i; - break; - } - } - - currentSession = Session(notify, index); - } - - void newCharacter() { - currentCharacter = Character(notify); - } - - void addCharacter(Character character) { - final index = _characters.indexWhere((element) => element.key == character.key); - - if (index.isNegative) { - _characters.insert(0, character); - notifyListeners(); - } - } - - void removeSession(Session session) { - if (session == _currentSession) { - _currentSession = _sessions.firstOrNull ?? Session(notify, 0); - notifyListeners(); - return; - } - - final index = _sessions.indexWhere((element) => element.key == session.key); - - if (!index.isNegative) { - _sessions.removeAt(index); - notifyListeners(); - } - } - - void removeCharacter(Character character) { - final index = _characters.indexWhere((element) => element.key == character.key); - - if (!index.isNegative) { - _characters.removeAt(index); - notifyListeners(); - } - } - - void clearSessions() { - _sessions.clear(); - notifyListeners(); - } - - void clearCharacters() { - _characters.clear(); - notifyListeners(); - } - - void reset() { - clearSessions(); - clearCharacters(); - _currentCharacter = Character(notify); - _currentSession = Session(notify, 0); - notifyListeners(); - } - - void notify() { - save().then((value) => notifyListeners()); - } -} diff --git a/lib/classes/providers/artificial_intelligence.dart b/lib/classes/providers/artificial_intelligence.dart index 08712442..10db75a3 100644 --- a/lib/classes/providers/artificial_intelligence.dart +++ b/lib/classes/providers/artificial_intelligence.dart @@ -44,6 +44,11 @@ class ArtificialIntelligence extends ChangeNotifier { await Future.wait(futures); } + void reset() { + llm.reset(); + notify(); + } + void notify() { save().then((_) => notifyListeners()); } diff --git a/lib/classes/providers/character.dart b/lib/classes/providers/character.dart index 4f2f66c3..87db22b9 100644 --- a/lib/classes/providers/character.dart +++ b/lib/classes/providers/character.dart @@ -6,7 +6,7 @@ import 'package:crypto/crypto.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/services.dart'; import 'package:flutter/material.dart'; -import 'package:maid/classes/providers/app_data.dart'; +import 'package:maid/classes/providers/characters.dart'; import 'package:maid/classes/static/logger.dart'; import 'package:image/image.dart'; import 'package:maid/classes/static/utilities.dart'; @@ -32,7 +32,7 @@ class Character extends ChangeNotifier { Map _cachedJson = {}; - static Character of(BuildContext context) => AppData.of(context).currentCharacter; + static Character of(BuildContext context) => CharacterCollection.of(context).current; Character(VoidCallback? listener) : _key = UniqueKey() { if (listener != null) { diff --git a/lib/classes/providers/characters.dart b/lib/classes/providers/characters.dart new file mode 100644 index 00000000..d6d2ef3a --- /dev/null +++ b/lib/classes/providers/characters.dart @@ -0,0 +1,105 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:maid/classes/providers/character.dart'; +import 'package:provider/provider.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +class CharacterCollection extends ChangeNotifier { + static CharacterCollection of(BuildContext context) => Provider.of(context, listen: false); + + CharacterCollection(this._characters, this._current) { + _current.addListener(notify); + } + + final List _characters; + Character _current; + + List get list { + _characters.removeWhere((element) => element.key == _current.key); + + return List.from([_current, ..._characters]); + } + + Character get current => _current; + + set current(Character character) { + _characters.insert(0, _current); + + _current = character; + + _current.addListener(notify); + + save().then((value) => notifyListeners()); + } + + static Future get last async { + final prefs = await SharedPreferences.getInstance(); + + String? charactersString = prefs.getString("characters"); + + List characters = []; + + if (charactersString != null) { + characters = (json.decode(charactersString) as List).map((e) => Character.fromMap(null, e)).toList(); + } + + final character = await Character.last; + + return CharacterCollection( + characters, + character + ); + } + + Future save() async { + final prefs = await SharedPreferences.getInstance(); + + _characters.removeWhere((element) => element.key == _current.key); + final characterMaps = _characters.map((e) => e.toMap()).toList(); + + final futures = [ + prefs.setString("characters", json.encode(characterMaps)), + _current.save(), + ]; + + await Future.wait(futures); + } + + void newCharacter() { + current = Character(notify); + } + + void addCharacter(Character character) { + final index = _characters.indexWhere((element) => element.key == character.key); + + if (index.isNegative) { + _characters.insert(0, character); + notifyListeners(); + } + } + + void removeCharacter(Character character) { + final index = _characters.indexWhere((element) => element.key == character.key); + + if (!index.isNegative) { + _characters.removeAt(index); + notifyListeners(); + } + } + + void clearCharacters() { + _characters.clear(); + notifyListeners(); + } + + void reset() { + clearCharacters(); + _current = Character(notify); + notifyListeners(); + } + + void notify() { + save().then((value) => notifyListeners()); + } +} diff --git a/lib/classes/providers/session.dart b/lib/classes/providers/session.dart index e747aca0..aed6ecf8 100644 --- a/lib/classes/providers/session.dart +++ b/lib/classes/providers/session.dart @@ -6,8 +6,8 @@ import 'package:flutter/material.dart'; import 'package:maid/classes/chat_node_tree.dart'; import 'package:maid/classes/providers/app_preferences.dart'; import 'package:maid/classes/providers/large_language_model.dart'; +import 'package:maid/classes/providers/sessions.dart'; import 'package:maid/enumerators/chat_role.dart'; -import 'package:maid/classes/providers/app_data.dart'; import 'package:maid/classes/providers/character.dart'; import 'package:maid/classes/providers/user.dart'; import 'package:maid/classes/static/logger.dart'; @@ -39,7 +39,7 @@ class Session extends ChangeNotifier { notifyListeners(); } - static Session of(BuildContext context) => AppData.of(context).currentSession; + static Session of(BuildContext context) => Sessions.of(context).current; Session(VoidCallback? listener, int index) { if (listener != null) { diff --git a/lib/classes/providers/sessions.dart b/lib/classes/providers/sessions.dart new file mode 100644 index 00000000..47052964 --- /dev/null +++ b/lib/classes/providers/sessions.dart @@ -0,0 +1,113 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:maid/classes/providers/session.dart'; +import 'package:provider/provider.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +class Sessions extends ChangeNotifier { + static Sessions of(BuildContext context) => Provider.of(context, listen: false); + + Sessions(this._sessions, this._current) { + _current.addListener(notify); + } + + final List _sessions; + Session _current; + + List get list { + _sessions.removeWhere((element) => element == _current); + + return List.from([_current, ..._sessions]); + } + + Session get current => _current; + + set current(Session session) { + if (!current.chat.tail.finalised) return; + + _sessions.insert(0, _current); + + _current = session; + + _current.addListener(notify); + + save().then((value) => notifyListeners()); + } + + static Future get last async { + final prefs = await SharedPreferences.getInstance(); + + String? sessionsString = prefs.getString("sessions"); + + List sessions = []; + + if (sessionsString != null) { + sessions = (json.decode(sessionsString) as List).map((e) => Session.fromMap(null, e)).toList(); + } + + final session = await Session.last; + + return Sessions( + sessions, + session + ); + } + + Future save() async { + final prefs = await SharedPreferences.getInstance(); + + _sessions.removeWhere((element) => element.key == _current.key); + final sessionsMaps = _sessions.map((e) => e.toMap()).toList(); + + final futures = [ + prefs.setString("sessions", json.encode(sessionsMaps)), + _current.save(), + ]; + + await Future.wait(futures); + } + + void newSession() { + int index = 0; + + for (int i = 1; i <= list.length; i++) { + if (!list.any((element) => element.name == "New Chat $i")) { + index = i; + break; + } + } + + current = Session(notify, index); + } + + void removeSession(Session session) { + if (session == _current) { + _current = _sessions.firstOrNull ?? Session(notify, 0); + notifyListeners(); + return; + } + + final index = _sessions.indexWhere((element) => element.key == session.key); + + if (!index.isNegative) { + _sessions.removeAt(index); + notifyListeners(); + } + } + + void clearSessions() { + _sessions.clear(); + notifyListeners(); + } + + void reset() { + clearSessions(); + _current = Session(notify, 0); + notifyListeners(); + } + + void notify() { + save().then((value) => notifyListeners()); + } +} diff --git a/lib/main.dart b/lib/main.dart index 2e3c3079..e9cd9162 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,9 +1,10 @@ import 'package:babylon_tts/babylon_tts.dart'; import 'package:flutter/material.dart'; -import 'package:maid/classes/providers/app_data.dart'; import 'package:maid/classes/providers/app_preferences.dart'; import 'package:maid/classes/providers/artificial_intelligence.dart'; +import 'package:maid/classes/providers/characters.dart'; import 'package:maid/classes/providers/huggingface_selection.dart'; +import 'package:maid/classes/providers/sessions.dart'; import 'package:maid/classes/providers/user.dart'; import 'package:maid/ui/desktop/app.dart'; import 'package:maid/ui/mobile/app.dart'; @@ -15,14 +16,16 @@ void main() async { await Babylon.init(); AppPreferences appPreferences = await AppPreferences.last; - AppData appData = await AppData.last; + Sessions sessions = await Sessions.last; + CharacterCollection characters = await CharacterCollection.last; ArtificialIntelligence ai = await ArtificialIntelligence.last; User user = await User.last; runApp( MaidApp( appPreferences: appPreferences, - appData: appData, + sessions: sessions, + characters: characters, ai: ai, user: user ) @@ -31,14 +34,16 @@ void main() async { class MaidApp extends StatelessWidget { final AppPreferences appPreferences; - final AppData appData; + final Sessions sessions; + final CharacterCollection characters; final ArtificialIntelligence ai; final User user; const MaidApp({ super.key, required this.appPreferences, - required this.appData, + required this.sessions, + required this.characters, required this.ai, required this.user, }); @@ -48,7 +53,8 @@ class MaidApp extends StatelessWidget { return MultiProvider( providers: [ ChangeNotifierProvider(create: (context) => appPreferences), - ChangeNotifierProvider(create: (context) => appData), + ChangeNotifierProvider(create: (context) => sessions), + ChangeNotifierProvider(create: (context) => characters), ChangeNotifierProvider(create: (context) => ai), ChangeNotifierProvider(create: (context) => user), ChangeNotifierProvider(create: (context) => HuggingfaceSelection()) diff --git a/lib/ui/desktop/buttons/new_character_button.dart b/lib/ui/desktop/buttons/new_character_button.dart index 93d7eb03..cc3676ba 100644 --- a/lib/ui/desktop/buttons/new_character_button.dart +++ b/lib/ui/desktop/buttons/new_character_button.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:maid/classes/providers/app_data.dart'; +import 'package:maid/classes/providers/characters.dart'; class NewCharacterButton extends StatelessWidget { const NewCharacterButton({super.key}); @@ -8,7 +8,7 @@ class NewCharacterButton extends StatelessWidget { Widget build(BuildContext context) { return FilledButton( onPressed: () { - AppData.of(context).newCharacter(); + CharacterCollection.of(context).newCharacter(); }, child: const Text( "New Character" diff --git a/lib/ui/desktop/settings_panels/app_settings_panel.dart b/lib/ui/desktop/settings_panels/app_settings_panel.dart index 40665fdc..98747d90 100644 --- a/lib/ui/desktop/settings_panels/app_settings_panel.dart +++ b/lib/ui/desktop/settings_panels/app_settings_panel.dart @@ -1,6 +1,9 @@ import 'package:flutter/material.dart'; -import 'package:maid/classes/providers/app_data.dart'; import 'package:maid/classes/providers/app_preferences.dart'; +import 'package:maid/classes/providers/artificial_intelligence.dart'; +import 'package:maid/classes/providers/characters.dart'; +import 'package:maid/classes/providers/sessions.dart'; +import 'package:maid/classes/providers/user.dart'; import 'package:maid/classes/static/logger.dart'; import 'package:maid/ui/shared/dropdowns/app_layout_dropdown.dart'; import 'package:maid/ui/shared/dropdowns/theme_mode_dropdown.dart'; @@ -60,7 +63,10 @@ class AppSettingsPanel extends StatelessWidget { SharedPreferences.getInstance().then((prefs) { prefs.clear(); AppPreferences.of(context).reset(); - AppData.of(context).reset(); + CharacterCollection.of(context).reset(); + Sessions.of(context).reset(); + ArtificialIntelligence.of(context).reset(); + User.of(context).reset(); Logger.clear(); }); }, diff --git a/lib/ui/desktop/settings_panels/log_panel.dart b/lib/ui/desktop/settings_panels/log_panel.dart index f071f1dc..5c3449f7 100644 --- a/lib/ui/desktop/settings_panels/log_panel.dart +++ b/lib/ui/desktop/settings_panels/log_panel.dart @@ -1,6 +1,9 @@ import 'package:flutter/material.dart'; -import 'package:maid/classes/providers/app_data.dart'; import 'package:maid/classes/providers/app_preferences.dart'; +import 'package:maid/classes/providers/artificial_intelligence.dart'; +import 'package:maid/classes/providers/characters.dart'; +import 'package:maid/classes/providers/sessions.dart'; +import 'package:maid/classes/providers/user.dart'; import 'package:maid/classes/static/logger.dart'; import 'package:provider/provider.dart'; @@ -11,13 +14,13 @@ class LogPanel extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.black, - body: Consumer2( + body: Consumer5( builder: buildLog, ), ); } - Widget buildLog(BuildContext context, AppData appData, AppPreferences appPreferences, Widget? child) { + Widget buildLog(BuildContext context, ArtificialIntelligence ai, CharacterCollection characters, Sessions sessions, User user, AppPreferences appPreferences, Widget? child) { return Container( padding: const EdgeInsets.all(8.0), color: Colors.black, diff --git a/lib/ui/mobile/layout/home_drawer.dart b/lib/ui/mobile/layout/home_drawer.dart index 99f9a75a..d841a70b 100644 --- a/lib/ui/mobile/layout/home_drawer.dart +++ b/lib/ui/mobile/layout/home_drawer.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:maid/classes/providers/app_data.dart'; +import 'package:maid/classes/providers/characters.dart'; import 'package:maid/ui/shared/tiles/character_tile.dart'; import 'package:maid/ui/shared/buttons/clear_sessions_button.dart'; import 'package:maid/ui/shared/views/sessions_list_view.dart'; @@ -17,13 +17,13 @@ class HomeDrawer extends StatelessWidget { onTap: () { Navigator.pop(context); }, - child: Consumer( + child: Consumer( builder: drawerBuilder ) ); } - Widget drawerBuilder(BuildContext context, AppData appData, Widget? child) { + Widget drawerBuilder(BuildContext context, CharacterCollection characters, Widget? child) { return Drawer( semanticLabel: "Drawer Menu", backgroundColor: Theme.of(context).colorScheme.surface, @@ -39,7 +39,7 @@ class HomeDrawer extends StatelessWidget { children: [ Expanded( child: CharacterTile( - character: appData.currentCharacter, + character: characters.current, ) ), const SizedBox(height: 5.0), diff --git a/lib/ui/mobile/pages/character_browser_page.dart b/lib/ui/mobile/pages/character_browser_page.dart index b1db25f1..175f6845 100644 --- a/lib/ui/mobile/pages/character_browser_page.dart +++ b/lib/ui/mobile/pages/character_browser_page.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:maid/classes/providers/app_data.dart'; +import 'package:maid/classes/providers/characters.dart'; import 'package:maid/ui/shared/utilities/session_busy_overlay.dart'; import 'package:maid/ui/shared/views/characters_grid_view.dart'; @@ -24,7 +24,7 @@ class CharacterBrowserPage extends StatelessWidget { IconButton( icon: const Icon(Icons.add), onPressed: () { - AppData.of(context).newCharacter(); + CharacterCollection.of(context).newCharacter(); }, ), ], diff --git a/lib/ui/mobile/pages/settings_page.dart b/lib/ui/mobile/pages/settings_page.dart index 7ff41415..701ebfab 100644 --- a/lib/ui/mobile/pages/settings_page.dart +++ b/lib/ui/mobile/pages/settings_page.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; -import 'package:maid/classes/providers/app_data.dart'; import 'package:maid/classes/providers/app_preferences.dart'; +import 'package:maid/classes/providers/artificial_intelligence.dart'; +import 'package:maid/classes/providers/characters.dart'; +import 'package:maid/classes/providers/sessions.dart'; import 'package:maid/classes/providers/user.dart'; import 'package:maid/classes/static/logger.dart'; import 'package:maid/ui/shared/layout/generic_app_bar.dart'; @@ -77,7 +79,9 @@ class _SettingsPageState extends State { prefs.clear(); AppPreferences.of(context).reset(); User.of(context).reset(); - AppData.of(context).reset(); + Sessions.of(context).reset(); + CharacterCollection.of(context).reset(); + ArtificialIntelligence.of(context).reset(); setState(() { Logger.clear(); }); diff --git a/lib/ui/shared/buttons/clear_sessions_button.dart b/lib/ui/shared/buttons/clear_sessions_button.dart index 72454432..94d10f6b 100644 --- a/lib/ui/shared/buttons/clear_sessions_button.dart +++ b/lib/ui/shared/buttons/clear_sessions_button.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:maid/classes/providers/app_data.dart'; +import 'package:maid/classes/providers/sessions.dart'; /// A button widget that clears all [Session]s. /// @@ -10,7 +10,7 @@ class ClearSessionsButton extends StatelessWidget { @override Widget build(BuildContext context) { return FilledButton( - onPressed: AppData.of(context).clearSessions, + onPressed: Sessions.of(context).clearSessions, child: const Text( "Clear Chats" ), diff --git a/lib/ui/shared/buttons/new_session_button.dart b/lib/ui/shared/buttons/new_session_button.dart index 7c0dcaaf..89c23ce0 100644 --- a/lib/ui/shared/buttons/new_session_button.dart +++ b/lib/ui/shared/buttons/new_session_button.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:maid/classes/providers/app_data.dart'; +import 'package:maid/classes/providers/sessions.dart'; /// A button widget that creates a new [Session]. /// @@ -12,7 +12,7 @@ class NewSessionButton extends StatelessWidget { Widget build(BuildContext context) { return IconButton( tooltip: "New Session", - onPressed: AppData.of(context).newSession, + onPressed: Sessions.of(context).newSession, icon: const Icon( Icons.border_color_rounded, size: 24, diff --git a/lib/ui/shared/chat_widgets/chat_body.dart b/lib/ui/shared/chat_widgets/chat_body.dart index 541ca5b1..fac45576 100644 --- a/lib/ui/shared/chat_widgets/chat_body.dart +++ b/lib/ui/shared/chat_widgets/chat_body.dart @@ -2,9 +2,10 @@ import 'dart:math'; import 'package:flutter/material.dart'; import 'package:maid/classes/chat_node.dart'; +import 'package:maid/classes/providers/characters.dart'; +import 'package:maid/classes/providers/sessions.dart'; import 'package:maid/classes/providers/user.dart'; import 'package:maid/enumerators/chat_role.dart'; -import 'package:maid/classes/providers/app_data.dart'; import 'package:maid/classes/static/utilities.dart'; import 'package:maid/ui/shared/chat_widgets/chat_field.dart'; import 'package:maid/ui/shared/chat_widgets/chat_message.dart'; @@ -36,28 +37,25 @@ class ChatBody extends StatelessWidget { } Widget _buildChat() { - return Consumer2( - builder: (context, appData, user, child) { - final session = appData.currentSession; - final character = appData.currentCharacter; - - List chat = session.chat.getChat(); + return Consumer3( + builder: (context, sessions, characters, user, child) { + List chat = sessions.current.chat.getChat(); if ( chat.isEmpty && - character.useGreeting && - character.greetings.isNotEmpty + characters.current.useGreeting && + characters.current.greetings.isNotEmpty ) { - final index = Random().nextInt(character.greetings.length); + final index = Random().nextInt(characters.current.greetings.length); - if (character.greetings[index].isNotEmpty) { + if (characters.current.greetings[index].isNotEmpty) { final message = ChatNode( role: ChatRole.assistant, - content: Utilities.formatPlaceholders(character.greetings[index], user.name, character.name), + content: Utilities.formatPlaceholders(characters.current.greetings[index], user.name, characters.current.name), finalised: true ); - session.chat.addNode(message); + sessions.current.chat.addNode(message); chat = [message]; } } diff --git a/lib/ui/shared/chat_widgets/chat_field.dart b/lib/ui/shared/chat_widgets/chat_field.dart index 16e92d35..9dbb2dee 100644 --- a/lib/ui/shared/chat_widgets/chat_field.dart +++ b/lib/ui/shared/chat_widgets/chat_field.dart @@ -4,9 +4,9 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:maid/classes/providers/artificial_intelligence.dart'; import 'package:maid/classes/providers/large_language_models/llama_cpp_model.dart'; +import 'package:maid/classes/providers/sessions.dart'; import 'package:maid/enumerators/chat_role.dart'; import 'package:maid/enumerators/large_language_model_type.dart'; -import 'package:maid/classes/providers/app_data.dart'; import 'package:maid/classes/providers/session.dart'; import 'package:maid/ui/shared/dialogs/missing_requirements_dialog.dart'; import 'package:maid/classes/static/logger.dart'; @@ -90,13 +90,11 @@ class _ChatFieldState extends State { } Widget _buildRow() { - return Consumer2( - builder: (context, appData, ai, child) { - final session = appData.currentSession; - + return Consumer2( + builder: (context, sessions, ai, child) { return Row( children: [ - if (!session.chat.tail.finalised && + if (!sessions.current.chat.tail.finalised && ai.llm.type == LargeLanguageModelType.llamacpp) Semantics( label: 'Stop button', @@ -144,14 +142,14 @@ class _ChatFieldState extends State { } ); } - else if (session.chat.tail.finalised) { + else if (sessions.current.chat.tail.finalised) { send(); } }, iconSize: 50, icon: Icon( Icons.arrow_circle_right, - color: !session.chat.tail.finalised + color: !sessions.current.chat.tail.finalised ? Theme.of(context).colorScheme.onPrimary : Theme.of(context).colorScheme.secondary, ) diff --git a/lib/ui/shared/chat_widgets/chat_message.dart b/lib/ui/shared/chat_widgets/chat_message.dart index d8a4e659..b1937014 100644 --- a/lib/ui/shared/chat_widgets/chat_message.dart +++ b/lib/ui/shared/chat_widgets/chat_message.dart @@ -2,10 +2,11 @@ import 'dart:math'; import 'package:flutter/material.dart'; import 'package:babylon_tts/babylon_tts.dart'; +import 'package:maid/classes/providers/characters.dart'; import 'package:maid/classes/providers/large_language_model.dart'; +import 'package:maid/classes/providers/sessions.dart'; import 'package:maid/classes/providers/user.dart'; import 'package:maid/enumerators/chat_role.dart'; -import 'package:maid/classes/providers/app_data.dart'; import 'package:maid/classes/providers/session.dart'; import 'package:maid/ui/shared/dialogs/missing_requirements_dialog.dart'; import 'package:maid/ui/shared/shaders/blade_runner_gradient_shader.dart'; @@ -33,12 +34,9 @@ class _ChatMessageWidgetState extends State with SingleTicker @override Widget build(BuildContext context) { - return Consumer2( - builder: (context, appData, user, child) { - final session = appData.currentSession; - final character = appData.currentCharacter; - - node = session.chat.find(widget.hash)!; + return Consumer3( + builder: (context, sessions, characters, user, child) { + node = sessions.current.chat.find(widget.hash)!; return Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -48,15 +46,15 @@ class _ChatMessageWidgetState extends State with SingleTicker children: [ const SizedBox(width: 10.0), FutureAvatar( - key: node.role == ChatRole.user ? user.key : character.key, - image: node.role == ChatRole.user ? user.profile : character.profile, + key: node.role == ChatRole.user ? user.key : characters.current.key, + image: node.role == ChatRole.user ? user.profile : characters.current.profile, radius: 16, ), const SizedBox(width: 10.0), BladeRunnerGradientShader( stops: const [0.5, 0.85], child: Text( - node.role == ChatRole.user ? user.name : character.name, + node.role == ChatRole.user ? user.name : characters.current.name, style: const TextStyle( fontWeight: FontWeight.normal, color: Colors.white, @@ -169,12 +167,10 @@ class _ChatMessageWidgetState extends State with SingleTicker } Widget branchSwitcher() { - return Consumer( - builder: (BuildContext context, AppData appData, Widget? child) { - final session = appData.currentSession; - - int currentIndex = session.chat.indexOf(widget.hash); - int siblingCount = session.chat.siblingCountOf(widget.hash); + return Consumer( + builder: (BuildContext context, Sessions sessions, Widget? child) { + int currentIndex = sessions.current.chat.indexOf(widget.hash); + int siblingCount = sessions.current.chat.siblingCountOf(widget.hash); return Row( mainAxisSize: MainAxisSize.max, @@ -184,9 +180,9 @@ class _ChatMessageWidgetState extends State with SingleTicker tooltip: 'Previous chat branch', padding: const EdgeInsets.all(0), onPressed: () { - if (!session.chat.tail.finalised) return; - session.chat.last(widget.hash); - session.notify(); + if (!sessions.current.chat.tail.finalised) return; + sessions.current.chat.last(widget.hash); + sessions.current.notify(); }, icon: Icon( Icons.arrow_left, @@ -202,9 +198,9 @@ class _ChatMessageWidgetState extends State with SingleTicker tooltip: 'Next chat branch', padding: const EdgeInsets.all(0), onPressed: () { - if (!session.chat.tail.finalised) return; - session.chat.next(widget.hash); - session.notify(); + if (!sessions.current.chat.tail.finalised) return; + sessions.current.chat.next(widget.hash); + sessions.current.notify(); }, icon: Icon( Icons.arrow_right, diff --git a/lib/ui/shared/dialogs/storage_operation_dialog.dart b/lib/ui/shared/dialogs/storage_operation_dialog.dart index 6c0ee670..8afc1f65 100644 --- a/lib/ui/shared/dialogs/storage_operation_dialog.dart +++ b/lib/ui/shared/dialogs/storage_operation_dialog.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:maid/classes/providers/app_data.dart'; import 'package:maid/ui/shared/dialogs/loading_dialog.dart'; class StorageOperationDialog extends StatelessWidget { @@ -27,7 +26,6 @@ class StorageOperationDialog extends StatelessWidget { actions: [ FilledButton( onPressed: () { - AppData.of(context).notify(); Navigator.of(context).pop(); }, child: Text( diff --git a/lib/ui/shared/pages/character_customization_page.dart b/lib/ui/shared/pages/character_customization_page.dart index 4be989a2..5c027482 100644 --- a/lib/ui/shared/pages/character_customization_page.dart +++ b/lib/ui/shared/pages/character_customization_page.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; -import 'package:maid/classes/providers/app_data.dart'; import 'package:maid/classes/providers/app_preferences.dart'; import 'package:maid/classes/providers/character.dart'; +import 'package:maid/classes/providers/characters.dart'; import 'package:maid/classes/providers/desktop_navigator.dart'; import 'package:maid/classes/static/utilities.dart'; import 'package:maid/ui/shared/dialogs/storage_operation_dialog.dart'; @@ -66,29 +66,29 @@ class _CharacterCustomizationPageState extends State "Character Customization" ), ), - body: Consumer( + body: Consumer( builder: buildBody, ) ); } - Widget buildBody(BuildContext context, AppData appData, Widget? child) { + Widget buildBody(BuildContext context, CharacterCollection characters, Widget? child) { if (regenerate) { - nameController = TextEditingController(text: appData.currentCharacter.name); - descriptionController = TextEditingController(text: appData.currentCharacter.description); - personalityController = TextEditingController(text: appData.currentCharacter.personality); - scenarioController = TextEditingController(text: appData.currentCharacter.scenario); - systemController = TextEditingController(text: appData.currentCharacter.system); + nameController = TextEditingController(text: characters.current.name); + descriptionController = TextEditingController(text: characters.current.description); + personalityController = TextEditingController(text: characters.current.personality); + scenarioController = TextEditingController(text: characters.current.scenario); + systemController = TextEditingController(text: characters.current.system); greetingControllers = List.generate( - appData.currentCharacter.greetings.length, - (index) => TextEditingController(text: appData.currentCharacter.greetings[index]), + characters.current.greetings.length, + (index) => TextEditingController(text: characters.current.greetings[index]), ); exampleControllers = List.generate( - appData.currentCharacter.examples.length, + characters.current.examples.length, (index) => - TextEditingController(text: appData.currentCharacter.examples[index]["content"]), + TextEditingController(text: characters.current.examples[index]["content"]), ); regenerate = false; @@ -99,19 +99,19 @@ class _CharacterCustomizationPageState extends State Padding( padding: const EdgeInsets.all(20.0), child: FutureTileImage( - key: appData.currentCharacter.imageKey, - image: appData.currentCharacter.profile, + key: characters.current.imageKey, + image: characters.current.profile, borderRadius: BorderRadius.circular(10.0), ) ), const SizedBox(height: 20.0), Text( - appData.currentCharacter.name, + characters.current.name, textAlign: TextAlign.center, style: Theme.of(context).textTheme.titleLarge, ), const SizedBox(height: 20.0), - buttonGridView(appData.currentCharacter), + buttonGridView(characters.current), const SizedBox(height: 20.0), Divider( indent: 10, @@ -123,7 +123,7 @@ class _CharacterCustomizationPageState extends State labelText: 'Name', controller: nameController, onChanged: (value) { - appData.currentCharacter.name = value; + characters.current.name = value; }, multiline: false, ), @@ -134,12 +134,12 @@ class _CharacterCustomizationPageState extends State ), SwitchListTile( title: const Text('Use System'), - value: appData.currentCharacter.useSystem, + value: characters.current.useSystem, onChanged: (value) { - appData.currentCharacter.useSystem = value; + characters.current.useSystem = value; }, ), - if (appData.currentCharacter.useSystem) ...system(appData.currentCharacter), + if (characters.current.useSystem) ...system(characters.current), Divider( indent: 10, endIndent: 10, @@ -147,12 +147,12 @@ class _CharacterCustomizationPageState extends State ), SwitchListTile( title: const Text('Use Greeting'), - value: appData.currentCharacter.useGreeting, + value: characters.current.useGreeting, onChanged: (value) { - appData.currentCharacter.useGreeting = value; + characters.current.useGreeting = value; }, ), - if (appData.currentCharacter.useGreeting) ...greetings(appData.currentCharacter), + if (characters.current.useGreeting) ...greetings(characters.current), Divider( indent: 10, endIndent: 10, @@ -160,12 +160,12 @@ class _CharacterCustomizationPageState extends State ), SwitchListTile( title: const Text('Use Examples'), - value: appData.currentCharacter.useExamples, + value: characters.current.useExamples, onChanged: (value) { - appData.currentCharacter.useExamples = value; + characters.current.useExamples = value; }, ), - if (appData.currentCharacter.useExamples) ...examples(appData.currentCharacter), + if (characters.current.useExamples) ...examples(characters.current), ]); } diff --git a/lib/ui/shared/tiles/character_tile.dart b/lib/ui/shared/tiles/character_tile.dart index b8adc2e4..60535d49 100644 --- a/lib/ui/shared/tiles/character_tile.dart +++ b/lib/ui/shared/tiles/character_tile.dart @@ -2,9 +2,9 @@ import 'dart:async'; import 'dart:io'; import 'package:flutter/material.dart'; -import 'package:maid/classes/providers/app_data.dart'; import 'package:maid/classes/providers/app_preferences.dart'; import 'package:maid/classes/providers/character.dart'; +import 'package:maid/classes/providers/characters.dart'; import 'package:maid/classes/providers/desktop_navigator.dart'; import 'package:maid/classes/static/logger.dart'; @@ -130,7 +130,7 @@ class _CharacterTileState extends State { void onTapUp(TapUpDetails details) { if (longPressTimer?.isActive ?? false) { longPressTimer?.cancel(); - AppData.of(context).currentCharacter = widget.character; + CharacterCollection.of(context).current = widget.character; if (AppPreferences.of(context).isDesktop) { DesktopNavigator.of(context).navigateSidePanel('/character'); @@ -155,7 +155,7 @@ class _CharacterTileState extends State { items: [ PopupMenuItem( onTap: () { - AppData.of(context).removeCharacter(widget.character); + CharacterCollection.of(context).removeCharacter(widget.character); }, child: const Text('Delete'), ), diff --git a/lib/ui/shared/tiles/session_tile.dart b/lib/ui/shared/tiles/session_tile.dart index 48e4ea4e..b37f89a9 100644 --- a/lib/ui/shared/tiles/session_tile.dart +++ b/lib/ui/shared/tiles/session_tile.dart @@ -1,9 +1,8 @@ import 'dart:async'; import 'package:flutter/material.dart'; -import 'package:maid/classes/providers/app_data.dart'; import 'package:maid/classes/providers/session.dart'; -import 'package:provider/provider.dart'; +import 'package:maid/classes/providers/sessions.dart'; class SessionTile extends StatefulWidget { final Session session; @@ -25,12 +24,6 @@ class _SessionTileState extends State { Widget build(BuildContext context) { controller.text = widget.session.name; - return Consumer( - builder: buildGestureDetector, - ); - } - - Widget buildGestureDetector(BuildContext context, AppData appData, Widget? child) { return InkWell( onSecondaryTapUp: (TapUpDetails details) => showContextMenu(details.globalPosition), @@ -55,7 +48,7 @@ class _SessionTileState extends State { void onTapUp(TapUpDetails details) { if (longPressTimer?.isActive ?? false) { longPressTimer?.cancel(); - AppData.of(context).currentSession = widget.session; + Sessions.of(context).current = widget.session; } } @@ -72,7 +65,7 @@ class _SessionTileState extends State { items: [ PopupMenuItem( onTap: () { - AppData.of(context).removeSession(widget.session); + Sessions.of(context).removeSession(widget.session); }, child: const Text('Delete'), ), @@ -113,10 +106,8 @@ class _SessionTileState extends State { ), FilledButton( onPressed: () => setState(() { - final appData = AppData.of(context); - - if (widget.session == appData.currentSession) { - appData.currentSession.name = controller.text; + if (widget.session == Sessions.of(context).current) { + Sessions.of(context).current.name = controller.text; } widget.session.name = controller.text; diff --git a/lib/ui/shared/utilities/session_busy_overlay.dart b/lib/ui/shared/utilities/session_busy_overlay.dart index 914dbb62..c9464b4d 100644 --- a/lib/ui/shared/utilities/session_busy_overlay.dart +++ b/lib/ui/shared/utilities/session_busy_overlay.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:maid/classes/providers/app_data.dart'; +import 'package:maid/classes/providers/sessions.dart'; import 'package:provider/provider.dart'; class SessionBusyOverlay extends StatefulWidget { @@ -17,7 +17,7 @@ class _SessionBusyOverlayState extends State { return Stack( children: [ widget.child, - if (!context.watch().currentSession.chat.tail.finalised) + if (!context.watch().current.chat.tail.finalised) Positioned.fill( child: Container( color: Colors.black.withOpacity(0.4), diff --git a/lib/ui/shared/views/characters_grid_view.dart b/lib/ui/shared/views/characters_grid_view.dart index ffea3d5e..05040005 100644 --- a/lib/ui/shared/views/characters_grid_view.dart +++ b/lib/ui/shared/views/characters_grid_view.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:maid/classes/providers/app_data.dart'; +import 'package:maid/classes/providers/characters.dart'; import 'package:maid/ui/shared/tiles/character_tile.dart'; import 'package:provider/provider.dart'; @@ -9,16 +9,16 @@ class CharactersGridView extends StatelessWidget { @override Widget build(BuildContext context) { - return Consumer( + return Consumer( builder: buildGridView ); } - Widget buildGridView(BuildContext context, AppData appData, Widget? child) { - appData.save(); + Widget buildGridView(BuildContext context, CharacterCollection characters, Widget? child) { + characters.save(); return GridView.builder( - itemCount: appData.characters.length, + itemCount: characters.list.length, gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( maxCrossAxisExtent: 200, crossAxisSpacing: 8.0, @@ -31,8 +31,8 @@ class CharactersGridView extends StatelessWidget { Widget buildCharacterTile(BuildContext context, int index) { return CharacterTile( - character: AppData.of(context).characters[index], - isSelected: AppData.of(context).currentCharacter == AppData.of(context).characters[index], + character: CharacterCollection.of(context).list[index], + isSelected: CharacterCollection.of(context).current == CharacterCollection.of(context).list[index], ); } } \ No newline at end of file diff --git a/lib/ui/shared/views/sessions_list_view.dart b/lib/ui/shared/views/sessions_list_view.dart index e1c1f036..ea8fe8f8 100644 --- a/lib/ui/shared/views/sessions_list_view.dart +++ b/lib/ui/shared/views/sessions_list_view.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:maid/classes/providers/app_data.dart'; +import 'package:maid/classes/providers/sessions.dart'; import 'package:maid/ui/shared/tiles/session_tile.dart'; import 'package:provider/provider.dart'; @@ -8,23 +8,23 @@ class SessionsListView extends StatelessWidget { @override Widget build(BuildContext context) { - return Consumer( + return Consumer( builder: buildListView, ); } - Widget buildListView(BuildContext context, AppData appData, Widget? child) { - appData.save(); + Widget buildListView(BuildContext context, Sessions sessions, Widget? child) { + sessions.save(); return ListView.builder( - itemCount: appData.sessions.length, + itemCount: sessions.list.length, itemBuilder: buildSessionTile ); } Widget buildSessionTile(BuildContext context, int index) { return SessionTile( - session: AppData.of(context).sessions[index] + session: Sessions.of(context).list[index] ); } } \ No newline at end of file