mirror of
https://github.com/chenasraf/mudblock.git
synced 2026-05-17 17:48:05 +00:00
feat: button set page wip
This commit is contained in:
@@ -91,3 +91,16 @@ class MUDAction {
|
||||
}
|
||||
}
|
||||
|
||||
class NativeMUDAction extends MUDAction {
|
||||
NativeMUDAction(this.customInvoke)
|
||||
: super('-- native code --', target: MUDActionTarget.script);
|
||||
|
||||
final void Function(GameStore store, Automation parent, List<String> matches)
|
||||
customInvoke;
|
||||
|
||||
@override
|
||||
void invoke(GameStore store, Automation parent, List<String> matches) {
|
||||
customInvoke(store, parent, matches);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import '../platform_utils.dart';
|
||||
import '../store.dart';
|
||||
|
||||
import '../string_utils.dart';
|
||||
import 'action.dart';
|
||||
import 'automation.dart';
|
||||
|
||||
@@ -40,6 +41,12 @@ class GameButtonData {
|
||||
final MUDAction? swipeLeftAction;
|
||||
final MUDAction? swipeRightAction;
|
||||
|
||||
factory GameButtonData.empty() => GameButtonData(
|
||||
id: uuid(),
|
||||
label: GameButtonLabelData.empty(),
|
||||
pressAction: MUDAction.empty(),
|
||||
);
|
||||
|
||||
factory GameButtonData.fromJson(Map<String, dynamic> json) {
|
||||
return GameButtonData(
|
||||
id: json['id'] as String,
|
||||
@@ -77,6 +84,39 @@ class GameButtonData {
|
||||
);
|
||||
}
|
||||
|
||||
GameButtonData copyWith({
|
||||
String? id,
|
||||
GameButtonLabelData? label,
|
||||
GameButtonLabelData? labelUp,
|
||||
GameButtonLabelData? labelDown,
|
||||
GameButtonLabelData? labelLeft,
|
||||
GameButtonLabelData? labelRight,
|
||||
Color? color,
|
||||
double? size,
|
||||
MUDAction? pressAction,
|
||||
MUDAction? longPressAction,
|
||||
MUDAction? swipeUpAction,
|
||||
MUDAction? swipeDownAction,
|
||||
MUDAction? swipeLeftAction,
|
||||
MUDAction? swipeRightAction,
|
||||
}) =>
|
||||
GameButtonData(
|
||||
id: id ?? this.id,
|
||||
label: label ?? this.label,
|
||||
labelUp: labelUp ?? this.labelUp,
|
||||
labelDown: labelDown ?? this.labelDown,
|
||||
labelLeft: labelLeft ?? this.labelLeft,
|
||||
labelRight: labelRight ?? this.labelRight,
|
||||
color: color ?? this.color,
|
||||
size: size ?? this.size,
|
||||
pressAction: pressAction ?? this.pressAction,
|
||||
longPressAction: longPressAction ?? this.longPressAction,
|
||||
swipeUpAction: swipeUpAction ?? this.swipeUpAction,
|
||||
swipeDownAction: swipeDownAction ?? this.swipeDownAction,
|
||||
swipeLeftAction: swipeLeftAction ?? this.swipeLeftAction,
|
||||
swipeRightAction: swipeRightAction ?? this.swipeRightAction,
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'id': id,
|
||||
'label': label.toJson(),
|
||||
@@ -93,6 +133,38 @@ class GameButtonData {
|
||||
'swipeLeftAction': swipeLeftAction?.toJson(),
|
||||
'swipeRightAction': swipeRightAction?.toJson(),
|
||||
};
|
||||
|
||||
MUDAction directionalAction(GameButtonDirection direction) {
|
||||
switch (direction) {
|
||||
case GameButtonDirection.up:
|
||||
return swipeUpAction ?? pressAction;
|
||||
case GameButtonDirection.down:
|
||||
return swipeDownAction ?? pressAction;
|
||||
case GameButtonDirection.left:
|
||||
return swipeLeftAction ?? pressAction;
|
||||
case GameButtonDirection.right:
|
||||
return swipeRightAction ?? pressAction;
|
||||
default:
|
||||
return pressAction;
|
||||
}
|
||||
}
|
||||
|
||||
MUDAction? actionForDirection(GameButtonDirection direction) {
|
||||
switch (direction) {
|
||||
case GameButtonDirection.none:
|
||||
return pressAction;
|
||||
case GameButtonDirection.up:
|
||||
return swipeUpAction;
|
||||
case GameButtonDirection.down:
|
||||
return swipeDownAction;
|
||||
case GameButtonDirection.left:
|
||||
return swipeLeftAction;
|
||||
case GameButtonDirection.right:
|
||||
return swipeRightAction;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class GameButton extends StatefulWidget {
|
||||
@@ -148,7 +220,10 @@ class _GameButtonState extends State<GameButton> with GameStoreStateMixin {
|
||||
const IconThemeData.fallback().size!) /
|
||||
2;
|
||||
|
||||
Widget _listener({required BuildContext context, required Widget child}) {
|
||||
Widget _listener({
|
||||
required BuildContext context,
|
||||
required Widget child,
|
||||
}) {
|
||||
if (PlatformUtils.isDesktop) {
|
||||
return Listener(
|
||||
onPointerDown: _onPointerDown,
|
||||
@@ -221,7 +296,10 @@ class _GameButtonState extends State<GameButton> with GameStoreStateMixin {
|
||||
}
|
||||
|
||||
void _onDragEnd(DragEndDetails details) {
|
||||
// _dragEnd = details.;
|
||||
_callCurrentDirection();
|
||||
setState(() {
|
||||
_direction = GameButtonDirection.none;
|
||||
});
|
||||
}
|
||||
|
||||
void _onPointerUp(PointerUpEvent event) {
|
||||
@@ -277,28 +355,13 @@ class _GameButtonState extends State<GameButton> with GameStoreStateMixin {
|
||||
return direction;
|
||||
}
|
||||
|
||||
MUDAction _directionalAction(GameButtonDirection direction) {
|
||||
switch (direction) {
|
||||
case GameButtonDirection.up:
|
||||
return data.swipeUpAction ?? data.pressAction;
|
||||
case GameButtonDirection.down:
|
||||
return data.swipeDownAction ?? data.pressAction;
|
||||
case GameButtonDirection.left:
|
||||
return data.swipeLeftAction ?? data.pressAction;
|
||||
case GameButtonDirection.right:
|
||||
return data.swipeRightAction ?? data.pressAction;
|
||||
default:
|
||||
return data.pressAction;
|
||||
}
|
||||
}
|
||||
|
||||
void _callAction(MUDAction? action) {
|
||||
final act = action ?? _directionalAction(GameButtonDirection.none);
|
||||
final act = action ?? data.directionalAction(GameButtonDirection.none);
|
||||
act.invoke(store, parentAutomation, []);
|
||||
}
|
||||
|
||||
void _callCurrentDirection() {
|
||||
_callAction(_directionalAction(_direction));
|
||||
_callAction(data.directionalAction(_direction));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,6 +376,8 @@ class GameButtonLabelData {
|
||||
this.iconTheme,
|
||||
}) : assert(label != null || icon != null);
|
||||
|
||||
factory GameButtonLabelData.empty() => GameButtonLabelData(label: '?');
|
||||
|
||||
factory GameButtonLabelData.fromJson(Map<String, dynamic> json) {
|
||||
return GameButtonLabelData(
|
||||
label: json['label'],
|
||||
|
||||
@@ -9,20 +9,20 @@ import 'game_button.dart';
|
||||
class GameButtonSet extends StatelessWidget {
|
||||
const GameButtonSet({
|
||||
super.key,
|
||||
required this.buttonSet,
|
||||
required this.data,
|
||||
});
|
||||
|
||||
final GameButtonSetData buttonSet;
|
||||
final GameButtonSetData data;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Align(
|
||||
alignment: buttonSet.alignment,
|
||||
alignment: data.alignment,
|
||||
child: IconTheme(
|
||||
data: IconTheme.of(context).copyWith(size: 32),
|
||||
child: Builder(
|
||||
builder: (context) {
|
||||
final containerSize = buttonSet.size;
|
||||
final containerSize = data.size;
|
||||
return SizedBox(
|
||||
width: containerSize.width,
|
||||
height: containerSize.height,
|
||||
@@ -35,16 +35,37 @@ class GameButtonSet extends StatelessWidget {
|
||||
}
|
||||
|
||||
Widget _buildButtonContainer(BuildContext context) {
|
||||
final type = buttonSet.type;
|
||||
final crossAxisCount = buttonSet.crossAxisCount;
|
||||
final buttonWidgets = buttonSet.buttons
|
||||
.map(
|
||||
(button) => Padding(
|
||||
padding: EdgeInsets.all(buttonSet.spacing / 2),
|
||||
child: button != null ? GameButton(data: button) : Container(),
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
return buildContainer(
|
||||
context: context,
|
||||
type: data.type,
|
||||
crossAxisCount: data.crossAxisCount,
|
||||
spacing: data.spacing,
|
||||
count: data.buttons.length,
|
||||
size: data.size,
|
||||
alignment: data.alignment,
|
||||
builder: (context, index) => data.buttons[index] != null
|
||||
? GameButton(data: data.buttons[index]!)
|
||||
: Container(),
|
||||
);
|
||||
}
|
||||
|
||||
static Widget buildContainer({
|
||||
required BuildContext context,
|
||||
required GameButtonSetType type,
|
||||
required Widget Function(BuildContext context, int index) builder,
|
||||
required int count,
|
||||
required int? crossAxisCount,
|
||||
required Alignment alignment,
|
||||
required double spacing,
|
||||
required Size size,
|
||||
}) {
|
||||
final buttonWidgets = List.generate(
|
||||
count,
|
||||
(index) => Padding(
|
||||
padding: EdgeInsets.all(spacing / 2),
|
||||
child: builder(context, index),
|
||||
),
|
||||
);
|
||||
switch (type) {
|
||||
case GameButtonSetType.row:
|
||||
return Row(
|
||||
@@ -67,15 +88,15 @@ class GameButtonSet extends StatelessWidget {
|
||||
|
||||
class GameButtonSetData {
|
||||
final String id;
|
||||
final String name;
|
||||
final GameButtonSetType type;
|
||||
final List<GameButtonData?> buttons;
|
||||
final int? crossAxisCount;
|
||||
final Alignment alignment;
|
||||
final double spacing;
|
||||
final String group;
|
||||
String name;
|
||||
GameButtonSetType type;
|
||||
List<GameButtonData?> buttons;
|
||||
int? crossAxisCount;
|
||||
Alignment alignment;
|
||||
double spacing;
|
||||
String group;
|
||||
|
||||
const GameButtonSetData({
|
||||
GameButtonSetData({
|
||||
required this.id,
|
||||
required this.type,
|
||||
required this.name,
|
||||
@@ -86,9 +107,17 @@ class GameButtonSetData {
|
||||
this.group = '',
|
||||
});
|
||||
|
||||
factory GameButtonSetData.empty() => GameButtonSetData(
|
||||
id: uuid(),
|
||||
name: '',
|
||||
type: GameButtonSetType.row,
|
||||
buttons: [],
|
||||
);
|
||||
|
||||
Size get size => Size(calculateWidth(), calculateHeight());
|
||||
|
||||
factory GameButtonSetData.fromJson(Map<String, dynamic> json) => GameButtonSetData(
|
||||
factory GameButtonSetData.fromJson(Map<String, dynamic> json) =>
|
||||
GameButtonSetData(
|
||||
id: json['id'] as String,
|
||||
name: json['name'] as String,
|
||||
type: GameButtonSetType.values.firstWhere(
|
||||
@@ -124,6 +153,27 @@ class GameButtonSetData {
|
||||
'group': group,
|
||||
};
|
||||
|
||||
GameButtonSetData copyWith({
|
||||
String? id,
|
||||
String? name,
|
||||
GameButtonSetType? type,
|
||||
List<GameButtonData?>? buttons,
|
||||
int? crossAxisCount,
|
||||
Alignment? alignment,
|
||||
double? spacing,
|
||||
String? group,
|
||||
}) =>
|
||||
GameButtonSetData(
|
||||
id: id ?? this.id,
|
||||
name: name ?? this.name,
|
||||
type: type ?? this.type,
|
||||
buttons: buttons ?? this.buttons,
|
||||
crossAxisCount: crossAxisCount ?? this.crossAxisCount,
|
||||
alignment: alignment ?? this.alignment,
|
||||
spacing: spacing ?? this.spacing,
|
||||
group: group ?? this.group,
|
||||
);
|
||||
|
||||
double calculateWidth() {
|
||||
switch (type) {
|
||||
case GameButtonSetType.row:
|
||||
|
||||
@@ -155,18 +155,33 @@ class MUDProfile {
|
||||
id, 'aliases/${alias.id}', alias.toJson());
|
||||
}
|
||||
|
||||
Future<void> deleteAlias(Alias alias) async {
|
||||
debugPrint('MUDProfile.deleteAlias: $id/aliases/${alias.id}');
|
||||
return ProfileStorage.deleteProfileFile(id, 'aliases/${alias.id}');
|
||||
}
|
||||
|
||||
Future<void> saveTrigger(Trigger trigger) async {
|
||||
debugPrint('MUDProfile.saveTrigger: $id/triggers/${trigger.id}');
|
||||
return ProfileStorage.writeProfileFile(
|
||||
id, 'triggers/${trigger.id}', trigger.toJson());
|
||||
}
|
||||
|
||||
Future<void> deleteTrigger(Trigger trigger) async {
|
||||
debugPrint('MUDProfile.deleteTrigger: $id/triggers/${trigger.id}');
|
||||
return ProfileStorage.deleteProfileFile(id, 'triggers/${trigger.id}');
|
||||
}
|
||||
|
||||
Future<void> saveButtonSet(GameButtonSetData buttonSet) async {
|
||||
debugPrint('MUDProfile.saveButtonSet: $id/button_sets/${buttonSet.id}');
|
||||
return ProfileStorage.writeProfileFile(
|
||||
id, 'button_sets/${buttonSet.id}', buttonSet.toJson());
|
||||
}
|
||||
|
||||
Future<void> deleteButtonSet(GameButtonSetData buttonSet) async {
|
||||
debugPrint('MUDProfile.deleteButtonSet: $id/button_sets/${buttonSet.id}');
|
||||
return ProfileStorage.deleteProfileFile(id, 'button_sets/${buttonSet.id}');
|
||||
}
|
||||
|
||||
Future<void> saveVariable(List<Variable> current, Variable update) async {
|
||||
debugPrint('MUDProfile.saveVariable: $id/vars');
|
||||
final existing = current.indexWhere(
|
||||
@@ -184,6 +199,21 @@ class MUDProfile {
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> deleteVariable(List<Variable> current, Variable update) async {
|
||||
debugPrint('MUDProfile.deleteVariable: $id/vars');
|
||||
final existing = current.indexWhere(
|
||||
(v) => v.name == update.name,
|
||||
);
|
||||
if (existing >= 0) {
|
||||
current.removeAt(existing);
|
||||
}
|
||||
return ProfileStorage.writeProfileFile(
|
||||
id,
|
||||
'vars',
|
||||
{'vars': current.map((v) => v.toJson()).toList()},
|
||||
);
|
||||
}
|
||||
|
||||
static final encKey = enc.Key.fromUtf8(pwdKey);
|
||||
static final encrypter = enc.Encrypter(enc.AES(encKey, padding: null));
|
||||
|
||||
@@ -221,3 +251,4 @@ enum AuthMethod {
|
||||
none,
|
||||
diku,
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import '../core/features/trigger.dart';
|
||||
import '../core/store.dart';
|
||||
import '../pages/alias_list_page.dart';
|
||||
import '../pages/alias_page.dart';
|
||||
import '../pages/button_set_page.dart';
|
||||
import '../pages/button_sets_list_page.dart';
|
||||
import '../pages/home_page.dart';
|
||||
import '../pages/home_scaffold.dart';
|
||||
@@ -15,6 +16,7 @@ import '../pages/trigger_page.dart';
|
||||
import '../pages/variable_list_page.dart';
|
||||
import '../pages/variable_page.dart';
|
||||
import 'consts.dart';
|
||||
import 'features/game_button_set.dart';
|
||||
import 'features/profile.dart';
|
||||
import 'features/variable.dart';
|
||||
|
||||
@@ -78,6 +80,11 @@ final routes = <String, Widget Function(BuildContext)>{
|
||||
return const ButtonSetListPage();
|
||||
},
|
||||
),
|
||||
Paths.buttonSet: (context) {
|
||||
final buttonSet =
|
||||
ModalRoute.of(context)!.settings.arguments as GameButtonSetData?;
|
||||
return GameButtonSetPage(buttonSet: buttonSet);
|
||||
},
|
||||
Paths.home: (context) => HomeScaffold(
|
||||
builder: (context, _) {
|
||||
return HomePage(key: homeKey);
|
||||
|
||||
@@ -32,6 +32,24 @@ class AliasListPage extends StatelessWidget with GameStoreMixin {
|
||||
save(store, alias);
|
||||
},
|
||||
),
|
||||
trailing: PopupMenuButton(
|
||||
itemBuilder: (context) {
|
||||
return [
|
||||
const PopupMenuItem(
|
||||
value: 'delete',
|
||||
child: Text('Delete'),
|
||||
),
|
||||
];
|
||||
},
|
||||
onSelected: (value) {
|
||||
switch (value) {
|
||||
case 'delete':
|
||||
store.currentProfile.deleteAlias(alias);
|
||||
store.loadAliases();
|
||||
break;
|
||||
}
|
||||
},
|
||||
),
|
||||
onTap: () async {
|
||||
final updated = await Navigator.pushNamed(
|
||||
context,
|
||||
|
||||
262
lib/pages/button_set_page.dart
Normal file
262
lib/pages/button_set_page.dart
Normal file
@@ -0,0 +1,262 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../core/features/action.dart';
|
||||
import '../core/features/game_button.dart';
|
||||
import '../core/features/game_button_set.dart';
|
||||
import '../core/platform_utils.dart';
|
||||
|
||||
class GameButtonSetPage extends StatefulWidget {
|
||||
const GameButtonSetPage({super.key, required this.buttonSet});
|
||||
|
||||
final GameButtonSetData? buttonSet;
|
||||
|
||||
@override
|
||||
State<GameButtonSetPage> createState() => _GameButtonSetPageState();
|
||||
}
|
||||
|
||||
class _GameButtonSetPageState extends State<GameButtonSetPage> {
|
||||
late final GameButtonSetData buttonSet;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
buttonSet = widget.buttonSet?.copyWith() ?? GameButtonSetData.empty();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Button Set'),
|
||||
// actions: [
|
||||
// Switch.adaptive(
|
||||
// value: buttonSet.enabled,
|
||||
// onChanged: (value) {
|
||||
// buttonSet.enabled = value;
|
||||
// },
|
||||
// )
|
||||
// ],
|
||||
),
|
||||
body: Align(
|
||||
alignment: Alignment.topCenter,
|
||||
child: SizedBox(
|
||||
width: 1200,
|
||||
child: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Builder(
|
||||
builder: (context) {
|
||||
return ListView(
|
||||
shrinkWrap: true,
|
||||
children: [
|
||||
TextField(
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Name',
|
||||
),
|
||||
controller: TextEditingController(
|
||||
text: buttonSet.name,
|
||||
),
|
||||
onChanged: (value) {
|
||||
buttonSet.name = value;
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
DropdownMenu(
|
||||
label: const Text('Type'),
|
||||
initialSelection: buttonSet.type,
|
||||
dropdownMenuEntries: GameButtonSetType.values
|
||||
.map(
|
||||
(e) => DropdownMenuEntry(
|
||||
value: e,
|
||||
label: e.name,
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
onSelected: (value) {
|
||||
buttonSet.type = value as GameButtonSetType;
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
ButtonSetEditor(data: buttonSet),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context, buttonSet);
|
||||
},
|
||||
child: const Icon(Icons.save),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ButtonSetEditor extends StatefulWidget {
|
||||
const ButtonSetEditor({
|
||||
super.key,
|
||||
required this.data,
|
||||
});
|
||||
|
||||
final GameButtonSetData? data;
|
||||
|
||||
@override
|
||||
State<ButtonSetEditor> createState() => _ButtonSetEditorState();
|
||||
}
|
||||
|
||||
class _ButtonSetEditorState extends State<ButtonSetEditor> {
|
||||
late final GameButtonSetData data;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
data = widget.data?.copyWith() ?? GameButtonSetData.empty();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _buildContainer(
|
||||
context,
|
||||
(context, index) {
|
||||
final data = this.data.buttons[index];
|
||||
return Container(
|
||||
color: Colors.grey,
|
||||
child: data != null
|
||||
? FakeGameButton(
|
||||
label: data.label,
|
||||
size: data.size ?? GameButtonData.defaultSize,
|
||||
spacing: this.data.spacing,
|
||||
onEdit: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => ButtonEditorDialog(data: data),
|
||||
);
|
||||
},
|
||||
)
|
||||
: Container(),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildContainer(BuildContext context,
|
||||
Widget Function(BuildContext context, int index) builder) {
|
||||
final size = data.size;
|
||||
return Center(
|
||||
child: SizedBox(
|
||||
width: size.width,
|
||||
height: size.height,
|
||||
child: GameButtonSet.buildContainer(
|
||||
context: context,
|
||||
type: data.type,
|
||||
size: data.size,
|
||||
count: data.buttons.length,
|
||||
crossAxisCount: data.crossAxisCount,
|
||||
spacing: data.spacing,
|
||||
alignment: data.alignment,
|
||||
builder: builder,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class FakeGameButton extends StatelessWidget {
|
||||
const FakeGameButton({
|
||||
super.key,
|
||||
required this.label,
|
||||
required this.onEdit,
|
||||
required this.size,
|
||||
required this.spacing,
|
||||
});
|
||||
|
||||
final GameButtonLabelData label;
|
||||
final void Function() onEdit;
|
||||
final double size;
|
||||
final double spacing;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return PopupMenuButton(
|
||||
offset: Offset(0, size),
|
||||
itemBuilder: (context) => const [
|
||||
PopupMenuItem(
|
||||
value: 'edit',
|
||||
child: Text('Edit'),
|
||||
),
|
||||
PopupMenuItem(
|
||||
value: 'delete',
|
||||
child: Text('Delete'),
|
||||
),
|
||||
],
|
||||
onSelected: (value) {
|
||||
if (value == 'edit') {
|
||||
onEdit();
|
||||
}
|
||||
},
|
||||
child: GameButton(
|
||||
data: GameButtonData.empty().copyWith(
|
||||
label: label,
|
||||
pressAction: MUDAction.empty(),
|
||||
longPressAction: MUDAction.empty(),
|
||||
swipeUpAction: MUDAction.empty(),
|
||||
swipeDownAction: MUDAction.empty(),
|
||||
swipeLeftAction: MUDAction.empty(),
|
||||
swipeRightAction: MUDAction.empty(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ButtonEditorDialog extends StatefulWidget {
|
||||
const ButtonEditorDialog({
|
||||
super.key,
|
||||
this.data,
|
||||
});
|
||||
|
||||
final GameButtonData? data;
|
||||
|
||||
@override
|
||||
State<ButtonEditorDialog> createState() => _ButtonEditorDialogState();
|
||||
}
|
||||
|
||||
class _ButtonEditorDialogState extends State<ButtonEditorDialog> {
|
||||
late final GameButtonData data;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
data = widget.data?.copyWith() ?? GameButtonData.empty();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Dialog(
|
||||
child: SizedBox(
|
||||
width: 600,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: ListView(
|
||||
shrinkWrap: true,
|
||||
children: [
|
||||
for (final direction in GameButtonDirection.values)
|
||||
TextFormField(
|
||||
initialValue:
|
||||
data.actionForDirection(direction)?.content ?? '',
|
||||
decoration: InputDecoration(
|
||||
label: Text("${direction.name} action"),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,14 +20,16 @@ class ButtonSetListPage extends StatelessWidget with GameStoreMixin {
|
||||
buttonSet.group,
|
||||
],
|
||||
actions: [
|
||||
DropdownButton(
|
||||
items: const [
|
||||
DropdownMenuItem(
|
||||
value: 'navigation_preset',
|
||||
child: Text('Create Navigation set'),
|
||||
),
|
||||
],
|
||||
onChanged: (value) {
|
||||
PopupMenuButton(
|
||||
itemBuilder: (context) {
|
||||
return [
|
||||
const PopupMenuItem(
|
||||
value: 'navigation_preset',
|
||||
child: Text('Create: Navigation Preset'),
|
||||
),
|
||||
];
|
||||
},
|
||||
onSelected: (value) {
|
||||
switch (value) {
|
||||
case 'navigation_preset':
|
||||
// Navigator.pushNamed(
|
||||
@@ -45,8 +47,7 @@ class ButtonSetListPage extends StatelessWidget with GameStoreMixin {
|
||||
return ListTile(
|
||||
key: Key(buttonSet.id),
|
||||
title: Text(buttonSet.name),
|
||||
// TODO change/remove
|
||||
subtitle: Text(buttonSet.name),
|
||||
// subtitle: Text(buttonSet.name),
|
||||
// leading: Switch.adaptive(
|
||||
// value: buttonSet.enabled,
|
||||
// onChanged: (value) {
|
||||
@@ -54,6 +55,24 @@ class ButtonSetListPage extends StatelessWidget with GameStoreMixin {
|
||||
// save(store, buttonSet);
|
||||
// },
|
||||
// ),
|
||||
trailing: PopupMenuButton(
|
||||
itemBuilder: (context) {
|
||||
return [
|
||||
const PopupMenuItem(
|
||||
value: 'delete',
|
||||
child: Text('Delete'),
|
||||
),
|
||||
];
|
||||
},
|
||||
onSelected: (value) {
|
||||
switch (value) {
|
||||
case 'delete':
|
||||
store.currentProfile.deleteButtonSet(buttonSet);
|
||||
store.loadButtonSets();
|
||||
break;
|
||||
}
|
||||
},
|
||||
),
|
||||
onTap: () async {
|
||||
final updated = await Navigator.pushNamed(
|
||||
context,
|
||||
|
||||
@@ -109,7 +109,7 @@ class HomePageState extends State<HomePage>
|
||||
for (final buttonSet in store.buttonSets)
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: GameButtonSet(buttonSet: buttonSet),
|
||||
child: GameButtonSet(data: buttonSet),
|
||||
)
|
||||
],
|
||||
),
|
||||
|
||||
@@ -32,6 +32,24 @@ class TriggerListPage extends StatelessWidget with GameStoreMixin {
|
||||
save(store, trigger);
|
||||
},
|
||||
),
|
||||
trailing: PopupMenuButton(
|
||||
itemBuilder: (context) {
|
||||
return [
|
||||
const PopupMenuItem(
|
||||
value: 'delete',
|
||||
child: Text('Delete'),
|
||||
),
|
||||
];
|
||||
},
|
||||
onSelected: (value) {
|
||||
switch (value) {
|
||||
case 'delete':
|
||||
store.currentProfile.deleteTrigger(trigger);
|
||||
store.loadTriggers();
|
||||
break;
|
||||
}
|
||||
},
|
||||
),
|
||||
onTap: () async {
|
||||
final updated = await Navigator.pushNamed(
|
||||
context,
|
||||
|
||||
Reference in New Issue
Block a user