diff --git a/lib/app/model_utils/model_pages.dart b/lib/app/model_utils/model_pages.dart index 8fa9f50a..8780604e 100644 --- a/lib/app/model_utils/model_pages.dart +++ b/lib/app/model_utils/model_pages.dart @@ -16,6 +16,7 @@ import 'package:dungeon_paper/app/modules/LibraryList/views/moves_library_list_v import 'package:dungeon_paper/app/modules/LibraryList/views/notes_library_list_view.dart'; import 'package:dungeon_paper/app/modules/LibraryList/views/races_library_list_view.dart'; import 'package:dungeon_paper/app/modules/LibraryList/views/spells_library_list_view.dart'; +import 'package:dungeon_paper/app/modules/StandardMoves/controllers/standard_moves_list_controller.dart'; import 'package:dungeon_paper/app/routes/app_pages.dart'; import 'package:dungeon_paper/app/widgets/forms/character_class_form.dart'; import 'package:dungeon_paper/app/widgets/forms/item_form.dart'; @@ -122,6 +123,21 @@ class ModelPages with LibraryProviderMixin, CharacterProviderMixin { ); } + static void openStandardMovesList( + BuildContext context, { + required Character character, + required MoveCategory category, + }) { + final char = character; + Navigator.of(context).pushNamed( + Routes.standardMoves, + arguments: StandardMovesArgs( + category: category, + character: char, + ), + ); + } + static void openRacesList( BuildContext context, { Character? character, @@ -318,4 +334,4 @@ class ModelPages with LibraryProviderMixin, CharacterProviderMixin { characterClass == null ? FormContext.create : FormContext.edit, ), ); -} +} \ No newline at end of file diff --git a/lib/app/modules/Home/views/home_character_actions_view.dart b/lib/app/modules/Home/views/home_character_actions_view.dart index 0f184404..f996e2eb 100644 --- a/lib/app/modules/Home/views/home_character_actions_view.dart +++ b/lib/app/modules/Home/views/home_character_actions_view.dart @@ -42,19 +42,15 @@ class HomeCharacterActionsView extends StatelessWidget Widget build(BuildContext context) { return PageStorage( bucket: PageStorageBucket(), - child: CharacterProvider.consumer( - (context, controller, _) { - if (controller.maybeCurrent == null) { - return Container(); - } - final builder = _getBuilder(controller); - return SizedBox( - child: builder.asListView( - padding: const EdgeInsets.only(bottom: 16), - ), - ); - }, - ), + child: CharacterProvider.consumer((context, controller, _) { + if (controller.maybeCurrent == null) { + return Container(); + } + final builder = _getBuilder(controller); + return SizedBox( + child: builder.asListView(padding: const EdgeInsets.only(bottom: 16)), + ); + }), ); } @@ -97,20 +93,22 @@ class HomeCharacterActionsView extends StatelessWidget } final raceCard = RaceCard( race: char.race, - onSave: (race) => controller.updateCharacter( - char.copyWithInherited(race: race), - ), + onSave: + (race) => + controller.updateCharacter(char.copyWithInherited(race: race)), actions: [ EntityEditMenu( onDelete: null, - onEdit: () => ModelPages.openRacePage( - context, - race: char.race, - abilityScores: char.abilityScores, - onSave: (race) => controller.updateCharacter( - char.copyWithInherited(race: race), - ), - ), + onEdit: + () => ModelPages.openRacePage( + context, + race: char.race, + abilityScores: char.abilityScores, + onSave: + (race) => controller.updateCharacter( + char.copyWithInherited(race: race), + ), + ), ), ], ); @@ -119,10 +117,11 @@ class HomeCharacterActionsView extends StatelessWidget actions: [ EntityEditMenu( onDelete: null, - onEdit: () => Navigator.of(context).pushNamed( - Routes.bio, - arguments: BioFormArguments(character: char), - ), + onEdit: + () => Navigator.of(context).pushNamed( + Routes.bio, + arguments: BioFormArguments(character: char), + ), ), ElevatedButton( onPressed: () => CharacterUtils.addXP(context, char, 1), @@ -130,10 +129,7 @@ class HomeCharacterActionsView extends StatelessWidget ), ], ); - final list = [ - raceCard, - alignmentCard, - ]; + final list = [raceCard, alignmentCard]; final index = char.actionCategories.toList().indexOf('ClassAction'); return CategorizedList( initiallyExpanded: true, @@ -143,19 +139,17 @@ class HomeCharacterActionsView extends StatelessWidget index: index, totalItemCount: Character.allActionCategories.length, onReorder: _onReorder, - ) + ), ], itemPadding: const EdgeInsets.only(bottom: 8), children: [ - ...list.map( - (obj) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 4), - key: PageStorageKey('type-ClassAction-${obj.key}'), - child: obj, - ); - }, - ), + ...list.map((obj) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 4), + key: PageStorageKey('type-ClassAction-${obj.key}'), + child: obj, + ); + }), ], ); } @@ -176,18 +170,14 @@ class HomeCharacterActionsView extends StatelessWidget Expanded( child: ElevatedButton( onPressed: () => _openBasicMoves(context), - child: Text( - tr.actions.moves.basic, - ), + child: Text(tr.actions.moves.basic), ), ), const SizedBox(width: 16), Expanded( child: ElevatedButton( onPressed: () => _openSpecialMoves(context), - child: Text( - tr.actions.moves.special, - ), + child: Text(tr.actions.moves.special), ), ), ], @@ -202,49 +192,56 @@ class HomeCharacterActionsView extends StatelessWidget MenuEntry( value: 'move_to_start', label: Text(tr.sort.moveEntityToTop(tr.entity(tn(Race)))), - onSelect: () => controller.updateCharacter( - char.copyWith( - settings: - char.settings.copyWith(racePosition: RacePosition.start), - ), - ), + onSelect: + () => controller.updateCharacter( + char.copyWith( + settings: char.settings.copyWith( + racePosition: RacePosition.start, + ), + ), + ), ), if (char.settings.racePosition != RacePosition.end) // Move to end of list MenuEntry( value: 'move_to_end', label: Text(tr.sort.moveEntityToBottom(tr.entity(tn(Race)))), - onSelect: () => controller.updateCharacter( - char.copyWith( - settings: - char.settings.copyWith(racePosition: RacePosition.end), - ), - ), + onSelect: + () => controller.updateCharacter( + char.copyWith( + settings: char.settings.copyWith( + racePosition: RacePosition.end, + ), + ), + ), ), ], - addPageArguments: ({required onSelected}) => MoveLibraryListArguments( - character: char, - onSelected: onSelected, - preSelections: char.moves, - ), - cardBuilder: (move, {required onSave, required onDelete}) => MoveCard( - reorderablePadding: true, - move: move, - advancedLevelDisplay: AdvancedLevelDisplay.none, - abilityScores: char.abilityScores, - actions: [ - EntityEditMenu( - onDelete: onDelete, - onEdit: () => ModelPages.openMovePage( - context, - move: move, - abilityScores: char.abilityScores, - onSave: onSave(true), - ), + addPageArguments: + ({required onSelected}) => MoveLibraryListArguments( + character: char, + onSelected: onSelected, + preSelections: char.moves, + ), + cardBuilder: + (move, {required onSave, required onDelete}) => MoveCard( + reorderablePadding: true, + move: move, + advancedLevelDisplay: AdvancedLevelDisplay.none, + abilityScores: char.abilityScores, + actions: [ + EntityEditMenu( + onDelete: onDelete, + onEdit: + () => ModelPages.openMovePage( + context, + move: move, + abilityScores: char.abilityScores, + onSave: onSave(true), + ), + ), + ], + onSave: onSave(false), ), - ], - onSave: onSave(false), - ), ); } @@ -258,29 +255,32 @@ class HomeCharacterActionsView extends StatelessWidget onReorder: _onReorder, list: char.spells, route: Routes.spells, - addPageArguments: ({required onSelected}) => SpellLibraryListArguments( - character: char, - onSelected: onSelected, - preSelections: char.spells, - ), - cardBuilder: (spell, {required onSave, required onDelete}) => SpellCard( - reorderablePadding: true, - spell: spell, - abilityScores: char.abilityScores, - actions: [ - EntityEditMenu( - onDelete: onDelete, - onEdit: () => ModelPages.openSpellPage( - context, - spell: spell, - classKeys: spell.classKeys, - abilityScores: char.abilityScores, - onSave: onSave(true), - ), + addPageArguments: + ({required onSelected}) => SpellLibraryListArguments( + character: char, + onSelected: onSelected, + preSelections: char.spells, + ), + cardBuilder: + (spell, {required onSave, required onDelete}) => SpellCard( + reorderablePadding: true, + spell: spell, + abilityScores: char.abilityScores, + actions: [ + EntityEditMenu( + onDelete: onDelete, + onEdit: + () => ModelPages.openSpellPage( + context, + spell: spell, + classKeys: spell.classKeys, + abilityScores: char.abilityScores, + onSave: onSave(true), + ), + ), + ], + onSave: onSave(false), ), - ], - onSave: onSave(false), - ), ); } @@ -294,64 +294,78 @@ class HomeCharacterActionsView extends StatelessWidget onReorder: _onReorder, list: char.items, route: Routes.items, - addPageArguments: ({required onSelected}) => ItemLibraryListArguments( - onSelected: (items) => onSelected( - items - .map( - (x) => - x.copyWithInherited(amount: x.amount == 0 ? 1 : x.amount), - ) - .toList(), - ), - preSelections: char.items, - ), - cardBuilder: (item, {required onSave, required onDelete}) => ItemCard( - reorderablePadding: true, - item: item, - actions: [ - EntityEditMenu( - onDelete: onDelete, - onEdit: () => ModelPages.openItemPage( - context, - item: item, - onSave: onSave(true), - ), - leading: [ - ChecklistMenuEntry( - value: 'countArmor', - checked: item.settings.countArmor, - label: Text(tr.items.settings.countArmor), - onChanged: (value) => onSave(false)( - item.copyWithInherited( - settings: item.settings.copyWith(countArmor: value!), - ), + addPageArguments: + ({required onSelected}) => ItemLibraryListArguments( + onSelected: + (items) => onSelected( + items + .map( + (x) => x.copyWithInherited( + amount: x.amount == 0 ? 1 : x.amount, + ), + ) + .toList(), ), - ), - ChecklistMenuEntry( - value: 'countDamage', - checked: item.settings.countDamage, - label: Text(tr.items.settings.countDamage), - onChanged: (value) => onSave(false)( - item.copyWithInherited( - settings: item.settings.copyWith(countDamage: value!), + preSelections: char.items, + ), + cardBuilder: + (item, {required onSave, required onDelete}) => ItemCard( + reorderablePadding: true, + item: item, + actions: [ + EntityEditMenu( + onDelete: onDelete, + onEdit: + () => ModelPages.openItemPage( + context, + item: item, + onSave: onSave(true), + ), + leading: [ + ChecklistMenuEntry( + value: 'countArmor', + checked: item.settings.countArmor, + label: Text(tr.items.settings.countArmor), + onChanged: + (value) => onSave(false)( + item.copyWithInherited( + settings: item.settings.copyWith( + countArmor: value!, + ), + ), + ), ), - ), - ), - ChecklistMenuEntry( - value: 'countWeight', - checked: item.settings.countWeight, - label: Text(tr.items.settings.countWeight), - onChanged: (value) => onSave(false)( - item.copyWithInherited( - settings: item.settings.copyWith(countWeight: value!), + ChecklistMenuEntry( + value: 'countDamage', + checked: item.settings.countDamage, + label: Text(tr.items.settings.countDamage), + onChanged: + (value) => onSave(false)( + item.copyWithInherited( + settings: item.settings.copyWith( + countDamage: value!, + ), + ), + ), ), - ), + ChecklistMenuEntry( + value: 'countWeight', + checked: item.settings.countWeight, + label: Text(tr.items.settings.countWeight), + onChanged: + (value) => onSave(false)( + item.copyWithInherited( + settings: item.settings.copyWith( + countWeight: value!, + ), + ), + ), + ), + ], ), ], + onSave: onSave(false), ), - ], - onSave: onSave(false), - ), ); } @@ -375,20 +389,18 @@ class HomeCharacterActionsView extends StatelessWidget } void _openBasicMoves(BuildContext context) { - ModelPages.openMovesList( + ModelPages.openStandardMovesList( context, category: MoveCategory.basic, - initialTab: FiltersGroup.playbook, - abilityScores: char.abilityScores, + character: char, ); } void _openSpecialMoves(BuildContext context) { - ModelPages.openMovesList( + ModelPages.openStandardMovesList( context, category: MoveCategory.special, - initialTab: FiltersGroup.playbook, - abilityScores: char.abilityScores, + character: char, ); } } @@ -416,17 +428,19 @@ class ActionsCardList extends StatelessWidget final List trailing; final LibraryListArguments> Function({ required void Function(Iterable obj) onSelected, - }) addPageArguments; + }) + addPageArguments; final Widget Function( T object, { required void Function() onDelete, required void Function(T object) Function(bool fork) onSave, // required void Function() onEdit, - }) cardBuilder; + }) + cardBuilder; final List list; final int index; final void Function(BuildContext context, int oldIndex, int newIndex) - onReorder; + onReorder; final List> menuLeading; final List> menuTrailing; @@ -435,7 +449,8 @@ class ActionsCardList extends StatelessWidget return CharacterProvider.consumer((context, controller, _) { debugPrint('ActionsCardList rebuild'); debugPrint( - 'Character items: \n${controller.current.items.map((e) => '- ${e.displayName}').join('\n')}'); + 'Character items: \n${controller.current.items.map((e) => '- ${e.displayName}').join('\n')}', + ); return CategorizedList( initiallyExpanded: true, title: Text(tr.entityPlural(typeName)), @@ -443,14 +458,18 @@ class ActionsCardList extends StatelessWidget titleTrailing: [ LibraryProvider.consumer( (context, library, _) => TextButton.icon( - onPressed: () => Navigator.pushNamed( - context, - route, - arguments: addPageArguments( - onSelected: (items) => library.upsertToCharacter(items, - forkBehavior: ForkBehavior.fork), - ), - ), + onPressed: + () => Navigator.pushNamed( + context, + route, + arguments: addPageArguments( + onSelected: + (items) => library.upsertToCharacter( + items, + forkBehavior: ForkBehavior.fork, + ), + ), + ), label: Text(tr.generic.addEntity(tr.entityPlural(typeName))), icon: const Icon(Icons.add), ), @@ -461,40 +480,45 @@ class ActionsCardList extends StatelessWidget onReorder: onReorder, leading: menuLeading, trailing: menuTrailing, - ) + ), ], leading: leading.map((obj) => _wrapChild(child: obj)).toList(), trailing: trailing.map((obj) => _wrapChild(child: obj)).toList(), children: [ - ...list.map( - (obj) { - return _wrapChild( - key: PageStorageKey('type-$T-${obj.key}'), - child: cardBuilder( - obj, - onDelete: _confirmDeleteDlg(context, obj, obj.displayName), - onSave: (fork) => (obj) { - final library = LibraryProvider.of(context); - library.upsertToCharacter([obj], - forkBehavior: ForkBehavior.none); - }, - ), - ); - }, - ), + ...list.map((obj) { + return _wrapChild( + key: PageStorageKey('type-$T-${obj.key}'), + child: cardBuilder( + obj, + onDelete: _confirmDeleteDlg(context, obj, obj.displayName), + onSave: + (fork) => (obj) { + final library = LibraryProvider.of(context); + library.upsertToCharacter([ + obj, + ], forkBehavior: ForkBehavior.none); + }, + ), + ); + }), ], - onReorder: (oldIndex, newIndex) => controller.updateCharacter( - CharacterUtils.reorderByType( - controller.current, oldIndex, newIndex)), + onReorder: + (oldIndex, newIndex) => controller.updateCharacter( + CharacterUtils.reorderByType( + controller.current, + oldIndex, + newIndex, + ), + ), ); }); } Widget _wrapChild({Key? key, required Widget child}) => Padding( - key: key, - padding: const EdgeInsets.symmetric(vertical: 4), - child: child, - ); + key: key, + padding: const EdgeInsets.symmetric(vertical: 4), + child: child, + ); void Function() _confirmDeleteDlg( BuildContext context, @@ -505,8 +529,9 @@ class ActionsCardList extends StatelessWidget awaitDeleteConfirmation( context, name, - () => charProvider - .updateCharacter(CharacterUtils.removeByType(char, [object])), + () => charProvider.updateCharacter( + CharacterUtils.removeByType(char, [object]), + ), ); }; } diff --git a/lib/app/modules/StandardMoves/controllers/standard_moves_list_controller.dart b/lib/app/modules/StandardMoves/controllers/standard_moves_list_controller.dart new file mode 100644 index 00000000..b9bb03ce --- /dev/null +++ b/lib/app/modules/StandardMoves/controllers/standard_moves_list_controller.dart @@ -0,0 +1,72 @@ +import 'package:dungeon_paper/app/data/models/character.dart'; +import 'package:dungeon_paper/app/data/models/move.dart'; +import 'package:dungeon_paper/app/data/services/repository_provider.dart'; +import 'package:dungeon_paper/core/route_arguments.dart'; +import 'package:dungeon_paper/i18n.dart'; +import 'package:flutter/material.dart'; + +class StandardMovesListController extends ChangeNotifier { + late StandardMovesArgs args; + + StandardMovesListController(BuildContext context) { + args = getArgs(context); + } + + String get title { + switch (args.category) { + case MoveCategory.basic: + return tr.actions.moves.basic; + case MoveCategory.special: + return tr.actions.moves.special; + default: + return ''; + } + } + + List builtInMoves(BuildContext context) { + final repo = RepositoryProvider.of(context); + switch (args.category) { + case MoveCategory.basic: + return repo.builtIn + .listByType() + .values + .where((move) => move.category == MoveCategory.basic) + .toList(); + case MoveCategory.special: + return repo.builtIn + .listByType() + .values + .where((move) => move.category == MoveCategory.special) + .toList(); + default: + return []; + } + } + + List playbookMoves(BuildContext context) { + final repo = RepositoryProvider.of(context); + switch (args.category) { + case MoveCategory.basic: + return repo.my + .listByType() + .values + .where((move) => move.category == MoveCategory.basic) + .toList(); + case MoveCategory.special: + return repo.my + .listByType() + .values + .where((move) => move.category == MoveCategory.special) + .toList(); + default: + return []; + } + } +} + +class StandardMovesArgs { + final MoveCategory category; + final Character character; + + StandardMovesArgs({required this.category, required this.character}); +} diff --git a/lib/app/modules/StandardMoves/views/standard_moves_list.dart b/lib/app/modules/StandardMoves/views/standard_moves_list.dart new file mode 100644 index 00000000..f87c80e0 --- /dev/null +++ b/lib/app/modules/StandardMoves/views/standard_moves_list.dart @@ -0,0 +1,64 @@ +import 'package:dungeon_paper/app/modules/StandardMoves/controllers/standard_moves_list_controller.dart'; +import 'package:dungeon_paper/app/widgets/cards/move_card.dart'; +import 'package:dungeon_paper/i18n.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +class StandardMovesListView extends StatelessWidget { + const StandardMovesListView({super.key}); + + @override + Widget build(BuildContext context) { + return Consumer( + builder: (context, controller, _) { + final textTheme = Theme.of(context).textTheme.titleMedium!; + return Scaffold( + appBar: AppBar(title: Text(controller.title)), + body: Center( + child: SizedBox( + width: 800, + child: ListView( + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + tr.myLibrary.libraryType('builtIn'), + style: textTheme, + ), + ), + for (final move in controller.builtInMoves(context)) + Padding( + padding: const EdgeInsets.all(8.0), + child: MoveCard( + move: move, + showStar: false, + showClasses: false, + abilityScores: controller.args.character.abilityScores, + ), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + tr.myLibrary.libraryType('my'), + style: textTheme, + ), + ), + for (final move in controller.playbookMoves(context)) + Padding( + padding: const EdgeInsets.all(8.0), + child: MoveCard( + move: move, + showStar: false, + showClasses: false, + abilityScores: controller.args.character.abilityScores, + ), + ), + ], + ), + ), + ), + ); + }, + ); + } +} diff --git a/lib/app/routes/app_pages.dart b/lib/app/routes/app_pages.dart index 2f71d6ff..0d7f4497 100644 --- a/lib/app/routes/app_pages.dart +++ b/lib/app/routes/app_pages.dart @@ -1,3 +1,5 @@ +import 'package:dungeon_paper/app/modules/StandardMoves/controllers/standard_moves_list_controller.dart'; +import 'package:dungeon_paper/app/modules/StandardMoves/views/standard_moves_list.dart'; import 'package:dungeon_paper/app/widgets/atoms/platform_scaffold_wrapper.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -196,6 +198,11 @@ class AppPages { child: const MovesLibraryListView(), ), + Routes.standardMoves: (context) => ChangeNotifierProvider( + create: (_) => StandardMovesListController(context), + child: const StandardMovesListView(), + ), + Routes.editMove: (context) => ChangeNotifierProvider( create: (_) => MoveFormController(context), child: const MoveForm(), @@ -365,4 +372,4 @@ class AppPages { create: (_) => ChangelogController(), ), }; -} +} \ No newline at end of file diff --git a/lib/app/routes/app_routes.dart b/lib/app/routes/app_routes.dart index 0525ba6c..dc16be7c 100644 --- a/lib/app/routes/app_routes.dart +++ b/lib/app/routes/app_routes.dart @@ -40,6 +40,9 @@ abstract class Routes { /// `/library/moves` static const moves = _Paths.library + _Paths.moves; + /// `/library/standard-moves` + static const standardMoves = _Paths.library + _Paths.standardMoves; + /// `/library/moves/edit` static const editMove = _Paths.library + _Paths.moves + _Paths.edit; @@ -221,6 +224,9 @@ abstract class _Paths { /// `/moves` static const moves = '/moves'; + /// `/standard-moves` + static const standardMoves = '/standard-moves'; + /// `/spells` static const spells = '/spells'; @@ -256,4 +262,4 @@ abstract class _Paths { /// `/changelog` static const changelog = '/changelog'; -} +} \ No newline at end of file