diff --git a/comunes_flutter.iml b/comunes_flutter.iml
new file mode 100644
index 0000000..c7d8949
--- /dev/null
+++ b/comunes_flutter.iml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lib/appIntroPage.dart b/lib/appIntroPage.dart
new file mode 100644
index 0000000..70f6b35
--- /dev/null
+++ b/lib/appIntroPage.dart
@@ -0,0 +1,143 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/material.dart';
+// import 'package:padder/padding.dart';
+import 'comunes_flutter.dart';
+
+class AppIntroItem {
+ final IconData icon;
+ final String title;
+ final String subTitle;
+
+ AppIntroItem({this.icon, this.title, this.subTitle = ''});
+// 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec vitae eros. Nunc sit amet neque. Ut id dui. Integer viverra feugiat sem. Morbi aliquam turpis rhoncus sapien volutpat condimentum.'});
+}
+
+typedef void OnIntroFinish(BuildContext context);
+typedef List ListItems(BuildContext context);
+
+abstract class AppIntroPage extends StatelessWidget {
+ static const String routeName = '/appintro';
+ final ListItems items;
+ final OnIntroFinish onIntroFinish;
+
+ const AppIntroPage({Key key, this.items, this.onIntroFinish})
+ : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return new Scaffold(
+ // appBar: new AppBar(),
+ body: new DefaultTabController(
+ length: items(context).length,
+ child: new _AppIntroPageSelector(items: items, onFinish: onIntroFinish),
+ ),
+ );
+ }
+}
+
+class _AppIntroPageSelector extends StatelessWidget {
+ const _AppIntroPageSelector({this.items, this.onFinish});
+
+ final ListItems items;
+ final OnIntroFinish onFinish;
+
+ void _handleArrowButtonPress(BuildContext context, int delta) {
+ final TabController controller = DefaultTabController.of(context);
+ if (!controller.indexIsChanging)
+ controller
+ .animateTo((controller.index + delta).clamp(0, items(context).length - 1));
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ final TabController controller = DefaultTabController.of(context);
+ final ThemeData theme = Theme.of(context);
+ final Color color = theme.accentColor;
+ final TextStyle titleStyle =
+ theme.textTheme.headline.copyWith(color: color);
+ final TextStyle subTitleStyle =
+ theme.textTheme.subhead; //.copyWith(color: color);
+ // final TextStyle descriptionStyle = theme.textTheme.subhead;
+ return new SafeArea(
+ top: true,
+ bottom: false,
+ child: new Column(
+ children: [
+ new Row(mainAxisAlignment: MainAxisAlignment.end, children: [
+ new IconButton(
+ onPressed: () {
+ onFinish(context);
+ },
+ icon: new Icon(Icons.close, size: 30.0, color: Colors.black38)),
+ ]),
+ new Expanded(
+ child: new OrientationBuilder(builder: (context, orientation) {
+ return new IconTheme(
+ data: new IconThemeData(
+ size: orientation == Orientation.portrait ? 200.0 : 100.0,
+ color: color,
+ ),
+ child: new TabBarView(
+ children: items(context).map((AppIntroItem item) {
+ return new Container(
+ padding: const EdgeInsets.all(12.0),
+ child: new Center(
+ child: new CenteredSpaceEvenlyColumn(children: [
+ Icon(
+ item.icon,
+ semanticLabel: item.title,
+ ),
+ new Padding(
+ padding: new EdgeInsets.only(left: 16.0, right: 16.0),
+ child: new CenteredColumn(children: [
+ new Text(
+ item.title,
+ style: titleStyle,
+ textAlign: TextAlign.center,
+ ),
+ new SizedBox(height: 20.0),
+ new Text(
+ item.subTitle,
+ style: subTitleStyle,
+ textAlign: TextAlign.center,
+ )
+ ])),
+ ]),
+ ),
+ );
+ }).toList()),
+ );
+ })),
+ new Container(
+ margin: const EdgeInsets.only(top: 16.0),
+ child: new Row(
+ children: listWithoutNulls([
+ new IconButton(
+ icon: const Icon(Icons.chevron_left),
+ color: color,
+ onPressed: () {
+ _handleArrowButtonPress(context, -1);
+ },
+ tooltip: 'Page back'),
+ new TabPageSelector(controller: controller),
+ new IconButton(
+ icon: const Icon(Icons.chevron_right),
+ color: color,
+ onPressed: () {
+ _handleArrowButtonPress(context, 1);
+ if (!controller.indexIsChanging &&
+ controller.index == items(context).length - 1) {
+ onFinish(context);
+ }
+ },
+ tooltip: 'Page forward'),
+ ]),
+ mainAxisAlignment: MainAxisAlignment.spaceBetween)),
+ ],
+ ),
+ );
+ }
+}
diff --git a/lib/comunes_flutter.dart b/lib/comunes_flutter.dart
new file mode 100644
index 0000000..ed6a158
--- /dev/null
+++ b/lib/comunes_flutter.dart
@@ -0,0 +1,17 @@
+export 'layout/centeredMaxWidget.dart';
+export 'layout/centeredRow.dart';
+export 'layout/centeredColumn.dart';
+export 'layout/centeredSpaceBetweenColumn.dart';
+export 'layout/centeredSpaceBetweenRow.dart';
+export 'layout/centeredSpaceAroundRow.dart';
+export 'layout/centeredSpaceAroundColumn.dart';
+export 'layout/centeredSpaceEvenlyRow.dart';
+export 'layout/centeredSpaceEvenlyColumn.dart';
+
+export 'widgets/roundedButton.dart';
+
+export 'utils/utils.dart';
+export 'utils/secretLoader.dart';
+
+export 'appIntroPage.dart';
+export 'materialAppWithIntro.dart';
\ No newline at end of file
diff --git a/lib/generated/i18n.dart b/lib/generated/i18n.dart
new file mode 100644
index 0000000..db983ef
--- /dev/null
+++ b/lib/generated/i18n.dart
@@ -0,0 +1,78 @@
+
+import 'dart:async';
+
+import 'package:flutter/foundation.dart';
+import 'package:flutter/material.dart';
+// ignore_for_file: non_constant_identifier_names
+// ignore_for_file: camel_case_types
+// ignore_for_file: prefer_single_quotes
+
+//This file is automatically generated. DO NOT EDIT, all your changes would be lost.
+
+class S implements WidgetsLocalizations {
+ const S();
+
+ static const GeneratedLocalizationsDelegate delegate =
+ const GeneratedLocalizationsDelegate();
+
+ static S of(BuildContext context) =>
+ Localizations.of(context, WidgetsLocalizations);
+
+ @override
+ TextDirection get textDirection => TextDirection.ltr;
+
+}
+
+class en extends S {
+ const en();
+}
+
+
+class GeneratedLocalizationsDelegate extends LocalizationsDelegate {
+ const GeneratedLocalizationsDelegate();
+
+ List get supportedLocales {
+ return const [
+
+ const Locale("en", ""),
+
+ ];
+ }
+
+ LocaleResolutionCallback resolution({Locale fallback}) {
+ return (Locale locale, Iterable supported) {
+ final Locale languageLocale = new Locale(locale.languageCode, "");
+ if (supported.contains(locale))
+ return locale;
+ else if (supported.contains(languageLocale))
+ return languageLocale;
+ else {
+ final Locale fallbackLocale = fallback ?? supported.first;
+ return fallbackLocale;
+ }
+ };
+ }
+
+ @override
+ Future load(Locale locale) {
+ final String lang = getLang(locale);
+ switch (lang) {
+
+ case "en":
+ return new SynchronousFuture(const en());
+
+ default:
+ return new SynchronousFuture(const S());
+ }
+ }
+
+ @override
+ bool isSupported(Locale locale) => supportedLocales.contains(locale);
+
+ @override
+ bool shouldReload(GeneratedLocalizationsDelegate old) => false;
+}
+
+String getLang(Locale l) => l.countryCode != null && l.countryCode.isEmpty
+ ? l.languageCode
+ : l.toString();
diff --git a/lib/layout/abstractCenteredColumn.dart b/lib/layout/abstractCenteredColumn.dart
new file mode 100644
index 0000000..3dddb9b
--- /dev/null
+++ b/lib/layout/abstractCenteredColumn.dart
@@ -0,0 +1,20 @@
+import 'package:flutter/material.dart';
+
+abstract class AbstractCenteredColumn extends Column {
+ AbstractCenteredColumn({
+ Key key,
+ MainAxisAlignment mainAxisAlignment,
+ TextDirection textDirection,
+ TextBaseline textBaseline,
+ List children: const [],
+ }) : super(
+ children: children,
+ key: key,
+ mainAxisAlignment: mainAxisAlignment,
+ mainAxisSize: MainAxisSize.max,
+ crossAxisAlignment: CrossAxisAlignment.center,
+ textDirection: textDirection,
+ verticalDirection: VerticalDirection.down,
+ textBaseline: textBaseline,
+ );
+}
diff --git a/lib/layout/abstractCenteredRow.dart b/lib/layout/abstractCenteredRow.dart
new file mode 100644
index 0000000..96f6aec
--- /dev/null
+++ b/lib/layout/abstractCenteredRow.dart
@@ -0,0 +1,20 @@
+import 'package:flutter/material.dart';
+
+abstract class AbstractCenteredRow extends Row {
+ AbstractCenteredRow({
+ Key key,
+ TextDirection textDirection,
+ TextBaseline textBaseline,
+ mainAxisAlignment,
+ List children: const [],
+ }) : super(
+ children: children,
+ key: key,
+ mainAxisAlignment: mainAxisAlignment,
+ mainAxisSize: MainAxisSize.max,
+ crossAxisAlignment: CrossAxisAlignment.center,
+ textDirection: textDirection,
+ verticalDirection: VerticalDirection.down,
+ textBaseline: textBaseline,
+ );
+}
diff --git a/lib/layout/centeredColumn.dart b/lib/layout/centeredColumn.dart
new file mode 100644
index 0000000..7f2e3c2
--- /dev/null
+++ b/lib/layout/centeredColumn.dart
@@ -0,0 +1,17 @@
+import 'package:flutter/material.dart';
+import 'abstractCenteredColumn.dart';
+
+class CenteredColumn extends AbstractCenteredColumn {
+ CenteredColumn({
+ Key key,
+ TextDirection textDirection,
+ TextBaseline textBaseline,
+ List children: const [],
+ }) : super(
+ children: children,
+ key: key,
+ mainAxisAlignment: MainAxisAlignment.center,
+ textDirection: textDirection,
+ textBaseline: textBaseline,
+ );
+}
diff --git a/lib/layout/centeredMaxWidget.dart b/lib/layout/centeredMaxWidget.dart
new file mode 100644
index 0000000..70e42e8
--- /dev/null
+++ b/lib/layout/centeredMaxWidget.dart
@@ -0,0 +1,17 @@
+import 'package:flutter/material.dart';
+import 'centeredColumn.dart';
+import 'centeredRow.dart';
+
+class CenteredMaxWidget extends CenteredColumn {
+ CenteredMaxWidget({
+ Key key,
+ TextDirection textDirection,
+ TextBaseline textBaseline,
+ List children: const [],
+ }) : super(
+ children: [new CenteredRow(children: children)],
+ key: key,
+ textDirection: textDirection,
+ textBaseline: textBaseline,
+ );
+}
diff --git a/lib/layout/centeredRow.dart b/lib/layout/centeredRow.dart
new file mode 100644
index 0000000..8b5242b
--- /dev/null
+++ b/lib/layout/centeredRow.dart
@@ -0,0 +1,17 @@
+import 'package:flutter/material.dart';
+import 'abstractCenteredRow.dart';
+
+class CenteredRow extends AbstractCenteredRow {
+ CenteredRow({
+ Key key,
+ TextDirection textDirection,
+ TextBaseline textBaseline,
+ List children: const [],
+ }) : super(
+ children: children,
+ key: key,
+ mainAxisAlignment: MainAxisAlignment.center,
+ textDirection: textDirection,
+ textBaseline: textBaseline,
+ );
+}
diff --git a/lib/layout/centeredSpaceAroundColumn.dart b/lib/layout/centeredSpaceAroundColumn.dart
new file mode 100644
index 0000000..704cfeb
--- /dev/null
+++ b/lib/layout/centeredSpaceAroundColumn.dart
@@ -0,0 +1,17 @@
+import 'package:flutter/material.dart';
+import 'abstractCenteredColumn.dart';
+
+class CenteredSpaceAroundColumn extends AbstractCenteredColumn {
+ CenteredSpaceAroundColumn({
+ Key key,
+ TextDirection textDirection,
+ TextBaseline textBaseline,
+ List children: const [],
+ }) : super(
+ children: children,
+ key: key,
+ mainAxisAlignment: MainAxisAlignment.spaceAround,
+ textDirection: textDirection,
+ textBaseline: textBaseline,
+ );
+}
diff --git a/lib/layout/centeredSpaceAroundRow.dart b/lib/layout/centeredSpaceAroundRow.dart
new file mode 100644
index 0000000..dadd9e0
--- /dev/null
+++ b/lib/layout/centeredSpaceAroundRow.dart
@@ -0,0 +1,17 @@
+import 'package:flutter/material.dart';
+import 'abstractCenteredRow.dart';
+
+class CenteredSpacedAroundRow extends AbstractCenteredRow {
+ CenteredSpacedAroundRow({
+ Key key,
+ TextDirection textDirection,
+ TextBaseline textBaseline,
+ List children: const [],
+ }) : super(
+ children: children,
+ key: key,
+ mainAxisAlignment: MainAxisAlignment.spaceAround,
+ textDirection: textDirection,
+ textBaseline: textBaseline,
+ );
+}
diff --git a/lib/layout/centeredSpaceBetweenColumn.dart b/lib/layout/centeredSpaceBetweenColumn.dart
new file mode 100644
index 0000000..dac8062
--- /dev/null
+++ b/lib/layout/centeredSpaceBetweenColumn.dart
@@ -0,0 +1,17 @@
+import 'package:flutter/material.dart';
+import 'abstractCenteredColumn.dart';
+
+class CenteredSpaceBetweenColumn extends AbstractCenteredColumn {
+ CenteredSpaceBetweenColumn({
+ Key key,
+ TextDirection textDirection,
+ TextBaseline textBaseline,
+ List children: const [],
+ }) : super(
+ children: children,
+ key: key,
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ textDirection: textDirection,
+ textBaseline: textBaseline,
+ );
+}
diff --git a/lib/layout/centeredSpaceBetweenRow.dart b/lib/layout/centeredSpaceBetweenRow.dart
new file mode 100644
index 0000000..a6a26d3
--- /dev/null
+++ b/lib/layout/centeredSpaceBetweenRow.dart
@@ -0,0 +1,17 @@
+import 'package:flutter/material.dart';
+import 'abstractCenteredRow.dart';
+
+class CenteredSpacedBetweenRow extends AbstractCenteredRow {
+ CenteredSpacedBetweenRow({
+ Key key,
+ TextDirection textDirection,
+ TextBaseline textBaseline,
+ List children: const [],
+ }) : super(
+ children: children,
+ key: key,
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ textDirection: textDirection,
+ textBaseline: textBaseline,
+ );
+}
diff --git a/lib/layout/centeredSpaceEvenlyColumn.dart b/lib/layout/centeredSpaceEvenlyColumn.dart
new file mode 100644
index 0000000..acac79f
--- /dev/null
+++ b/lib/layout/centeredSpaceEvenlyColumn.dart
@@ -0,0 +1,17 @@
+import 'package:flutter/material.dart';
+import 'abstractCenteredColumn.dart';
+
+class CenteredSpaceEvenlyColumn extends AbstractCenteredColumn {
+ CenteredSpaceEvenlyColumn({
+ Key key,
+ TextDirection textDirection,
+ TextBaseline textBaseline,
+ List children: const [],
+ }) : super(
+ children: children,
+ key: key,
+ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+ textDirection: textDirection,
+ textBaseline: textBaseline,
+ );
+}
diff --git a/lib/layout/centeredSpaceEvenlyRow.dart b/lib/layout/centeredSpaceEvenlyRow.dart
new file mode 100644
index 0000000..d505fec
--- /dev/null
+++ b/lib/layout/centeredSpaceEvenlyRow.dart
@@ -0,0 +1,17 @@
+import 'package:flutter/material.dart';
+import 'abstractCenteredRow.dart';
+
+class CenteredSpacedEvenlyRow extends AbstractCenteredRow {
+ CenteredSpacedEvenlyRow({
+ Key key,
+ TextDirection textDirection,
+ TextBaseline textBaseline,
+ List children: const [],
+ }) : super(
+ children: children,
+ key: key,
+ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+ textDirection: textDirection,
+ textBaseline: textBaseline,
+ );
+}
diff --git a/lib/materialAppWithIntro.dart b/lib/materialAppWithIntro.dart
new file mode 100644
index 0000000..e4e614d
--- /dev/null
+++ b/lib/materialAppWithIntro.dart
@@ -0,0 +1,81 @@
+import 'package:flutter/material.dart';
+import 'package:shared_preferences/shared_preferences.dart';
+import 'dart:async';
+
+abstract class MaterialAppWithIntro extends StatelessWidget {
+ final String name;
+ final ThemeData theme;
+ final Map routes;
+ final WidgetBuilder introWidget;
+ final WidgetBuilder continueWidget;
+ final String prefsKey;
+
+ MaterialAppWithIntro(this.name, this.theme, this.routes, this.introWidget,
+ this.continueWidget, this.prefsKey);
+
+ @override
+ Widget build(BuildContext context) {
+ return new MaterialApp(
+ home: new MaterialAppWithIntroHome(introWidget, continueWidget, prefsKey),
+ title: name,
+ theme: theme,
+ routes: routes);
+ }
+}
+
+class MaterialAppWithIntroHome extends StatefulWidget {
+ final WidgetBuilder introWidget;
+ final WidgetBuilder continueWidget;
+ final String prefsKey;
+
+ MaterialAppWithIntroHome(this.introWidget, this.continueWidget, this.prefsKey);
+
+ @override
+ _MaterialAppWithIntroState createState() =>
+ _MaterialAppWithIntroState(introWidget, continueWidget, prefsKey);
+}
+
+class _MaterialAppWithIntroState extends State {
+ final WidgetBuilder introWidget;
+ final WidgetBuilder continueWidget;
+ final String prefsKey;
+
+ _MaterialAppWithIntroState(this.introWidget, this.continueWidget, this.prefsKey);
+
+ @override
+ void initState() {
+ super.initState();
+ new Timer(new Duration(milliseconds: 1000), () {
+ checkFirstStart();
+ });
+ }
+
+ // https://stackoverflow.com/questions/50654195/flutter-one-time-intro-screen
+ Future checkFirstStart() async {
+ final String initialWizardKey = prefsKey;
+ SharedPreferences prefs = await SharedPreferences.getInstance();
+ bool showInitialWizard = (prefs.getBool(initialWizardKey) ?? true);
+
+ if (showInitialWizard) {
+ prefs.setBool(initialWizardKey, false);
+ print('Show initial intro at first start');
+ Navigator
+ .of(context)
+ .pushReplacement(new MaterialPageRoute(builder: this.introWidget));
+ } else {
+ print('Don\'t show initial intro ');
+ Navigator
+ .of(context)
+ .pushReplacement(new MaterialPageRoute(builder: this.continueWidget));
+ }
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return new Scaffold(
+ body: new Center(
+ child: new CircularProgressIndicator(),// Loading...
+ ),
+ );
+ }
+}
diff --git a/lib/utils/secretLoader.dart b/lib/utils/secretLoader.dart
new file mode 100644
index 0000000..4270707
--- /dev/null
+++ b/lib/utils/secretLoader.dart
@@ -0,0 +1,17 @@
+import 'dart:async' show Future;
+import 'dart:convert' show json;
+import 'package:flutter/services.dart' show rootBundle;
+
+class SecretLoader {
+ final String secretPath;
+
+ SecretLoader({this.secretPath});
+
+ Future