mirror of
https://github.com/zoriya/Aeris.git
synced 2026-06-06 03:55:43 +00:00
Mobile Client: Form: inherit reutrn from preceding actions
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
PODS:
|
||||
- Flutter (1.0.0)
|
||||
- flutter_keyboard_visibility (0.0.1):
|
||||
- Flutter
|
||||
- FMDB (2.7.5):
|
||||
- FMDB/standard (= 2.7.5)
|
||||
- FMDB/standard (2.7.5)
|
||||
@@ -15,6 +17,7 @@ PODS:
|
||||
|
||||
DEPENDENCIES:
|
||||
- Flutter (from `Flutter`)
|
||||
- flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`)
|
||||
- path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`)
|
||||
- shared_preferences_ios (from `.symlinks/plugins/shared_preferences_ios/ios`)
|
||||
- sqflite (from `.symlinks/plugins/sqflite/ios`)
|
||||
@@ -27,6 +30,8 @@ SPEC REPOS:
|
||||
EXTERNAL SOURCES:
|
||||
Flutter:
|
||||
:path: Flutter
|
||||
flutter_keyboard_visibility:
|
||||
:path: ".symlinks/plugins/flutter_keyboard_visibility/ios"
|
||||
path_provider_ios:
|
||||
:path: ".symlinks/plugins/path_provider_ios/ios"
|
||||
shared_preferences_ios:
|
||||
@@ -38,6 +43,7 @@ EXTERNAL SOURCES:
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a
|
||||
flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069
|
||||
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
|
||||
path_provider_ios: 7d7ce634493af4477d156294792024ec3485acd5
|
||||
shared_preferences_ios: 548a61f8053b9b8a49ac19c1ffbc8b92c50d68ad
|
||||
|
||||
@@ -79,8 +79,10 @@ class _CreatePipelinePageState extends State<CreatePipelinePage> {
|
||||
onTap: () {
|
||||
showAerisCardPage(
|
||||
context,
|
||||
(_) =>
|
||||
SetupActionPage(action: trigger))
|
||||
(_) => SetupActionPage(
|
||||
action: trigger,
|
||||
parentReactions: reactions
|
||||
))
|
||||
.then((_) => setState(() {}));
|
||||
})
|
||||
: ActionCard(
|
||||
@@ -88,6 +90,8 @@ class _CreatePipelinePageState extends State<CreatePipelinePage> {
|
||||
title: trigger.displayName(),
|
||||
trailing: ActionCardPopupMenu(
|
||||
deletable: false,
|
||||
parentReactions: reactions,
|
||||
parentTrigger: trigger,
|
||||
action: trigger,
|
||||
then: () => setState(() {})),
|
||||
),
|
||||
@@ -106,6 +110,8 @@ class _CreatePipelinePageState extends State<CreatePipelinePage> {
|
||||
leading: reaction.service.getLogo(logoSize: 50),
|
||||
title: reaction.displayName(),
|
||||
trailing: ActionCardPopupMenu(
|
||||
parentTrigger: trigger == Trigger.template() ? null : trigger,
|
||||
parentReactions: reactions,
|
||||
deletable: reactions.length > 1,
|
||||
action: reaction,
|
||||
then: () => setState(() {}),
|
||||
@@ -128,7 +134,10 @@ class _CreatePipelinePageState extends State<CreatePipelinePage> {
|
||||
showAerisCardPage(
|
||||
context,
|
||||
(_) => SetupActionPage(
|
||||
action: newreact))
|
||||
action: newreact,
|
||||
parentReactions: reactions,
|
||||
parentTrigger: trigger == Trigger.template() ? null : trigger,
|
||||
))
|
||||
.then((_) => setState(() {
|
||||
if (newreact != Reaction.template()) {
|
||||
reactions.add(newreact);
|
||||
|
||||
@@ -95,7 +95,12 @@ class _PipelineDetailPageState extends State<PipelineDetailPage> {
|
||||
onTap: () {
|
||||
Reaction newreaction = Reaction.template();
|
||||
showAerisCardPage(
|
||||
context, (_) => SetupActionPage(action: newreaction))
|
||||
context, (_) => SetupActionPage(
|
||||
action: newreaction,
|
||||
parentTrigger: pipeline.trigger,
|
||||
parentReactions: pipeline.reactions,
|
||||
)
|
||||
)
|
||||
.then((r) {
|
||||
if (newreaction != Reaction.template()) {
|
||||
setState(() {
|
||||
@@ -138,6 +143,8 @@ class _PipelineDetailPageState extends State<PipelineDetailPage> {
|
||||
title: pipeline.trigger.displayName(),
|
||||
trailing: ActionCardPopupMenu(
|
||||
deletable: false,
|
||||
parentTrigger: pipeline.trigger,
|
||||
parentReactions: pipeline.reactions,
|
||||
action: pipeline.trigger,
|
||||
then: () {
|
||||
setState(() {});
|
||||
@@ -154,6 +161,8 @@ class _PipelineDetailPageState extends State<PipelineDetailPage> {
|
||||
leading: reaction.service.getLogo(logoSize: 50),
|
||||
title: reaction.displayName(),
|
||||
trailing: ActionCardPopupMenu(
|
||||
parentTrigger: pipeline.trigger,
|
||||
parentReactions: pipeline.reactions,
|
||||
deletable: pipeline.reactions.length > 1,
|
||||
action: reaction,
|
||||
then: () {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:aeris/src/models/action_parameter.dart';
|
||||
import 'package:aeris/src/models/action_template.dart';
|
||||
import 'package:aeris/src/aeris_api.dart';
|
||||
import 'package:aeris/src/models/reaction.dart';
|
||||
import 'package:aeris/src/models/trigger.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:aeris/src/models/action.dart' as aeris;
|
||||
@@ -14,10 +15,15 @@ import 'package:skeleton_loader/skeleton_loader.dart';
|
||||
|
||||
///Page to setup an action
|
||||
class SetupActionPage extends StatefulWidget {
|
||||
const SetupActionPage({Key? key, required this.action}) : super(key: key);
|
||||
const SetupActionPage({Key? key, required this.action, required this.parentReactions, this.parentTrigger}) : super(key: key);
|
||||
|
||||
/// Action to setup
|
||||
final aeris.Action action;
|
||||
/// Trigger of Parent of the action to setup
|
||||
final Trigger? parentTrigger;
|
||||
|
||||
/// reactions of Parent of the action to setup
|
||||
final List<Reaction> parentReactions;
|
||||
|
||||
@override
|
||||
State<SetupActionPage> createState() => _SetupActionPageState();
|
||||
@@ -120,6 +126,9 @@ class _SetupActionPageState extends State<SetupActionPage> {
|
||||
expanded: Padding(
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: ActionForm(
|
||||
reactionsCandidates: widget.parentReactions,
|
||||
triggerCandidate: widget.parentTrigger,
|
||||
candidate: widget.action,
|
||||
key: Key("${availableAction.name}${availableAction.description}${availableAction.service}"),
|
||||
description: availableAction.description!,
|
||||
name: availableAction.name,
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'package:aeris/src/models/reaction.dart';
|
||||
import 'package:aeris/src/models/trigger.dart';
|
||||
import 'package:aeris/src/widgets/aeris_card_page.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:aeris/src/views/setup_action_page.dart';
|
||||
@@ -11,6 +13,8 @@ class ActionCardPopupMenu extends StatelessWidget {
|
||||
ActionCardPopupMenu({
|
||||
Key? key,
|
||||
required this.action,
|
||||
this.parentTrigger,
|
||||
required this.parentReactions,
|
||||
required this.then,
|
||||
required this.deletable,
|
||||
this.onDelete,
|
||||
@@ -22,6 +26,10 @@ class ActionCardPopupMenu extends StatelessWidget {
|
||||
|
||||
/// Selected Action
|
||||
final aeris.Action action;
|
||||
/// Trigger of the Parent of the action
|
||||
final Trigger? parentTrigger;
|
||||
/// Trigger of the Parent of the action
|
||||
final List<Reaction> parentReactions;
|
||||
|
||||
/// Function to trigger once the Edit menu is closed
|
||||
final void Function() then;
|
||||
@@ -46,15 +54,18 @@ class ActionCardPopupMenu extends StatelessWidget {
|
||||
icon: Icons.settings,
|
||||
title: AppLocalizations.of(context).modify,
|
||||
value: () => showAerisCardPage(
|
||||
context, (_) => SetupActionPage(action: action)).then((_) => then())
|
||||
),
|
||||
context, (_) => SetupActionPage(
|
||||
action: action,
|
||||
parentTrigger: parentTrigger,
|
||||
parentReactions: parentReactions,
|
||||
))
|
||||
.then((_) => then())),
|
||||
AerisPopupMenuItem(
|
||||
context: context,
|
||||
icon: Icons.delete,
|
||||
title: AppLocalizations.of(context).delete,
|
||||
value: onDelete,
|
||||
enabled: deletable
|
||||
),
|
||||
context: context,
|
||||
icon: Icons.delete,
|
||||
title: AppLocalizations.of(context).delete,
|
||||
value: onDelete,
|
||||
enabled: deletable),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
import 'package:aeris/src/models/action_parameter.dart';
|
||||
import 'package:aeris/src/models/action_template.dart';
|
||||
import 'package:aeris/src/models/reaction.dart';
|
||||
import 'package:aeris/src/models/action.dart' as aeris;
|
||||
import 'package:aeris/src/models/trigger.dart';
|
||||
import 'package:aeris/src/providers/action_catalogue_provider.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_form_builder/flutter_form_builder.dart';
|
||||
import 'package:flutter_typeahead/flutter_typeahead.dart';
|
||||
import 'package:form_builder_validators/form_builder_validators.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:recase/recase.dart';
|
||||
import 'package:tuple/tuple.dart';
|
||||
|
||||
/// Form for an action
|
||||
class ActionForm extends StatefulWidget {
|
||||
@@ -14,6 +21,13 @@ class ActionForm extends StatefulWidget {
|
||||
/// What the action does
|
||||
final String description;
|
||||
|
||||
/// The Action that will be eventually filled by the form
|
||||
final aeris.Action candidate;
|
||||
/// The trigger candidate in the parent form page
|
||||
final Trigger? triggerCandidate;
|
||||
/// The trigger candidate in the parent form page
|
||||
final List<Reaction> reactionsCandidates;
|
||||
|
||||
/// On validate callback
|
||||
final void Function(Map<String, String>) onValidate;
|
||||
|
||||
@@ -22,7 +36,11 @@ class ActionForm extends StatefulWidget {
|
||||
required this.name,
|
||||
required this.description,
|
||||
required this.parameters,
|
||||
required this.onValidate})
|
||||
required this.onValidate,
|
||||
required this.candidate,
|
||||
this.triggerCandidate,
|
||||
required this.reactionsCandidates,
|
||||
})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
@@ -30,34 +48,93 @@ class ActionForm extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _ActionFormState extends State<ActionForm> {
|
||||
final _formKey = GlobalKey<FormBuilderState>();
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
Map<String, String> formValues = {};
|
||||
|
||||
List getSuggestions(String pattern, ActionCatalogueProvider catalogue) {
|
||||
List<Tuple3<int, ActionParameter, ActionTemplate>> suggestions = [];
|
||||
if (pattern.endsWith("#") == false) return suggestions;
|
||||
print(widget.candidate.runtimeType);
|
||||
if (widget.candidate is Trigger) return suggestions;
|
||||
if (widget.triggerCandidate != null) {
|
||||
Trigger trigger = widget.triggerCandidate!;
|
||||
///TODO Dumb ass; look for returns instead of param
|
||||
var triggerTemplate = catalogue.triggerTemplates[trigger.service]!.firstWhere(
|
||||
(element) => element.name == trigger.name
|
||||
);
|
||||
for (var parameter in triggerTemplate.returnedValues) {
|
||||
suggestions.add(Tuple3(0, parameter, triggerTemplate));
|
||||
}
|
||||
}
|
||||
int index = 1;
|
||||
for (var reactionCandidate in widget.reactionsCandidates) {
|
||||
var reactionTemplate = catalogue.triggerTemplates[reactionCandidate.service]!.firstWhere(
|
||||
(element) => element.name == reactionCandidate.name
|
||||
);
|
||||
for (var parameter in reactionTemplate.returnedValues) {
|
||||
suggestions.add(Tuple3(index, parameter, reactionTemplate));
|
||||
}
|
||||
index++;
|
||||
}
|
||||
print(index);
|
||||
suggestions.forEach((element) => print(element.item2.name));
|
||||
return suggestions;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FormBuilder(
|
||||
return Consumer<ActionCatalogueProvider>(
|
||||
builder: (__, catalogue, _) => Form(
|
||||
key: _formKey,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Text(widget.description, textAlign: TextAlign.left, style: TextStyle(color: Theme.of(context).colorScheme.onSurface)),
|
||||
...widget.parameters.map((param) => FormBuilderTextField(
|
||||
initialValue: param.value?.toString(),
|
||||
name: param.name,
|
||||
decoration: InputDecoration(
|
||||
labelText: ReCase(param.name).titleCase,
|
||||
helperText: param.description
|
||||
),
|
||||
validator: FormBuilderValidators.compose([
|
||||
FormBuilderValidators.required(context),
|
||||
]),
|
||||
)),
|
||||
...widget.parameters.map((param) {
|
||||
return TypeAheadFormField(
|
||||
initialValue: formValues[param.name] ?? param.value?.toString(),
|
||||
validator: FormBuilderValidators.compose([
|
||||
FormBuilderValidators.required(context),
|
||||
]),
|
||||
hideOnEmpty: true,
|
||||
textFieldConfiguration: TextFieldConfiguration(
|
||||
decoration: InputDecoration(
|
||||
labelText: ReCase(param.name).titleCase,
|
||||
helperText: param.description
|
||||
),
|
||||
),
|
||||
suggestionsCallback: (suggestion) => getSuggestions(suggestion, catalogue),
|
||||
noItemsFoundBuilder: (_) => Container(),
|
||||
onSuggestionSelected: (suggestion) {
|
||||
var parameterSuggestion = suggestion as Tuple3<int, ActionParameter, ActionTemplate>;
|
||||
String content = formValues[param.name]!;
|
||||
content += "{${parameterSuggestion.item2}@${parameterSuggestion.item1}}";
|
||||
print(content);
|
||||
setState(() {
|
||||
formValues[param.name] = content;
|
||||
});
|
||||
},
|
||||
itemBuilder: (context, input) {
|
||||
var suggestion = input as Tuple3<int, ActionParameter, ActionTemplate>;
|
||||
return ListTile(
|
||||
isThreeLine: true,
|
||||
leading: suggestion.item3.service.getLogo(logoSize: 30),
|
||||
title: Text(suggestion.item2.name),
|
||||
subtitle: Text("${suggestion.item2.description}, from '${suggestion.item3.displayName()}'")
|
||||
);
|
||||
},
|
||||
onSaved: (value) => setState(() {
|
||||
formValues[param.name] = value!;
|
||||
}),
|
||||
);
|
||||
}),
|
||||
...[
|
||||
ElevatedButton(
|
||||
child: Text(AppLocalizations.of(context).save),
|
||||
onPressed: () {
|
||||
_formKey.currentState!.save();
|
||||
if (_formKey.currentState!.validate()) {
|
||||
widget.onValidate(_formKey.currentState!.value.map((key, value) => MapEntry(key, value)));
|
||||
_formKey.currentState!.save();
|
||||
widget.onValidate(formValues.map((key, value) => MapEntry(key, value)));
|
||||
}
|
||||
},
|
||||
),
|
||||
@@ -65,6 +142,6 @@ class _ActionFormState extends State<ActionForm> {
|
||||
]
|
||||
]
|
||||
)
|
||||
);
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user