Merge pull request #100 from AnonymusRaccoon/mobile_client_service_safety

Mobile client: service safety
This commit is contained in:
Zoe Roux
2022-03-05 15:48:53 +01:00
committed by GitHub
10 changed files with 93 additions and 39 deletions
+4 -1
View File
@@ -43,5 +43,8 @@
"tryToConnect": "Try to connect",
"routeToApi": "Route to API",
"setupAPIRoute": "Setup API Route",
"paramInheritTip": "To inherit parameters from previous actions, type '{' in the text field and tap on the choosen parameter"
"paramInheritTip": "To inherit parameters from previous actions, type '{' in the text field and tap on the choosen parameter",
"authenticatedToNoService": "You are not authenticated to any services.",
"connectService": "Connect service",
"cantEnablePipeline": "You can't enable this pipeline because it depends on a service that is not connected"
}
+4 -1
View File
@@ -43,5 +43,8 @@
"tryToConnect": "Tester la connection",
"routeToApi": "Route de l'API",
"setupAPIRoute": "Choisir la route de l'API",
"paramInheritTip": "Afin d'hériter de variables venant d'actions précedentes, entrez '{' dans un champ et choisissez la valeur"
"paramInheritTip": "Afin d'hériter de variables venant d'actions précedentes, entrez '{' dans un champ et choisissez la valeur",
"authenticatedToNoService": "Aucun service n'est connecté",
"connectService": "Connexion aux services",
"cantEnablePipeline": "Impossible d'activer la pipeline car elle dépend d'un service qui n'est pas connecté"
}
-3
View File
@@ -50,9 +50,6 @@ class AerisAPI {
deepLinkRoute = "$scheme://arthichaud.me";
}
/// Name of the file that contains the JWT used for Aeris' API requestd
static const String jwtFile = 'aeris_jwt.txt';
///ROUTES
/// Registers new user in the database and connects it. Returns false if register failed
Future<bool> signUpUser(String username, String password) async {
+5
View File
@@ -1,3 +1,4 @@
import 'package:aeris/src/models/service.dart';
import 'package:flutter/material.dart';
import 'package:aeris/src/models/reaction.dart';
import 'package:aeris/src/models/trigger.dart';
@@ -58,4 +59,8 @@ class Pipeline {
},
'reactions': reactions.map((e) => e.toJSON()).toList()
};
bool dependsOn(Service service) {
return service == trigger.service || reactions.any((reaction) => reaction.service == service);
}
}
@@ -10,7 +10,7 @@ class ServiceProvider extends ChangeNotifier {
List<Service> get connectedServices => _connectedServices;
/// Get the services the user is not connected to
List<Service> get availableServices => Service.all()
List<Service> get disconnectedServices => Service.all()
.where((element) => !_connectedServices.contains(element))
.toList();
+23 -6
View File
@@ -1,5 +1,7 @@
import 'package:aeris/src/aeris_api.dart';
import 'package:aeris/src/providers/pipelines_provider.dart';
import 'package:aeris/src/providers/services_provider.dart';
import 'package:aeris/src/views/service_page.dart';
import 'package:aeris/src/views/setup_action_page.dart';
import 'package:aeris/src/widgets/action_card_popup_menu.dart';
import 'package:aeris/src/widgets/aeris_card_page.dart';
@@ -28,7 +30,8 @@ class PipelineDetailPage extends StatefulWidget {
class _PipelineDetailPageState extends State<PipelineDetailPage> {
@override
Widget build(BuildContext context) =>
Consumer<PipelineProvider>(builder: (context, provider, _) {
Consumer<ServiceProvider>(builder: (context, services, _) {
return Consumer<PipelineProvider>(builder: (context, provider, _) {
Pipeline pipeline = widget.pipeline;
final cardHeader = Row(
@@ -67,11 +70,24 @@ class _PipelineDetailPageState extends State<PipelineDetailPage> {
width: 60,
value: pipeline.enabled,
onToggle: (value) {
setState(() {
pipeline.enabled = !pipeline.enabled;
GetIt.I<AerisAPI>().editPipeline(pipeline);
provider.sortPipelines();
});
if (!pipeline.enabled && services.disconnectedServices.any(
(service) => pipeline.dependsOn(service))
) {
showDialog<String>(
context: context,
builder: (BuildContext context) => WarningDialog(
message: AppLocalizations.of(context).cantEnablePipeline,
onAccept: () => showAerisCardPage(context, (_) => const ServicePage()),
actionButtonColor: Theme.of(context).colorScheme.secondaryContainer,
warnedAction: AppLocalizations.of(context).connectService)
);
} else {
setState(() {
pipeline.enabled = !pipeline.enabled;
GetIt.I<AerisAPI>().editPipeline(pipeline);
provider.sortPipelines();
});
}
},
),
),
@@ -184,4 +200,5 @@ class _PipelineDetailPageState extends State<PipelineDetailPage> {
]),
));
});
});
}
+1 -1
View File
@@ -67,7 +67,7 @@ class ServicePage extends StatelessWidget {
warnedAction: AppLocalizations.of(context).disconnect)),
context),
...getServiceGroup(
serviceProvider.availableServices,
serviceProvider.disconnectedServices,
AppLocalizations.of(context).available,
const Icon(Icons.connect_without_contact, color: Colors.green),
(Service service) {
+38 -14
View File
@@ -3,6 +3,9 @@ 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:aeris/src/providers/services_provider.dart';
import 'package:aeris/src/views/service_page.dart';
import 'package:aeris/src/widgets/colored_clickable_card.dart';
import 'package:flutter/material.dart';
import 'package:aeris/src/models/action.dart' as aeris;
import 'package:aeris/src/models/service.dart';
@@ -11,6 +14,7 @@ import 'package:aeris/src/widgets/aeris_card_page.dart';
import 'package:expandable/expandable.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:get_it/get_it.dart';
import 'package:provider/provider.dart';
import 'package:skeleton_loader/skeleton_loader.dart';
///Page to setup an action
@@ -43,13 +47,11 @@ class _SetupActionPageState extends State<SetupActionPage> {
void initState() {
super.initState();
serviceState = widget.action.service;
availableActions =
GetIt.I<AerisAPI>().getActionsFor(serviceState!, widget.action);
availableActions = GetIt.I<AerisAPI>().getActionsFor(serviceState!, widget.action);
}
@override
Widget build(BuildContext context) {
final Widget serviceDropdown = DropdownButton<Service>(
Widget serviceDropdown(List<Service> services) {
return DropdownButton<Service>(
value: serviceState,
elevation: 8,
underline: Container(),
@@ -60,7 +62,7 @@ class _SetupActionPageState extends State<SetupActionPage> {
GetIt.I<AerisAPI>().getActionsFor(service!, widget.action);
});
},
items: Service.all().map<DropdownMenuItem<Service>>((Service service) {
items: services.map<DropdownMenuItem<Service>>((Service service) {
return DropdownMenuItem<Service>(
value: service,
child: Row(children: [
@@ -74,20 +76,42 @@ class _SetupActionPageState extends State<SetupActionPage> {
);
}).toList(),
);
}
@override
Widget build(BuildContext context) {
var cardShape = const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(10)));
return AerisCardPage(
body: Padding(
body: Consumer<ServiceProvider>(builder: (context, services, _) => Padding(
padding: const EdgeInsets.only(bottom: 20, left: 10, right: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
widget.action is Trigger
? AppLocalizations.of(context).setupTrigger
: AppLocalizations.of(context).setupReaction,
children: services.connectedServices.isEmpty ?
([
Text(AppLocalizations.of(context).authenticatedToNoService,
style: const TextStyle(
fontSize: 25,
)
),
Padding(padding: const EdgeInsets.all(30),
child: ColoredClickableCard(
color: Theme.of(context)
.colorScheme
.secondaryContainer,
text:AppLocalizations.of(context).connectService,
onTap: () => showAerisCardPage(
context, (_) => const ServicePage()).then((value) => setState((){}) //TODO check, might be useless
)
)
)
])
: [
Text(widget.action is Trigger
? AppLocalizations.of(context).setupTrigger
: AppLocalizations.of(context).setupReaction,
style: const TextStyle(
fontSize: 25,
)),
@@ -106,7 +130,7 @@ class _SetupActionPageState extends State<SetupActionPage> {
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Align(
alignment: Alignment.centerRight, child: serviceDropdown),
alignment: Alignment.centerRight, child: serviceDropdown(services.connectedServices)),
),
),
],
@@ -175,6 +199,6 @@ class _SetupActionPageState extends State<SetupActionPage> {
]
],
),
));
)));
}
}
@@ -87,7 +87,9 @@ class _AnimatedBackgroundState extends State<AnimatedBackground> with TickerProv
});
Timer(const Duration(milliseconds: 2500), () {
topAnimController.forward();
try {
topAnimController.forward();
} catch (e) {}
});
bottomAnimController.forward();
+14 -11
View File
@@ -1,3 +1,4 @@
import 'package:aeris/main.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
@@ -11,13 +12,18 @@ class WarningDialog extends StatelessWidget {
///The action to execute once the warning was accepted
final void Function() onAccept;
///Color of the button that trigger the action
Color? actionButtonColor;
const WarningDialog(
WarningDialog(
{Key? key,
required this.message,
this.actionButtonColor,
required this.onAccept,
required this.warnedAction})
: super(key: key);
: super(key: key) {
actionButtonColor ??= Theme.of(Aeris.materialKey.currentContext!).colorScheme.error;
}
@override
Widget build(BuildContext context) {
@@ -28,27 +34,24 @@ class WarningDialog extends StatelessWidget {
)
),
content: Text(message),
actionsAlignment: MainAxisAlignment.spaceEvenly,
actionsOverflowDirection: VerticalDirection.up,
actions: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Theme.of(context).colorScheme.primaryContainer),
onPressed: () => Navigator.pop(context),
child: Text(AppLocalizations.of(context).cancel),
),
ElevatedButton(
ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Theme.of(context).colorScheme.error),
primary: actionButtonColor),
onPressed: () => {
Navigator.pop(context),
onAccept(),
},
child: Text(warnedAction)
)
],
),
]);
]);
}
}