mirror of
https://github.com/zoriya/Aeris.git
synced 2026-06-07 12:26:13 +00:00
Mobile client: Translation System
Mobile client: Translation System
This commit is contained in:
@@ -11,5 +11,7 @@ COPY pubspec.* ./
|
||||
RUN flutter pub get
|
||||
|
||||
COPY . .
|
||||
# Generate traduction files
|
||||
RUN fkutter gen-l10n
|
||||
RUN flutter build apk lib/src/main.dart
|
||||
CMD mv ./build/app/outputs/flutter-apk/app-release.apk /dist/aeris_android.apk
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
arb-dir: lib/l10n
|
||||
template-arb-file: app_en.arb
|
||||
output-localization-file: app_localizations.dartà
|
||||
output-localization-file: app_localizations.dart
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"helloWorld": "Hello World!",
|
||||
"@helloWorld": {
|
||||
"description": "The conventional newborn programmer greeting"
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"helloWorld": "Bonjour, monde!",
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"helloWorld": "Hello World!",
|
||||
"lastTrigger": "Last",
|
||||
"never": "Never",
|
||||
"nDaysAgo": "n days ago",
|
||||
"today": "Today",
|
||||
"nameOfThePipeline": "Name of the pipeline",
|
||||
"addReaction": "Add a Reaction",
|
||||
"addTrigger": "Add a Trigger",
|
||||
"modify": "Modify",
|
||||
"delete": "Delete",
|
||||
"services": "Services",
|
||||
"logout": "Logout",
|
||||
"usernameOrPasswordIncorrect": "Username or password is incorrect",
|
||||
"userDoesNotExist": "User does not exist",
|
||||
"enabled": "Enabled",
|
||||
"disabled": "Disabled",
|
||||
"disconnect": "Disconnect",
|
||||
"deletePipeline": "Delete Pipeline",
|
||||
"connected": "Connected",
|
||||
"connect": "Connect",
|
||||
"available": "Available",
|
||||
"disconnectServiceWarningMessage": "You are about to disconnect to a service. Once disconnected, every related pipeline will be deleted. This action cannot be undone.",
|
||||
"deletePipelineWarningMessage": "You are about to delete a pipeline. This action can not be undone. Are you sure ?",
|
||||
"avalableActionsFor": "available actions for",
|
||||
"mergeDisabledPipelines": "Merge disabled pipelines",
|
||||
"seperateDisabledPipelines": "Seperate disabled pipelines",
|
||||
"aerisDescription": "Aeris is the best AREA in Nantes! Control each of your social network with Aeris, your new Action / Reaction app."
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"helloWorld": "Bonjour le monde!",
|
||||
"lastTrigger": "Dernière",
|
||||
"never": "Jamais",
|
||||
"nDaysAgo": " jours",
|
||||
"today": "Aujourd'hui",
|
||||
"nameOfThePipeline": "Nom de la pipeline",
|
||||
"addReaction": "Ajouter une Reaction",
|
||||
"addTrigger": "Ajouter un Déclancheur",
|
||||
"modify": "Modifier",
|
||||
"delete": "Supprimer",
|
||||
"services": "Services",
|
||||
"logout": "Se Deconnecter",
|
||||
"usernameOrPasswordIncorrect": "Nom d'utilisateur ou mot de passe incorrect",
|
||||
"userDoesNotExist": "L'utilisateur n'existe pas",
|
||||
"enabled": "Activé",
|
||||
"disabled": "Désactivé",
|
||||
"disconnect": "Déconnecter",
|
||||
"deletePipeline": "Supprimer la Pipeline",
|
||||
"connected": "Connecté",
|
||||
"connect": "Se Connecter",
|
||||
"available": "Disponible",
|
||||
"disconnectServiceWarningMessage": "Vous allez supprimer un service. Une fois fait, toutes les pipelines associées seront supprimées. Cela ne peut pas être annulé.",
|
||||
"deletePipelineWarningMessage": "Vous allez supprimer une pipeline. Cela ne peut pas être annulé.",
|
||||
"avalableActionsFor": "Actions disponibles pour",
|
||||
"mergeDisabledPipelines": "Mélanger les pipelines désactivées",
|
||||
"seperateDisabledPipelines": "Séparer les pipelines désactivées",
|
||||
"aerisDescription": "Aeris est le meilleur AREA de Nantes! Prennez le contrôle de vos réseaux sociaux avec Aeris, la nouvelle application de pipeline!"
|
||||
}
|
||||
+32
-30
@@ -12,35 +12,35 @@ import 'package:mobile/src/views/home_page.dart';
|
||||
import 'package:mobile/src/constants.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
void main() {
|
||||
runApp(
|
||||
MultiProvider(
|
||||
providers: [
|
||||
ChangeNotifierProvider(create: (_) => PipelineProvider()),
|
||||
ChangeNotifierProvider(create: (_) => UserServiceProvider())
|
||||
],
|
||||
child: const MyApp()
|
||||
)
|
||||
);
|
||||
runApp(MultiProvider(providers: [
|
||||
ChangeNotifierProvider(create: (_) => PipelineProvider()),
|
||||
ChangeNotifierProvider(create: (_) => UserServiceProvider())
|
||||
], child: const Aeris()));
|
||||
}
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
const MyApp({Key? key}) : super(key: key);
|
||||
class Aeris extends StatelessWidget {
|
||||
static GlobalKey<NavigatorState> materialKey = GlobalKey<NavigatorState>();
|
||||
const Aeris({Key? key}) : super(key: key);
|
||||
|
||||
///This widget is the root of your application.
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
locale: const Locale('fr', ''),
|
||||
navigatorKey: Aeris.materialKey,
|
||||
debugShowCheckedModeBanner: false,
|
||||
title: 'Aeris',
|
||||
localizationsDelegates: const [
|
||||
AppLocalizations.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
FormBuilderLocalizations.delegate
|
||||
],
|
||||
supportedLocales: const [Locale('en', ''), Locale('fr', '')],
|
||||
supportedLocales: const [Locale('fr', ''), Locale('en', '')],
|
||||
theme: ThemeData(colorScheme: aerisScheme),
|
||||
initialRoute: '/',
|
||||
onGenerateRoute: (settings) {
|
||||
@@ -60,23 +60,25 @@ class MyApp extends StatelessWidget {
|
||||
..addAll(cardRoutes)
|
||||
..addAll(pageRoutes);
|
||||
return PageRouteBuilder(
|
||||
opaque: false,
|
||||
settings: settings,
|
||||
pageBuilder: (_, __, ___) => routes[settings.name].call(),
|
||||
transitionDuration: const Duration(milliseconds: 350),
|
||||
transitionsBuilder: (context, animation, secondaryAnimation, child) =>
|
||||
pageRoutes.containsKey(settings.name) ? ScaleTransition(
|
||||
child: child,
|
||||
scale: CurvedAnimation(
|
||||
parent: animation,
|
||||
curve: Curves.ease,
|
||||
)
|
||||
) : SlideTransition(
|
||||
position: animation.drive(Tween(begin: const Offset(0, 1), end: Offset.zero).chain(CurveTween(curve: Curves.ease))),
|
||||
child: child,
|
||||
)
|
||||
);
|
||||
}
|
||||
);
|
||||
opaque: false,
|
||||
settings: settings,
|
||||
pageBuilder: (_, __, ___) => routes[settings.name].call(),
|
||||
transitionDuration: const Duration(milliseconds: 350),
|
||||
transitionsBuilder: (context, animation, secondaryAnimation,
|
||||
child) =>
|
||||
pageRoutes.containsKey(settings.name)
|
||||
? ScaleTransition(
|
||||
child: child,
|
||||
scale: CurvedAnimation(
|
||||
parent: animation,
|
||||
curve: Curves.ease,
|
||||
))
|
||||
: SlideTransition(
|
||||
position: animation.drive(
|
||||
Tween(begin: const Offset(0, 1), end: Offset.zero)
|
||||
.chain(CurveTween(curve: Curves.ease))),
|
||||
child: child,
|
||||
));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ abstract class Action {
|
||||
String name;
|
||||
|
||||
///Action's parameters
|
||||
Map<String, Object?> parameters;
|
||||
Map<String, Object> parameters;
|
||||
Action(
|
||||
{Key? key,
|
||||
required this.service,
|
||||
|
||||
@@ -8,7 +8,7 @@ class Reaction extends aeris_action.Action {
|
||||
{Key? key,
|
||||
required Service service,
|
||||
required String name,
|
||||
Map<String, Object?> parameters = const {}})
|
||||
Map<String, Object> parameters = const {}})
|
||||
: super(service: service, name: name, parameters: parameters);
|
||||
|
||||
/// Template trigger, used as an 'empty' trigger
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:mobile/src/main.dart';
|
||||
import 'package:mobile/src/models/service.dart';
|
||||
import 'package:mobile/src/models/action.dart' as aeris_action;
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
///Object representation of a pipeline trigger
|
||||
class Trigger extends aeris_action.Action {
|
||||
@@ -10,17 +12,20 @@ class Trigger extends aeris_action.Action {
|
||||
{Key? key,
|
||||
required Service service,
|
||||
required String name,
|
||||
Map<String, Object?> parameters = const {},
|
||||
Map<String, Object> parameters = const {},
|
||||
this.last})
|
||||
: super(service: service, name: name, parameters: parameters);
|
||||
|
||||
///TODO Constructor from DB 'Type' field
|
||||
///TODO translate
|
||||
String lastToString() {
|
||||
if (last == null) return 'Last: Never';
|
||||
var context = AppLocalizations.of(Aeris.materialKey.currentContext!);
|
||||
String lastStr = context.lastTrigger;
|
||||
if (last == null) return '$lastStr: ${context.lastTrigger}';
|
||||
int elapsedDays = DateTime.now().difference(last!).inDays;
|
||||
return elapsedDays == 0
|
||||
? 'Last: Today'
|
||||
: 'Last: ${elapsedDays.toString()}d ago';
|
||||
? '$lastStr: ${context.today}'
|
||||
: '$lastStr: $elapsedDays${context.nDaysAgo}';
|
||||
}
|
||||
|
||||
/// Template trigger, used as an 'empty' trigger
|
||||
|
||||
@@ -12,6 +12,7 @@ import 'package:mobile/src/widgets/aeris_card_page.dart';
|
||||
import 'package:flutter_form_builder/flutter_form_builder.dart';
|
||||
import 'package:mobile/src/widgets/colored_clickable_card.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
/// Page to create a new pipeline
|
||||
class CreatePipelinePage extends StatefulWidget {
|
||||
@@ -22,7 +23,6 @@ class CreatePipelinePage extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _CreatePipelinePageState extends State<CreatePipelinePage> {
|
||||
|
||||
/// Creates a basic Template the user can modify
|
||||
Trigger trigger = Trigger.template();
|
||||
|
||||
@@ -36,113 +36,126 @@ class _CreatePipelinePageState extends State<CreatePipelinePage> {
|
||||
Widget build(BuildContext context) {
|
||||
final _formKey = GlobalKey<FormBuilderState>();
|
||||
return Consumer<PipelineProvider>(
|
||||
builder: (context, provider, _) =>
|
||||
AerisCardPage(
|
||||
body: ListView(children: [
|
||||
const Text("Create a new pipeline",
|
||||
style: TextStyle(
|
||||
fontSize: 25,
|
||||
)
|
||||
),
|
||||
FormBuilder(
|
||||
key: _formKey,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: Column(children: [
|
||||
FormBuilderTextField(
|
||||
name: 'name',
|
||||
initialValue: name,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Name of the pipeline',
|
||||
),
|
||||
validator: FormBuilderValidators.compose([
|
||||
FormBuilderValidators.required(context),
|
||||
FormBuilderValidators.minLength(context, 5),
|
||||
builder: (context, provider, _) => AerisCardPage(
|
||||
body: ListView(children: [
|
||||
const Text("Create a new pipeline",
|
||||
style: TextStyle(
|
||||
fontSize: 25,
|
||||
)),
|
||||
FormBuilder(
|
||||
key: _formKey,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: Column(children: [
|
||||
FormBuilderTextField(
|
||||
name: 'name',
|
||||
initialValue: name,
|
||||
decoration: InputDecoration(
|
||||
labelText:
|
||||
AppLocalizations.of(context).nameOfThePipeline,
|
||||
),
|
||||
validator: FormBuilderValidators.compose([
|
||||
FormBuilderValidators.required(context),
|
||||
FormBuilderValidators.minLength(context, 5),
|
||||
]),
|
||||
onChanged: (value) {
|
||||
name = value;
|
||||
},
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: trigger == Trigger.template()
|
||||
? ColoredClickableCard(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.secondaryContainer,
|
||||
text: AppLocalizations.of(context).addTrigger,
|
||||
onTap: () {
|
||||
print("add trigger"); // TODO add reaction
|
||||
Navigator.of(context)
|
||||
.pushNamed('/pipeline/action/new',
|
||||
arguments:
|
||||
SetupActionPageArguments(trigger))
|
||||
.then((_) => setState(() {}));
|
||||
})
|
||||
: ActionCard(
|
||||
leading: trigger.service.getLogo(logoSize: 50),
|
||||
title: trigger.service.name,
|
||||
trailing: ActionCardPopupMenu(
|
||||
deletable: false,
|
||||
action: trigger,
|
||||
then: () => setState(() {})),
|
||||
),
|
||||
),
|
||||
...[
|
||||
for (Reaction reaction in reactions)
|
||||
ActionCard(
|
||||
leading: reaction.service.getLogo(logoSize: 50),
|
||||
title: reaction.service.name,
|
||||
trailing: ActionCardPopupMenu(
|
||||
deletable: reaction != reactions[0],
|
||||
action: reaction,
|
||||
then: () => setState(() {}),
|
||||
onDelete: () {
|
||||
setState(() {
|
||||
reactions.remove(reaction);
|
||||
});
|
||||
}))
|
||||
],
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: ColoredClickableCard(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.secondaryContainer,
|
||||
text: AppLocalizations.of(context).addReaction,
|
||||
onTap: () async {
|
||||
// TODO add to db
|
||||
reactions.add(Reaction.template());
|
||||
await Navigator.of(context).pushNamed(
|
||||
'/pipeline/action/new',
|
||||
arguments:
|
||||
SetupActionPageArguments(reactions.last));
|
||||
setState(() {});
|
||||
}),
|
||||
),
|
||||
ElevatedButton(
|
||||
child: const Text("Save"),
|
||||
onPressed: () {
|
||||
_formKey.currentState!.save();
|
||||
if (_formKey.currentState!.validate()) {
|
||||
if (trigger == Trigger.template() ||
|
||||
reactions.isEmpty ||
|
||||
reactions
|
||||
.where((element) =>
|
||||
element == Reaction.template())
|
||||
.isNotEmpty) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
|
||||
backgroundColor:
|
||||
Theme.of(context).colorScheme.secondary,
|
||||
content: const Text(
|
||||
"You must select at least a trigger and a reaction")));
|
||||
} else {
|
||||
Pipeline newPipeline = Pipeline(
|
||||
id: 0,
|
||||
name: _formKey.currentState!.value['name'],
|
||||
triggerCount: 0,
|
||||
enabled: true,
|
||||
parameters: {},
|
||||
trigger: trigger,
|
||||
reactions: reactions);
|
||||
provider.addPipelineInProvider(newPipeline);
|
||||
|
||||
///TODO add to db
|
||||
Navigator.of(context).popAndPushNamed('/pipeline',
|
||||
arguments:
|
||||
PipelineDetailPageArguments(newPipeline));
|
||||
}
|
||||
}
|
||||
},
|
||||
),
|
||||
]),
|
||||
onChanged: (value) {
|
||||
name = value;
|
||||
},
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: trigger == Trigger.template() ? ColoredClickableCard(
|
||||
color: Theme.of(context).colorScheme.secondaryContainer,
|
||||
text: "Add Trigger",
|
||||
onTap: () {
|
||||
print("add trigger"); // TODO add reaction
|
||||
Navigator.of(context).pushNamed('/pipeline/action/new',
|
||||
arguments: SetupActionPageArguments(trigger)
|
||||
).then((_) => setState(() {}));
|
||||
}
|
||||
) : ActionCard(
|
||||
leading: trigger.service.getLogo(logoSize: 50),
|
||||
title: trigger.service.name,
|
||||
trailing: ActionCardPopupMenu(
|
||||
deletable: false,
|
||||
action: trigger,
|
||||
then: () => setState(() {})),
|
||||
),
|
||||
),
|
||||
...[
|
||||
for (Reaction reaction in reactions)
|
||||
ActionCard(
|
||||
leading: reaction.service.getLogo(logoSize: 50),
|
||||
title: reaction.service.name,
|
||||
trailing: ActionCardPopupMenu(
|
||||
deletable: reaction != reactions[0],
|
||||
action: reaction,
|
||||
then: () => setState(() {})),
|
||||
)
|
||||
],
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: ColoredClickableCard(
|
||||
color: Theme.of(context).colorScheme.secondaryContainer,
|
||||
text: "Add Reaction",
|
||||
onTap: () async {
|
||||
// TODO add to db
|
||||
reactions.add(Reaction.template());
|
||||
await Navigator.of(context).pushNamed('/pipeline/action/new',
|
||||
arguments: SetupActionPageArguments(reactions.last)
|
||||
);
|
||||
setState(() {});
|
||||
}
|
||||
),
|
||||
),
|
||||
ElevatedButton(
|
||||
child: const Text("Save"),
|
||||
onPressed: () {
|
||||
_formKey.currentState!.save();
|
||||
if (_formKey.currentState!.validate()) {
|
||||
if (trigger == Trigger.template() || reactions.isEmpty ||
|
||||
reactions.where((element) => element == Reaction.template()).isNotEmpty) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
|
||||
backgroundColor: Theme.of(context).colorScheme.secondary,
|
||||
content: const Text("You must select at least a trigger and a reaction"))
|
||||
);
|
||||
} else {
|
||||
Pipeline newPipeline = Pipeline(
|
||||
id: 0,
|
||||
name: _formKey.currentState!.value['name'],
|
||||
triggerCount: 0,
|
||||
enabled: true,
|
||||
parameters: {},
|
||||
trigger: trigger,
|
||||
reactions: reactions
|
||||
);
|
||||
provider.addPipelineInProvider(newPipeline);
|
||||
///TODO add to db
|
||||
Navigator.of(context).popAndPushNamed('/pipeline',
|
||||
arguments: PipelineDetailPageArguments(newPipeline)
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
),
|
||||
]),
|
||||
)),
|
||||
])
|
||||
)
|
||||
);
|
||||
)),
|
||||
])));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import 'package:mobile/src/main.dart';
|
||||
import 'package:mobile/src/widgets/aeris_page.dart';
|
||||
import 'package:flutter_login/flutter_login.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
const users = {
|
||||
'dribbble@gmail.com': '12345',
|
||||
@@ -19,10 +21,12 @@ class LoginPage extends StatelessWidget {
|
||||
debugPrint('Name: ${data.name}, Password: ${data.password}');
|
||||
return Future.delayed(loginDuration).then((_) {
|
||||
if (!users.containsKey(data.name)) {
|
||||
return 'User does not exists';
|
||||
return AppLocalizations.of(Aeris.materialKey.currentContext!)
|
||||
.usernameOrPasswordIncorrect;
|
||||
}
|
||||
if (users[data.name] != data.password) {
|
||||
return 'Password does not match';
|
||||
return AppLocalizations.of(Aeris.materialKey.currentContext!)
|
||||
.usernameOrPasswordIncorrect;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
@@ -41,7 +45,7 @@ class LoginPage extends StatelessWidget {
|
||||
debugPrint('Name: $name');
|
||||
return Future.delayed(loginDuration).then((_) {
|
||||
if (!users.containsKey(name)) {
|
||||
return 'User does not exists';
|
||||
return AppLocalizations.of(Aeris.materialKey.currentContext!).userDoesNotExist;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
@@ -50,23 +54,20 @@ class LoginPage extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AerisPage(
|
||||
displayAppbar: false,
|
||||
body: FlutterLogin(
|
||||
disableCustomPageTransformer: true,
|
||||
logo: const AssetImage("assets/logo.png"),
|
||||
onRecoverPassword: _recoverPassword,
|
||||
theme: LoginTheme(
|
||||
pageColorLight: Colors.transparent,
|
||||
pageColorDark: Colors.transparent,
|
||||
primaryColor: Theme.of(context).colorScheme.primary
|
||||
),
|
||||
onLogin: _authUser,
|
||||
onSignup: _signupUser,
|
||||
onSubmitAnimationCompleted: () {
|
||||
Navigator.of(context).popUntil((route) => route.isFirst);
|
||||
Navigator.of(context).popAndPushNamed("/home");
|
||||
}
|
||||
)
|
||||
);
|
||||
displayAppbar: false,
|
||||
body: FlutterLogin(
|
||||
disableCustomPageTransformer: true,
|
||||
logo: const AssetImage("assets/logo.png"),
|
||||
onRecoverPassword: _recoverPassword,
|
||||
theme: LoginTheme(
|
||||
pageColorLight: Colors.transparent,
|
||||
pageColorDark: Colors.transparent,
|
||||
primaryColor: Theme.of(context).colorScheme.primary),
|
||||
onLogin: _authUser,
|
||||
onSignup: _signupUser,
|
||||
onSubmitAnimationCompleted: () {
|
||||
Navigator.of(context).popUntil((route) => route.isFirst);
|
||||
Navigator.of(context).popAndPushNamed("/home");
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:mobile/src/main.dart';
|
||||
import 'package:mobile/src/providers/pipelines_provider.dart';
|
||||
import 'package:mobile/src/views/setup_action_page.dart';
|
||||
import 'package:mobile/src/widgets/action_card_popup_menu.dart';
|
||||
@@ -10,6 +11,7 @@ import 'package:mobile/src/models/reaction.dart';
|
||||
import 'package:mobile/src/models/pipeline.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
/// Class to get the pipeline's name in route's arguments
|
||||
class PipelineDetailPageArguments {
|
||||
@@ -33,7 +35,9 @@ class _PipelineDetailPageState extends State<PipelineDetailPage> {
|
||||
@override
|
||||
Widget build(BuildContext context) =>
|
||||
Consumer<PipelineProvider>(builder: (context, provider, _) {
|
||||
final PipelineDetailPageArguments arguments = ModalRoute.of(context)!.settings.arguments as PipelineDetailPageArguments;
|
||||
final PipelineDetailPageArguments arguments = ModalRoute.of(context)!
|
||||
.settings
|
||||
.arguments as PipelineDetailPageArguments;
|
||||
Pipeline pipeline = arguments.pipeline;
|
||||
|
||||
final cardHeader = Row(
|
||||
@@ -45,139 +49,129 @@ class _PipelineDetailPageState extends State<PipelineDetailPage> {
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(pipeline.name,
|
||||
style: const TextStyle(
|
||||
fontSize: 25,
|
||||
)
|
||||
),
|
||||
style: const TextStyle(
|
||||
fontSize: 25,
|
||||
)),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(pipeline.trigger.lastToString(),
|
||||
style: const TextStyle(
|
||||
fontSize: 17,
|
||||
)
|
||||
),
|
||||
style: const TextStyle(
|
||||
fontSize: 17,
|
||||
)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 3,
|
||||
child: Column(
|
||||
children: [
|
||||
const SizedBox(height: 10),
|
||||
Align(
|
||||
alignment: Alignment.center,
|
||||
child: FlutterSwitch(
|
||||
activeColor: Colors.green,
|
||||
width: 60,
|
||||
value: pipeline.enabled,
|
||||
onToggle: (value) {
|
||||
setState(() {
|
||||
pipeline.enabled = !pipeline.enabled;
|
||||
provider.sortPipelines();
|
||||
provider.notifyListeners();
|
||||
// TODO call api
|
||||
});
|
||||
},
|
||||
flex: 3,
|
||||
child: Column(
|
||||
children: [
|
||||
const SizedBox(height: 10),
|
||||
Align(
|
||||
alignment: Alignment.center,
|
||||
child: FlutterSwitch(
|
||||
activeColor: Colors.green,
|
||||
width: 60,
|
||||
value: pipeline.enabled,
|
||||
onToggle: (value) {
|
||||
setState(() {
|
||||
pipeline.enabled = !pipeline.enabled;
|
||||
provider.sortPipelines();
|
||||
provider.notifyListeners();
|
||||
// TODO call api
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Align(
|
||||
alignment: Alignment.center,
|
||||
child: Text(pipeline.enabled ? "Enabled" : "Disabed",
|
||||
style: const TextStyle(fontSize: 13)
|
||||
const SizedBox(height: 10),
|
||||
Align(
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
pipeline.enabled
|
||||
? AppLocalizations.of(context).enabled
|
||||
: AppLocalizations.of(context).disabled,
|
||||
style: const TextStyle(fontSize: 13)),
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
)
|
||||
],
|
||||
))
|
||||
],
|
||||
);
|
||||
|
||||
final Widget addReactionbutton = ColoredClickableCard(
|
||||
color: Theme.of(context).colorScheme.secondaryContainer,
|
||||
text: "Add a reaction",
|
||||
onTap: () {
|
||||
Reaction newreaction = Reaction.template();
|
||||
Navigator.of(context).pushNamed('/pipeline/action/new',
|
||||
arguments: SetupActionPageArguments(newreaction)
|
||||
).then((r) {
|
||||
if (newreaction != Reaction.template()) {
|
||||
setState(() {
|
||||
pipeline.reactions.add(newreaction);
|
||||
});
|
||||
}
|
||||
return r;
|
||||
}); // TODO add reaction in db
|
||||
}
|
||||
);
|
||||
color: Theme.of(context).colorScheme.secondaryContainer,
|
||||
text: AppLocalizations.of(context).addReaction,
|
||||
onTap: () {
|
||||
Reaction newreaction = Reaction.template();
|
||||
Navigator.of(context)
|
||||
.pushNamed('/pipeline/action/new',
|
||||
arguments: SetupActionPageArguments(newreaction))
|
||||
.then((r) {
|
||||
if (newreaction != Reaction.template()) {
|
||||
setState(() {
|
||||
pipeline.reactions.add(newreaction);
|
||||
});
|
||||
}
|
||||
return r;
|
||||
}); // TODO add reaction in db
|
||||
});
|
||||
|
||||
final Widget deleteButton = ColoredClickableCard(
|
||||
color: Theme.of(context).colorScheme.error,
|
||||
text: "Delete a Pipeline",
|
||||
text: AppLocalizations.of(context).deletePipeline,
|
||||
onTap: () => showDialog<String>(
|
||||
context: context,
|
||||
builder: (BuildContext context) => WarningDialog(
|
||||
message:
|
||||
"You are about to delete a pipeline. This action can not be undone. Are you sure ?",
|
||||
onAccept: () {
|
||||
provider.removePipeline(pipeline);
|
||||
print("Delete pipeline"); /*TODO call api*/
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
warnedAction: "Delete"
|
||||
)
|
||||
),
|
||||
context: context,
|
||||
builder: (BuildContext context) => WarningDialog(
|
||||
message:
|
||||
AppLocalizations.of(context).deletePipelineWarningMessage,
|
||||
onAccept: () {
|
||||
provider.removePipeline(pipeline);
|
||||
print("Delete pipeline"); /*TODO call api*/
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
warnedAction: AppLocalizations.of(context).delete)),
|
||||
);
|
||||
|
||||
return AerisCardPage(
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.only(top: 10),
|
||||
child: ListView(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 40),
|
||||
child: cardHeader,
|
||||
),
|
||||
const Text("Action",
|
||||
style: TextStyle(fontWeight: FontWeight.w500)
|
||||
),
|
||||
ActionCard(
|
||||
leading: pipeline.trigger.service.getLogo(logoSize: 50),
|
||||
title: pipeline.trigger.name,
|
||||
trailing: ActionCardPopupMenu(
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.only(top: 10),
|
||||
child: ListView(children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 40),
|
||||
child: cardHeader,
|
||||
),
|
||||
const Text("Action", style: TextStyle(fontWeight: FontWeight.w500)),
|
||||
ActionCard(
|
||||
leading: pipeline.trigger.service.getLogo(logoSize: 50),
|
||||
title: pipeline.trigger.name,
|
||||
trailing: ActionCardPopupMenu(
|
||||
deletable: false,
|
||||
action: pipeline.trigger,
|
||||
then: () => setState(() {}))
|
||||
),
|
||||
const SizedBox(height: 25),
|
||||
const Text("Reactions",
|
||||
style: TextStyle(fontWeight: FontWeight.w500)
|
||||
),
|
||||
for (var reaction in pipeline.reactions)
|
||||
ActionCard(
|
||||
leading: reaction.service.getLogo(logoSize: 50),
|
||||
title: reaction.name,
|
||||
trailing: ActionCardPopupMenu(
|
||||
deletable: reaction != pipeline.reactions.first,
|
||||
action: reaction,
|
||||
then: () => setState(() {}))
|
||||
),
|
||||
addReactionbutton,
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(top: 30, bottom: 5),
|
||||
child: Text("Danger Zone",
|
||||
style: TextStyle(fontWeight: FontWeight.w500)
|
||||
)
|
||||
),
|
||||
deleteButton,
|
||||
const SizedBox(height: 25),
|
||||
]
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
);
|
||||
then: () => setState(() {}))),
|
||||
const SizedBox(height: 25),
|
||||
const Text("Reactions",
|
||||
style: TextStyle(fontWeight: FontWeight.w500)),
|
||||
for (var reaction in pipeline.reactions)
|
||||
ActionCard(
|
||||
leading: reaction.service.getLogo(logoSize: 50),
|
||||
title: reaction.name,
|
||||
trailing: ActionCardPopupMenu(
|
||||
deletable: reaction != pipeline.reactions.first,
|
||||
action: reaction,
|
||||
then: () => setState(() {}),
|
||||
onDelete: () {
|
||||
pipeline.reactions.remove(reaction);
|
||||
},
|
||||
)),
|
||||
addReactionbutton,
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(top: 30, bottom: 5),
|
||||
child: Text("Danger Zone",
|
||||
style: TextStyle(fontWeight: FontWeight.w500))),
|
||||
deleteButton,
|
||||
const SizedBox(height: 25),
|
||||
]),
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,34 +1,40 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:mobile/src/models/pipeline.dart';
|
||||
import 'package:mobile/src/models/reaction.dart';
|
||||
import 'package:mobile/src/models/service.dart';
|
||||
import 'package:mobile/src/providers/pipelines_provider.dart';
|
||||
import 'package:mobile/src/providers/user_services_provider.dart';
|
||||
import 'package:mobile/src/widgets/action_card.dart';
|
||||
import 'package:mobile/src/widgets/aeris_card_page.dart';
|
||||
import 'package:mobile/src/widgets/warning_dialog.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
///Page listing connected & available services
|
||||
class ServicePage extends StatelessWidget {
|
||||
const ServicePage({Key? key}) : super(key: key);
|
||||
|
||||
List<Widget> getServiceGroup(String groupName, Icon trailingIcon, void Function() onTap, BuildContext context) {
|
||||
UserServiceProvider uServicesProvider = Provider.of<UserServiceProvider>(context);
|
||||
List<Widget> getServiceGroup(String groupName, Icon trailingIcon,
|
||||
void Function(Service) onTap, BuildContext context) {
|
||||
UserServiceProvider uServicesProvider =
|
||||
Provider.of<UserServiceProvider>(context);
|
||||
|
||||
return [
|
||||
Text("$groupName:",
|
||||
Text(
|
||||
"$groupName:",
|
||||
style: const TextStyle(fontWeight: FontWeight.w500),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
for (var service in uServicesProvider.userServices)
|
||||
ActionCard(
|
||||
leading: service.serviceProvider.getLogo(logoSize: 50),
|
||||
title: service.serviceProvider.name,
|
||||
trailing: IconButton(
|
||||
splashColor: trailingIcon.color!.withAlpha(100),
|
||||
splashRadius: 20,
|
||||
icon: trailingIcon,
|
||||
onPressed: onTap,
|
||||
)
|
||||
),
|
||||
leading: service.serviceProvider.getLogo(logoSize: 50),
|
||||
title: service.serviceProvider.name,
|
||||
trailing: IconButton(
|
||||
splashColor: trailingIcon.color!.withAlpha(100),
|
||||
splashRadius: 20,
|
||||
icon: trailingIcon,
|
||||
onPressed: () => onTap(service.serviceProvider),
|
||||
)),
|
||||
const SizedBox(height: 30),
|
||||
];
|
||||
}
|
||||
@@ -43,46 +49,66 @@ class ServicePage extends StatelessWidget {
|
||||
Service.twitter(),
|
||||
Service.spotify()
|
||||
];
|
||||
UserServiceProvider uServiceProvider = Provider.of<UserServiceProvider>(context, listen: false);
|
||||
UserServiceProvider uServiceProvider =
|
||||
Provider.of<UserServiceProvider>(context, listen: false);
|
||||
for (var service in services) {
|
||||
uServiceProvider.createUserService(service);
|
||||
}
|
||||
|
||||
return AerisCardPage(
|
||||
body: NotificationListener<OverscrollIndicatorNotification>(
|
||||
onNotification: (overscroll) {
|
||||
overscroll.disallowIndicator();
|
||||
return true;
|
||||
},
|
||||
child: ListView(
|
||||
children: [
|
||||
...[
|
||||
const Align(
|
||||
alignment: Alignment.center,
|
||||
child: Text("Services",
|
||||
style: TextStyle(fontSize: 25)
|
||||
return Consumer<PipelineProvider>(
|
||||
builder: (context, provider, _) => AerisCardPage(
|
||||
body: NotificationListener<OverscrollIndicatorNotification>(
|
||||
onNotification: (overscroll) {
|
||||
overscroll.disallowIndicator();
|
||||
return true;
|
||||
},
|
||||
child: ListView(
|
||||
children: [
|
||||
...[
|
||||
const Align(
|
||||
alignment: Alignment.center,
|
||||
child: Text("Services", style: TextStyle(fontSize: 25)),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 60)
|
||||
const SizedBox(height: 60)
|
||||
],
|
||||
...getServiceGroup(
|
||||
AppLocalizations.of(context).connected,
|
||||
const Icon(Icons.delete, color: Colors.red),
|
||||
(Service service) => showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) => WarningDialog(
|
||||
message: AppLocalizations.of(context)
|
||||
.disconnectServiceWarningMessage,
|
||||
onAccept: () => {
|
||||
provider.pipelineCollection.pipelines
|
||||
.removeWhere((Pipeline pipeline) {
|
||||
if (pipeline.trigger.service == service) {
|
||||
return true;
|
||||
}
|
||||
if (pipeline.reactions
|
||||
.where((Reaction react) =>
|
||||
react.service == service)
|
||||
.isNotEmpty) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}),
|
||||
/// TODO Remove service from provider
|
||||
provider.notifyListeners(),
|
||||
print("Disconnect")
|
||||
} /* TODO Delete service form db + related actions*/,
|
||||
warnedAction:
|
||||
AppLocalizations.of(context).disconnect)),
|
||||
context),
|
||||
...getServiceGroup(
|
||||
AppLocalizations.of(context).available,
|
||||
const Icon(Icons.connect_without_contact,
|
||||
color: Colors.green),
|
||||
(Service service) =>
|
||||
print("Connected") /* TODO open page to connect service*/,
|
||||
context),
|
||||
],
|
||||
...getServiceGroup(
|
||||
"Connected",
|
||||
const Icon(Icons.delete, color: Colors.red),
|
||||
() => showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) => WarningDialog(
|
||||
message: "You are about to disconnect to a service. Once disconnected, every related pipeline will be deleted. This action cannot be undone.",
|
||||
onAccept: () => print("Disconnect") /* TODO Delete service form db + related actions*/,
|
||||
warnedAction: "Disconnect")
|
||||
),
|
||||
context
|
||||
),
|
||||
...getServiceGroup(
|
||||
"Available",
|
||||
const Icon(Icons.connect_without_contact, color: Colors.green),
|
||||
() => print("Connected") /* TODO open page to connect service*/,
|
||||
context),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -5,6 +5,7 @@ import 'package:mobile/src/models/trigger.dart';
|
||||
import 'package:mobile/src/widgets/action_form.dart';
|
||||
import 'package:mobile/src/widgets/aeris_card_page.dart';
|
||||
import 'package:expandable/expandable.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
/// Class to get the action in route's arguments
|
||||
class SetupActionPageArguments {
|
||||
@@ -38,7 +39,7 @@ class _SetupActionPageState extends State<SetupActionPage> {
|
||||
last: DateTime.now(),
|
||||
service: arguments.action.service,
|
||||
name: "action",
|
||||
parameters: {'key1': 'value1', 'key2': null})
|
||||
parameters: {'key1': 'value1', 'key2': 'value2'})
|
||||
];
|
||||
|
||||
final Widget serviceDropdown = DropdownButton<Service>(
|
||||
@@ -82,7 +83,7 @@ class _SetupActionPageState extends State<SetupActionPage> {
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
"${availableActions.length} available actions for ",
|
||||
"${availableActions.length} ${AppLocalizations.of(context).avalableActionsFor} ",
|
||||
)),
|
||||
Align(alignment: Alignment.centerRight, child: serviceDropdown),
|
||||
],
|
||||
@@ -104,6 +105,7 @@ class _SetupActionPageState extends State<SetupActionPage> {
|
||||
name: availableAction.name,
|
||||
parametersNames:
|
||||
availableAction.parameters.keys.toList(),
|
||||
initValues: arguments.action.parameters,
|
||||
onValidate: (parameters) {
|
||||
arguments.action.service = serviceState!;
|
||||
arguments.action.parameters = parameters;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:flutter_fadein/flutter_fadein.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import '../widgets/aeris_page.dart';
|
||||
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import '../../aeris.dart';
|
||||
|
||||
/// [StatefulWidget] used in order to display StartupPage [Widget]
|
||||
@@ -28,12 +28,12 @@ class _StartupPageState extends State<StartupPage> {
|
||||
curve: Curves.easeInOut
|
||||
)
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.all(20),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: OverlayedText(
|
||||
text: "Aeris is the best AREA in Nantes! Control each of your social network with Aeris, your new Action / Reaction app.",
|
||||
overlayedColor: Color.fromRGBO(50, 0, 27, 1),
|
||||
textColor: Color.fromRGBO(198, 93, 151, 1),
|
||||
text: AppLocalizations.of(context).aerisDescription,
|
||||
overlayedColor: const Color.fromRGBO(50, 0, 27, 1),
|
||||
textColor: const Color.fromRGBO(198, 93, 151, 1),
|
||||
fontSize: 20,
|
||||
strokeWidth: 2.15
|
||||
)
|
||||
@@ -48,9 +48,9 @@ class _StartupPageState extends State<StartupPage> {
|
||||
onPressed: () {
|
||||
Navigator.of(context).pushNamed('/login');
|
||||
},
|
||||
child: const Tooltip(
|
||||
child: Tooltip(
|
||||
message: 'Connexion',
|
||||
child: Text("Se connecter")
|
||||
child: Text(AppLocalizations.of(context).connect)
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
@@ -3,15 +3,21 @@ import 'package:mobile/src/views/setup_action_page.dart';
|
||||
import 'package:mobile/src/widgets/aeris_popup_menu.dart';
|
||||
import 'package:mobile/src/widgets/aeris_popup_menu_item.dart';
|
||||
import 'package:mobile/src/models/action.dart' as aeris;
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
/// [StatelessWidget] displayed as a PopupMenu
|
||||
class ActionCardPopupMenu extends StatelessWidget {
|
||||
const ActionCardPopupMenu({
|
||||
ActionCardPopupMenu({
|
||||
Key? key,
|
||||
required this.action,
|
||||
required this.then,
|
||||
required this.deletable,
|
||||
}) : super(key: key);
|
||||
this.onDelete,
|
||||
}) : super(key: key) {
|
||||
if (deletable) {
|
||||
assert(onDelete != null);
|
||||
}
|
||||
}
|
||||
|
||||
/// Action to trigger
|
||||
final aeris.Action action;
|
||||
@@ -22,36 +28,45 @@ class ActionCardPopupMenu extends StatelessWidget {
|
||||
/// Deletable characteristic
|
||||
final bool deletable;
|
||||
|
||||
final void Function()? onDelete;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AerisPopupMenu(
|
||||
onSelected: (value) {
|
||||
Map object = value as Map;
|
||||
Navigator.pushNamed(context, object['route'] as String, arguments: object['params']).then((r) {
|
||||
then();
|
||||
return r;
|
||||
});
|
||||
},
|
||||
icon: Icons.more_vert,
|
||||
itemBuilder: (context) => [
|
||||
AerisPopupMenuItem(
|
||||
context: context,
|
||||
icon: Icons.settings,
|
||||
title: "Modify",
|
||||
value: {
|
||||
'route': "/pipeline/action/mod",
|
||||
'params': SetupActionPageArguments(action),
|
||||
}),
|
||||
AerisPopupMenuItem(
|
||||
context: context,
|
||||
icon: Icons.delete,
|
||||
title: "Delete",
|
||||
value: "/pipeline/action/del",
|
||||
enabled: deletable,
|
||||
// TODO Delete from parent pipeline
|
||||
/* TODO Define delete route*/
|
||||
),
|
||||
]
|
||||
);
|
||||
onSelected: (value) {
|
||||
if (value == '/pipeline/action/del') {
|
||||
onDelete!();
|
||||
///TODO delete from db
|
||||
} else {
|
||||
Map object = value as Map;
|
||||
Navigator.pushNamed(context, object['route'] as String,
|
||||
arguments: object['params'])
|
||||
.then((r) {
|
||||
then();
|
||||
return r;
|
||||
});
|
||||
}
|
||||
;
|
||||
},
|
||||
icon: Icons.more_vert,
|
||||
itemBuilder: (context) => [
|
||||
AerisPopupMenuItem(
|
||||
context: context,
|
||||
icon: Icons.settings,
|
||||
title: AppLocalizations.of(context).modify,
|
||||
value: {
|
||||
'route': "/pipeline/action/mod",
|
||||
'params': SetupActionPageArguments(action),
|
||||
}),
|
||||
AerisPopupMenuItem(
|
||||
context: context,
|
||||
icon: Icons.delete,
|
||||
title: AppLocalizations.of(context).delete,
|
||||
value: "/pipeline/action/del",
|
||||
enabled: deletable,
|
||||
// TODO Delete from parent pipeline
|
||||
/* TODO Define delete route*/
|
||||
),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'dart:ffi';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_form_builder/flutter_form_builder.dart';
|
||||
import 'package:form_builder_validators/form_builder_validators.dart';
|
||||
@@ -9,7 +11,7 @@ class ActionForm extends StatefulWidget {
|
||||
/// Names of the parameters
|
||||
final List<String> parametersNames;
|
||||
/// Initial values of the fields
|
||||
final Map<String, String> initValues;
|
||||
final Map<String, Object> initValues;
|
||||
|
||||
/// On validate callback
|
||||
final void Function(Map<String, String>) onValidate;
|
||||
@@ -44,6 +46,7 @@ class _ActionFormState extends State<ActionForm> {
|
||||
validator: FormBuilderValidators.compose([
|
||||
FormBuilderValidators.required(context),
|
||||
]),
|
||||
keyboardType: (widget.initValues.containsKey(name)) && widget.initValues[name] is Int ? TextInputType.number : null,
|
||||
)),
|
||||
...[
|
||||
ElevatedButton(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:mobile/src/widgets/background/animated_background.dart';
|
||||
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
/// Application base page, holds scaffold and background
|
||||
class AerisPage extends StatelessWidget {
|
||||
/// Body of the page
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:mobile/src/widgets/aeris_popup_menu.dart';
|
||||
import 'package:mobile/src/widgets/aeris_popup_menu_item.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
/// Menu for the Home Page
|
||||
class HomePageMenu extends StatelessWidget {
|
||||
@@ -11,10 +12,16 @@ class HomePageMenu extends StatelessWidget {
|
||||
return AerisPopupMenu(
|
||||
itemBuilder: (context) => [
|
||||
AerisPopupMenuItem(
|
||||
context: context,
|
||||
icon: Icons.electrical_services, title: "Services", value: "/services"),
|
||||
context: context,
|
||||
icon: Icons.electrical_services,
|
||||
title: AppLocalizations.of(context).services,
|
||||
value: "/services"),
|
||||
AerisPopupMenuItem(
|
||||
context: context, icon: Icons.logout, title: "Logout", value: "/logout"),
|
||||
|
||||
context: context,
|
||||
icon: Icons.logout,
|
||||
title: AppLocalizations.of(context).logout,
|
||||
value: "/logout"),
|
||||
],
|
||||
onSelected: (route) => Navigator.pushNamed(context, route as String),
|
||||
icon: Icons.more_horiz,
|
||||
|
||||
@@ -4,6 +4,7 @@ import 'package:mobile/src/providers/pipelines_provider.dart';
|
||||
import 'package:mobile/src/widgets/aeris_popup_menu.dart';
|
||||
import 'package:mobile/src/widgets/aeris_popup_menu_item.dart';
|
||||
import 'package:recase/recase.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
/// Sorting Menu for the Home Page
|
||||
class HomePageSortMenu extends StatelessWidget {
|
||||
@@ -33,27 +34,27 @@ class HomePageSortMenu extends StatelessWidget {
|
||||
...[
|
||||
for (var sortingMethod in PipelineCollectionSort.values)
|
||||
AerisPopupMenuItem(
|
||||
context: context,
|
||||
icon: sortMethodGetIcon(sortingMethod),
|
||||
title: ReCase(sortingMethod.name).titleCase,
|
||||
value: sortingMethod
|
||||
),
|
||||
context: context,
|
||||
icon: sortMethodGetIcon(sortingMethod),
|
||||
title: ReCase(sortingMethod.name).titleCase,
|
||||
value: sortingMethod),
|
||||
],
|
||||
AerisPopupMenuItem(
|
||||
context: context,
|
||||
icon: Icons.call_merge,
|
||||
title: collectionProvider.pipelineCollection.sortingSplitDisabled
|
||||
? "Merge disabled pipelines"
|
||||
: "Seperate disabled pipelines",
|
||||
value: ""
|
||||
),
|
||||
context: context,
|
||||
icon: Icons.call_merge,
|
||||
title: collectionProvider.pipelineCollection.sortingSplitDisabled
|
||||
? AppLocalizations.of(context).mergeDisabledPipelines
|
||||
: AppLocalizations.of(context).seperateDisabledPipelines,
|
||||
value: ""),
|
||||
],
|
||||
onSelected: (sortingMethod) {
|
||||
/// TODO: not clean
|
||||
if (sortingMethod == "") {
|
||||
collectionProvider.pipelineCollection.sortingSplitDisabled = !collectionProvider.pipelineCollection.sortingSplitDisabled;
|
||||
collectionProvider.pipelineCollection.sortingSplitDisabled =
|
||||
!collectionProvider.pipelineCollection.sortingSplitDisabled;
|
||||
} else {
|
||||
collectionProvider.pipelineCollection.sortingMethod = sortingMethod as PipelineCollectionSort;
|
||||
collectionProvider.pipelineCollection.sortingMethod =
|
||||
sortingMethod as PipelineCollectionSort;
|
||||
}
|
||||
collectionProvider.sortPipelines();
|
||||
},
|
||||
|
||||
+5
-5
@@ -571,7 +571,7 @@ packages:
|
||||
name: url_launcher_web
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.6"
|
||||
version: "2.0.8"
|
||||
url_launcher_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -592,21 +592,21 @@ packages:
|
||||
name: vector_math
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
version: "2.1.2"
|
||||
win32:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: win32
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.3.9"
|
||||
version: "2.3.11"
|
||||
xdg_directories:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: xdg_directories
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.2.0"
|
||||
version: "0.2.0+1"
|
||||
xml:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -623,4 +623,4 @@ packages:
|
||||
version: "3.1.0"
|
||||
sdks:
|
||||
dart: ">=2.16.0-100.0.dev <3.0.0"
|
||||
flutter: ">=2.5.0"
|
||||
flutter: ">=2.10.0"
|
||||
|
||||
@@ -12,7 +12,7 @@ import 'package:mobile/src/main.dart';
|
||||
void main() {
|
||||
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
|
||||
// Build our app and trigger a frame.
|
||||
await tester.pumpWidget(const MyApp());
|
||||
await tester.pumpWidget(const Aeris());
|
||||
|
||||
// Verify that our counter starts at 0.
|
||||
expect(find.text('0'), findsOneWidget);
|
||||
|
||||
Reference in New Issue
Block a user