Skip to content

Commit

Permalink
Add simple editor pages
Browse files Browse the repository at this point in the history
  • Loading branch information
CodeDoctorDE committed Dec 24, 2024
1 parent f5361ce commit a6d0c4b
Show file tree
Hide file tree
Showing 11 changed files with 175 additions and 59 deletions.
8 changes: 7 additions & 1 deletion api/lib/src/models/data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ class SetonixData extends ArchiveData<SetonixData> {

Iterable<PackItem<FigureDefinition>> getFigureItems(
[String namespace = '']) =>
getDecks().map((e) => getFigureItem(e, namespace)).nonNulls;
getFigures().map((e) => getFigureItem(e, namespace)).nonNulls;

Iterable<String> getBoards() => getAssets(kPackBoardsPath, true);

Expand Down Expand Up @@ -214,6 +214,12 @@ class SetonixData extends ArchiveData<SetonixData> {
translations: getAllTranslations(),
getLocale: getLocale,
);

SetonixData removeFigure(String figure) =>
removeAsset('$kPackFiguresPath/$figure.json');

SetonixData setFigure(String figure, FigureDefinition definition) => setAsset(
'$kPackFiguresPath/$figure.json', utf8.encode(definition.toJson()));
}

class SetonixFile {
Expand Down
2 changes: 0 additions & 2 deletions api/lib/src/models/meta.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ enum FileType {
@MappableClass()
final class FileMetadata with FileMetadataMappable {
final FileType type;
final String id;
final String name;
final String description;
final String author;
Expand All @@ -24,7 +23,6 @@ final class FileMetadata with FileMetadataMappable {

const FileMetadata({
this.type = FileType.pack,
this.id = '',
this.name = '',
this.description = '',
this.author = '',
Expand Down
9 changes: 0 additions & 9 deletions api/lib/src/models/meta.mapper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,6 @@ class FileMetadataMapper extends ClassMapperBase<FileMetadata> {
static FileType _$type(FileMetadata v) => v.type;
static const Field<FileMetadata, FileType> _f$type =
Field('type', _$type, opt: true, def: FileType.pack);
static String _$id(FileMetadata v) => v.id;
static const Field<FileMetadata, String> _f$id =
Field('id', _$id, opt: true, def: '');
static String _$name(FileMetadata v) => v.name;
static const Field<FileMetadata, String> _f$name =
Field('name', _$name, opt: true, def: '');
Expand All @@ -99,7 +96,6 @@ class FileMetadataMapper extends ClassMapperBase<FileMetadata> {
@override
final MappableFields<FileMetadata> fields = const {
#type: _f$type,
#id: _f$id,
#name: _f$name,
#description: _f$description,
#author: _f$author,
Expand All @@ -111,7 +107,6 @@ class FileMetadataMapper extends ClassMapperBase<FileMetadata> {
static FileMetadata _instantiate(DecodingData data) {
return FileMetadata(
type: data.dec(_f$type),
id: data.dec(_f$id),
name: data.dec(_f$name),
description: data.dec(_f$description),
author: data.dec(_f$author),
Expand Down Expand Up @@ -174,7 +169,6 @@ abstract class FileMetadataCopyWith<$R, $In extends FileMetadata, $Out>
implements ClassCopyWith<$R, $In, $Out> {
$R call(
{FileType? type,
String? id,
String? name,
String? description,
String? author,
Expand All @@ -195,7 +189,6 @@ class _FileMetadataCopyWithImpl<$R, $Out>
@override
$R call(
{FileType? type,
String? id,
String? name,
String? description,
String? author,
Expand All @@ -204,7 +197,6 @@ class _FileMetadataCopyWithImpl<$R, $Out>
int? fileVersion}) =>
$apply(FieldCopyWithData({
if (type != null) #type: type,
if (id != null) #id: id,
if (name != null) #name: name,
if (description != null) #description: description,
if (author != null) #author: author,
Expand All @@ -215,7 +207,6 @@ class _FileMetadataCopyWithImpl<$R, $Out>
@override
FileMetadata $make(CopyWithData data) => FileMetadata(
type: data.get(#type, or: $value.type),
id: data.get(#id, or: $value.id),
name: data.get(#name, or: $value.name),
description: data.get(#description, or: $value.description),
author: data.get(#author, or: $value.author),
Expand Down
6 changes: 3 additions & 3 deletions app/lib/api/open.dart
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,12 @@ Future<void> importFileData(BuildContext context, SetonixFileSystem fileSystem,
),
);
if (!(result ?? false)) return;
final namespace = metadata.id;
final id = file.identifier;
switch (type) {
case FileType.pack:
await fileSystem.packSystem.updateFile(namespace, file);
await fileSystem.packSystem.updateFile(id, file);
case FileType.template:
await fileSystem.templateSystem.updateFile(namespace, data);
await fileSystem.templateSystem.createFile(metadata.name, data);
case FileType.game:
await fileSystem.worldSystem.createFile(metadata.name, data);
}
Expand Down
24 changes: 22 additions & 2 deletions app/lib/bloc/editor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,27 @@ class EditorCubit extends Cubit<SetonixData> {
save();
}

Future<void> save() {
return fileSystem.editorSystem.updateFile(path, state);
bool _needsSave = false;
bool _isSaving = false;

Future<void> save() async {
_needsSave = true;
if (_isSaving) {
return;
}
_isSaving = true;
while (_needsSave) {
_needsSave = false;
await fileSystem.editorSystem.updateFile(path, state);
}
_isSaving = false;
}

void removeFigure(String figure) {
emit(state.removeFigure(figure));
}

void setFigure(String figure, FigureDefinition definition) {
emit(state.setFigure(figure, definition));
}
}
17 changes: 9 additions & 8 deletions app/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_web_plugins/url_strategy.dart';
import 'package:material_leap/l10n/leap_localizations.dart';
import 'package:material_leap/material_leap.dart';
import 'package:setonix/pages/editor/general.dart';
import 'package:setonix/pages/editor/shell.dart';
import 'package:setonix/pages/game/page.dart';
import 'package:setonix/pages/home/page.dart';
Expand Down Expand Up @@ -132,13 +131,15 @@ class SetonixApp extends StatelessWidget {
name: state.pathParameters['name']!,
child: child,
),
routes: [
GoRoute(
name: 'editor',
path: kEditorPath,
builder: (context, state) => const GeneralEditorPage(),
),
],
routes: EditorPage.values
.map(
(e) => GoRoute(
path: '$kEditorPath${e.location}',
name: e.route,
builder: (context, state) => e.getPage(),
),
)
.toList(),
),
GoRoute(
name: 'connect',
Expand Down
66 changes: 66 additions & 0 deletions app/lib/pages/editor/figures.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:material_leap/material_leap.dart';
import 'package:phosphor_flutter/phosphor_flutter.dart';
import 'package:setonix/bloc/editor.dart';
import 'package:setonix_api/setonix_api.dart';

class FiguresEditorPage extends StatelessWidget {
const FiguresEditorPage({super.key});

@override
Widget build(BuildContext context) {
final cubit = context.read<EditorCubit>();
return Scaffold(
body: SingleChildScrollView(
child: Center(
child: Container(
constraints: BoxConstraints(maxWidth: LeapBreakpoints.expanded),
padding: const EdgeInsets.all(4),
child: BlocBuilder<EditorCubit, SetonixData>(
builder: (context, state) {
final figures = state.getFigureItems();
return Column(
children: figures.map((figure) {
final id = figure.id;
return Dismissible(
key: ValueKey(id),
onDismissed: (direction) {
cubit.removeFigure(id);
},
child: ListTile(
title: Text(id),
trailing: IconButton(
icon: const Icon(PhosphorIconsLight.trash),
onPressed: () {
cubit.removeFigure(id);
},
),
),
);
}).toList(),
);
},
),
),
),
),
floatingActionButton: FloatingActionButton.extended(
onPressed: () async {
final name = await showDialog<String>(
context: context,
builder: (context) => NameDialog(
validator: defaultNameValidator(
context, cubit.state.getFigures().toList()),
));
if (name == null) return;
cubit.setFigure(
name, FigureDefinition(back: FigureBackDefinition(texture: '')));
},
label: Text(AppLocalizations.of(context).create),
icon: const Icon(PhosphorIconsLight.plus),
),
);
}
}
76 changes: 47 additions & 29 deletions app/lib/pages/editor/shell.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,28 @@ import 'package:go_router/go_router.dart';
import 'package:material_leap/material_leap.dart';
import 'package:phosphor_flutter/phosphor_flutter.dart';
import 'package:setonix/bloc/editor.dart';
import 'package:setonix/pages/editor/figures.dart';
import 'package:setonix/pages/editor/general.dart';
import 'package:setonix/services/file_system.dart';
import 'package:setonix_api/setonix_api.dart';

const kEditorPath = '/editor/:name';

enum EditorPage {
general(PhosphorIcons.house, ''),
figures(PhosphorIcons.cube, 'figures'),
decks(PhosphorIcons.stack, 'decks'),
backgrounds(PhosphorIcons.image, 'backgrounds'),
translations(PhosphorIcons.translate, 'translations');
figures(PhosphorIcons.cube, '/figures'),
decks(PhosphorIcons.stack, '/decks'),
backgrounds(PhosphorIcons.image, '/backgrounds'),
translations(PhosphorIcons.translate, '/translations');

final IconGetter icon;
final String location;

const EditorPage(this.icon, this.location);

String get fullLocation => '$kEditorPath$location';
String get route => 'editor-$name';

String getLocalizedName(BuildContext context) {
final loc = AppLocalizations.of(context);
return switch (this) {
Expand All @@ -32,6 +37,16 @@ enum EditorPage {
EditorPage.translations => loc.translations,
};
}

Widget getPage() {
return switch (this) {
EditorPage.general => const GeneralEditorPage(),
EditorPage.figures => const FiguresEditorPage(),
EditorPage.decks => const GeneralEditorPage(),
EditorPage.backgrounds => const GeneralEditorPage(),
EditorPage.translations => const GeneralEditorPage(),
};
}
}

class EditorNavigatorView extends StatelessWidget {
Expand All @@ -44,36 +59,36 @@ class EditorNavigatorView extends StatelessWidget {
this.isMobile = false,
});

void _navigate(BuildContext context, EditorPage page) {
final cubit = context.read<EditorCubit>();
context.goNamed(page.route, pathParameters: {'name': cubit.path});
}

@override
Widget build(BuildContext context) {
if (isMobile) {
return NavigationDrawer(
selectedIndex: currentPage.index + 1,
onDestinationSelected: (value) {},
children: [
return NavigationDrawer(
selectedIndex: currentPage.index + 1,
onDestinationSelected: (value) {
if (value == 0) {
context.go('/');
} else {
_navigate(context, EditorPage.values[value - 1]);
}
},
children: [
if (isMobile) ...[
NavigationDrawerDestination(
icon: Icon(PhosphorIconsLight.arrowLeft),
label: Text(AppLocalizations.of(context).back),
),
const Divider(),
...EditorPage.values.map((e) => NavigationDrawerDestination(
icon: Icon(e.icon(PhosphorIconsStyle.light)),
label: Text(e.getLocalizedName(context)),
selectedIcon: Icon(e.icon(PhosphorIconsStyle.fill)),
)),
],
);
}
return NavigationRail(
destinations: EditorPage.values
.map((e) => NavigationRailDestination(
icon: Icon(e.icon(PhosphorIconsStyle.light)),
label: Text(e.getLocalizedName(context)),
selectedIcon: Icon(e.icon(PhosphorIconsStyle.fill)),
))
.toList(),
selectedIndex: currentPage.index,
extended: true,
...EditorPage.values.map((e) => NavigationDrawerDestination(
icon: Icon(e.icon(PhosphorIconsStyle.light)),
label: Text(e.getLocalizedName(context)),
selectedIcon: Icon(e.icon(PhosphorIconsStyle.fill)),
)),
],
);
}
}
Expand Down Expand Up @@ -151,17 +166,20 @@ class _EditorShellState extends State<EditorShell> {
Widget _buildContent(BuildContext context, SetonixData data) {
final width = MediaQuery.sizeOf(context).width;
final isMobile = width < LeapBreakpoints.medium;
final location = widget.state.path?.substring(kEditorPath.length + 1);
final name = widget.state.fullPath;
final currentPage = EditorPage.values.firstWhere(
(e) => e.location == location,
(e) => e.fullLocation == name,
orElse: () => EditorPage.general,
);
return BlocProvider(
create: (context) =>
EditorCubit(widget.name, context.read<SetonixFileSystem>(), data),
child: Row(
children: [
if (!isMobile) EditorNavigatorView(currentPage: currentPage),
if (!isMobile) ...[
EditorNavigatorView(currentPage: currentPage),
const SizedBox(width: 8)
],
Expanded(
child: Scaffold(
appBar: AppBar(
Expand Down
1 change: 0 additions & 1 deletion app/lib/pages/game/drawer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ class GameDrawer extends StatelessWidget {
if (newInfo == null) return;
bloc.process(MetadataChanged(newInfo.copyWith(
type: metadata.type,
id: metadata.id,
)));
},
),
Expand Down
1 change: 1 addition & 0 deletions metadata/en-US/changelogs/4.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
* Fix importing of packs
* Rework packs dialog
* Upgrade to flutter 3.27
Loading

0 comments on commit a6d0c4b

Please sign in to comment.