From caa44f355b4b5bc5554a2d67747b482dc19c139a Mon Sep 17 00:00:00 2001 From: CodeDoctorDE Date: Fri, 6 Sep 2024 10:39:27 +0200 Subject: [PATCH] Add page switch system --- api/lib/src/models/data.dart | 2 + app/lib/bloc/world/bloc.dart | 7 ++ app/lib/bloc/world/local.dart | 7 ++ app/lib/bloc/world/local.mapper.dart | 115 +++++++++++++++++++++++++++ app/lib/l10n/app_en.arb | 5 +- app/lib/pages/game/drawer.dart | 107 ++++++++++++++++++++++++- 6 files changed, 239 insertions(+), 4 deletions(-) diff --git a/api/lib/src/models/data.dart b/api/lib/src/models/data.dart index e3b35ae..646fcaa 100644 --- a/api/lib/src/models/data.dart +++ b/api/lib/src/models/data.dart @@ -47,6 +47,8 @@ class QuokkaData extends ArchiveData { utf8.encode(table.toJson()), ); + Iterable getTables() => getAssets(kGameTablePath, true); + FileMetadata? getMetadata() { final data = getAsset(kPackMetadataPath); if (data == null) { diff --git a/app/lib/bloc/world/bloc.dart b/app/lib/bloc/world/bloc.dart index 4d7f02c..d4090a7 100644 --- a/app/lib/bloc/world/bloc.dart +++ b/app/lib/bloc/world/bloc.dart @@ -81,6 +81,13 @@ class WorldBloc extends Bloc { switchCellOnMove: event.value, )); }); + on((event, emit) { + emit(state.copyWith( + table: state.data.getTableOrDefault(event.name), + tableName: event.name, + data: state.data.setTable(state.table, state.tableName), + )); + }); } Future save() async { diff --git a/app/lib/bloc/world/local.dart b/app/lib/bloc/world/local.dart index 5b46afb..b48c5d5 100644 --- a/app/lib/bloc/world/local.dart +++ b/app/lib/bloc/world/local.dart @@ -42,3 +42,10 @@ final class SwitchCellOnMoveChanged extends LocalWorldEvent SwitchCellOnMoveChanged(this.value); } + +@MappableClass() +final class TableSwitched extends LocalWorldEvent with TableSwitchedMappable { + final String name; + + TableSwitched([this.name = '']); +} diff --git a/app/lib/bloc/world/local.mapper.dart b/app/lib/bloc/world/local.mapper.dart index 8433d8f..6353d55 100644 --- a/app/lib/bloc/world/local.mapper.dart +++ b/app/lib/bloc/world/local.mapper.dart @@ -493,3 +493,118 @@ class _SwitchCellOnMoveChangedCopyWithImpl<$R, $Out> $chain<$R2, $Out2>(Then<$Out2, $R2> t) => _SwitchCellOnMoveChangedCopyWithImpl($value, $cast, t); } + +class TableSwitchedMapper extends SubClassMapperBase { + TableSwitchedMapper._(); + + static TableSwitchedMapper? _instance; + static TableSwitchedMapper ensureInitialized() { + if (_instance == null) { + MapperContainer.globals.use(_instance = TableSwitchedMapper._()); + LocalWorldEventMapper.ensureInitialized().addSubMapper(_instance!); + } + return _instance!; + } + + @override + final String id = 'TableSwitched'; + + static String _$name(TableSwitched v) => v.name; + static const Field _f$name = + Field('name', _$name, opt: true, def: ''); + + @override + final MappableFields fields = const { + #name: _f$name, + }; + + @override + final String discriminatorKey = 'type'; + @override + final dynamic discriminatorValue = 'TableSwitched'; + @override + late final ClassMapperBase superMapper = + LocalWorldEventMapper.ensureInitialized(); + + static TableSwitched _instantiate(DecodingData data) { + return TableSwitched(data.dec(_f$name)); + } + + @override + final Function instantiate = _instantiate; + + static TableSwitched fromMap(Map map) { + return ensureInitialized().decodeMap(map); + } + + static TableSwitched fromJson(String json) { + return ensureInitialized().decodeJson(json); + } +} + +mixin TableSwitchedMappable { + String toJson() { + return TableSwitchedMapper.ensureInitialized() + .encodeJson(this as TableSwitched); + } + + Map toMap() { + return TableSwitchedMapper.ensureInitialized() + .encodeMap(this as TableSwitched); + } + + TableSwitchedCopyWith + get copyWith => _TableSwitchedCopyWithImpl( + this as TableSwitched, $identity, $identity); + @override + String toString() { + return TableSwitchedMapper.ensureInitialized() + .stringifyValue(this as TableSwitched); + } + + @override + bool operator ==(Object other) { + return TableSwitchedMapper.ensureInitialized() + .equalsValue(this as TableSwitched, other); + } + + @override + int get hashCode { + return TableSwitchedMapper.ensureInitialized() + .hashValue(this as TableSwitched); + } +} + +extension TableSwitchedValueCopy<$R, $Out> + on ObjectCopyWith<$R, TableSwitched, $Out> { + TableSwitchedCopyWith<$R, TableSwitched, $Out> get $asTableSwitched => + $base.as((v, t, t2) => _TableSwitchedCopyWithImpl(v, t, t2)); +} + +abstract class TableSwitchedCopyWith<$R, $In extends TableSwitched, $Out> + implements LocalWorldEventCopyWith<$R, $In, $Out> { + @override + $R call({String? name}); + TableSwitchedCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t); +} + +class _TableSwitchedCopyWithImpl<$R, $Out> + extends ClassCopyWithBase<$R, TableSwitched, $Out> + implements TableSwitchedCopyWith<$R, TableSwitched, $Out> { + _TableSwitchedCopyWithImpl(super.value, super.then, super.then2); + + @override + late final ClassMapperBase $mapper = + TableSwitchedMapper.ensureInitialized(); + @override + $R call({String? name}) => + $apply(FieldCopyWithData({if (name != null) #name: name})); + @override + TableSwitched $make(CopyWithData data) => + TableSwitched(data.get(#name, or: $value.name)); + + @override + TableSwitchedCopyWith<$R2, TableSwitched, $Out2> $chain<$R2, $Out2>( + Then<$Out2, $R2> t) => + _TableSwitchedCopyWithImpl($value, $cast, t); +} diff --git a/app/lib/l10n/app_en.arb b/app/lib/l10n/app_en.arb index 97e381c..e185a5d 100644 --- a/app/lib/l10n/app_en.arb +++ b/app/lib/l10n/app_en.arb @@ -142,5 +142,8 @@ "switchCellOnMove": "Switch cell on move", "addPack": "Add pack", "removePack": "Remove pack", - "noTemplates": "There are no templates available" + "noTemplates": "There are no templates available", + "table": "Table", + "defaultTable": "Default table", + "switchTable": "Switch table" } diff --git a/app/lib/pages/game/drawer.dart b/app/lib/pages/game/drawer.dart index 8619405..d481149 100644 --- a/app/lib/pages/game/drawer.dart +++ b/app/lib/pages/game/drawer.dart @@ -133,6 +133,108 @@ class GameDrawer extends StatelessWidget { ); }, ), + BlocBuilder( + buildWhen: (previous, current) => + previous.tableName != current.tableName, + builder: (context, state) { + final bloc = context.read(); + return ListTile( + leading: const Icon(PhosphorIconsLight.gridFour), + title: Text(AppLocalizations.of(context).table), + subtitle: Text(state.tableName.isEmpty + ? AppLocalizations.of(context).defaultTable + : state.tableName), + onTap: () => showLeapBottomSheet( + context: context, + titleBuilder: (context) => + Text(AppLocalizations.of(context).table), + actionsBuilder: (context) => [ + IconButton( + icon: const Icon( + PhosphorIconsLight.arrowsLeftRight), + tooltip: + AppLocalizations.of(context).switchTable, + onPressed: () async { + String name = ''; + final result = await showDialog( + context: context, + builder: (context) => AlertDialog( + title: Text(AppLocalizations.of(context) + .switchTable), + content: TextField( + decoration: InputDecoration( + labelText: + AppLocalizations.of(context).name, + hintText: AppLocalizations.of(context) + .enterName, + filled: true, + ), + onChanged: (value) => name = value, + onSubmitted: (value) => + Navigator.of(context).pop(true), + autofocus: true, + ), + actions: [ + TextButton.icon( + onPressed: () => + Navigator.of(context).pop(false), + label: Text( + AppLocalizations.of(context) + .cancel), + icon: const Icon( + PhosphorIconsLight.prohibit), + ), + ElevatedButton.icon( + onPressed: () => + Navigator.of(context).pop(true), + label: Text( + AppLocalizations.of(context) + .change), + icon: const Icon( + PhosphorIconsLight.check), + ), + ], + ), + ); + if (!(result ?? false)) return; + bloc.process(TableSwitched(name)); + }, + ), + ], + childrenBuilder: (context) => [ + BlocBuilder( + bloc: bloc, + buildWhen: (previous, current) => + previous.tableName != current.tableName || + previous.data != current.data, + builder: (context, state) { + final other = { + ...state.data.getTables(), + state.tableName + }.where((e) => e.isNotEmpty).toList(); + return Column( + children: [ + ListTile( + title: Text(AppLocalizations.of(context) + .defaultTable), + selected: state.tableName == '', + onTap: () => + bloc.process(TableSwitched()), + ), + if (other.isNotEmpty) const Divider(), + ...other.map((e) => ListTile( + title: Text(e), + selected: state.tableName == e, + onTap: () => + bloc.process(TableSwitched(e)), + )), + ], + ); + }, + ) + ])); + }, + ), BlocBuilder( buildWhen: (previous, current) => previous.table.background != current.table.background, @@ -292,6 +394,7 @@ class GameDrawer extends StatelessWidget { content: TextField( decoration: InputDecoration( labelText: AppLocalizations.of(context).name, + hintText: AppLocalizations.of(context).enterName, filled: true, ), onChanged: (value) => name = value, @@ -304,9 +407,7 @@ class GameDrawer extends StatelessWidget { child: Text(AppLocalizations.of(context).cancel), ), ElevatedButton( - onPressed: () { - Navigator.of(context).pop(true); - }, + onPressed: () => Navigator.of(context).pop(true), child: Text(AppLocalizations.of(context).save), ), ],