Initial framework in place, non-functional POST & env vars atm
This commit is contained in:
parent
3bc940063a
commit
5c718fc14b
29 changed files with 1263 additions and 170 deletions
|
@ -1,29 +0,0 @@
|
||||||
<component name="ProjectCodeStyleConfiguration">
|
|
||||||
<code_scheme name="Project" version="173">
|
|
||||||
<Objective-C-extensions>
|
|
||||||
<file>
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
|
|
||||||
</file>
|
|
||||||
<class>
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
|
|
||||||
</class>
|
|
||||||
<extensions>
|
|
||||||
<pair source="cpp" header="h" fileNamingConvention="NONE" />
|
|
||||||
<pair source="c" header="h" fileNamingConvention="NONE" />
|
|
||||||
</extensions>
|
|
||||||
</Objective-C-extensions>
|
|
||||||
</code_scheme>
|
|
||||||
</component>
|
|
|
@ -1,6 +1,6 @@
|
||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="main.dart" type="FlutterRunConfigurationType" factoryName="Flutter">
|
<configuration default="false" name="main.dart" type="FlutterRunConfigurationType" factoryName="Flutter" singleton="false">
|
||||||
<option name="filePath" value="$PROJECT_DIR$/lib/main.dart" />
|
<option name="filePath" value="$PROJECT_DIR$/lib/main.dart" />
|
||||||
<method />
|
<method v="2" />
|
||||||
</configuration>
|
</configuration>
|
||||||
</component>
|
</component>
|
|
@ -15,6 +15,12 @@ For help getting started with Flutter, view our
|
||||||
[online documentation](https://flutter.io/docs), which offers tutorials,
|
[online documentation](https://flutter.io/docs), which offers tutorials,
|
||||||
samples, guidance on mobile development, and a full API reference.
|
samples, guidance on mobile development, and a full API reference.
|
||||||
|
|
||||||
|
## Environments
|
||||||
|
|
||||||
|
To build an apk from dev, use:
|
||||||
|
flutter build apk -t lib/main_dev.dart
|
||||||
|
|
||||||
## Links and Things
|
## Links and Things
|
||||||
|
|
||||||
https://github.com/putraxor/flutter-login-ui
|
https://github.com/putraxor/flutter-login-ui
|
||||||
|
https://github.com/pbirdsall/medium_splash_tokenauth
|
50
lib/common/apifunctions/request_login_api.dart
Normal file
50
lib/common/apifunctions/request_login_api.dart
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:local_spend/common/functions/save_current_login.dart';
|
||||||
|
import 'package:local_spend/common/functions/show_dialog_single_button.dart';
|
||||||
|
import 'package:local_spend/model/json/login_model.dart';
|
||||||
|
import 'package:local_spend/config.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
|
||||||
|
Future<LoginModel> requestLoginAPI(
|
||||||
|
BuildContext context, String email, String password) async {
|
||||||
|
//var apiUrl = ConfigWrapper.of(context).apiKey;
|
||||||
|
final url = "https://dev.peartrade.org/api/login";
|
||||||
|
|
||||||
|
Map<String, String> body = {
|
||||||
|
'email': email,
|
||||||
|
'password': password,
|
||||||
|
};
|
||||||
|
|
||||||
|
debugPrint('$body');
|
||||||
|
|
||||||
|
final response = await http.post(
|
||||||
|
url,
|
||||||
|
body: body,
|
||||||
|
);
|
||||||
|
|
||||||
|
debugPrint(response.body);
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
final responseJson = json.decode(response.body);
|
||||||
|
var user = new LoginModel.fromJson(responseJson);
|
||||||
|
|
||||||
|
saveCurrentLogin(responseJson);
|
||||||
|
Navigator.of(context).pushReplacementNamed('/HomePage');
|
||||||
|
|
||||||
|
return LoginModel.fromJson(responseJson);
|
||||||
|
} else {
|
||||||
|
final responseJson = json.decode(response.body);
|
||||||
|
|
||||||
|
saveCurrentLogin(responseJson);
|
||||||
|
showDialogSingleButton(
|
||||||
|
context,
|
||||||
|
"Unable to Login",
|
||||||
|
"You may have supplied an invalid 'Email' / 'Password' combination. Please try again or email an administrator.",
|
||||||
|
"OK");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
31
lib/common/apifunctions/request_logout_api.dart
Normal file
31
lib/common/apifunctions/request_logout_api.dart
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
import 'dart:io';
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:local_spend/common/functions/get_token.dart';
|
||||||
|
import 'package:local_spend/common/functions/save_logout.dart';
|
||||||
|
import 'package:local_spend/model/json/login_model.dart';
|
||||||
|
|
||||||
|
Future<LoginModel> requestLogoutAPI(BuildContext context) async {
|
||||||
|
final url = "https://www.yoururl.com/logout";
|
||||||
|
|
||||||
|
var token;
|
||||||
|
|
||||||
|
await getToken().then((result) {
|
||||||
|
token = result;
|
||||||
|
});
|
||||||
|
|
||||||
|
final response = await http.post(
|
||||||
|
url,
|
||||||
|
headers: {HttpHeaders.authorizationHeader: "Token $token"},
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
saveLogout();
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
saveLogout();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
8
lib/common/functions/get_token.dart
Normal file
8
lib/common/functions/get_token.dart
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
|
getToken() async {
|
||||||
|
SharedPreferences preferences = await SharedPreferences.getInstance();
|
||||||
|
|
||||||
|
String getToken = await preferences.getString("LastToken");
|
||||||
|
return getToken;
|
||||||
|
}
|
30
lib/common/functions/save_current_login.dart
Normal file
30
lib/common/functions/save_current_login.dart
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import 'package:local_spend/model/json/login_model.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
|
saveCurrentLogin(Map responseJson) async {
|
||||||
|
SharedPreferences preferences = await SharedPreferences.getInstance();
|
||||||
|
|
||||||
|
var user;
|
||||||
|
if ((responseJson != null && responseJson.isNotEmpty)) {
|
||||||
|
user = LoginModel.fromJson(responseJson).userName;
|
||||||
|
} else {
|
||||||
|
user = "";
|
||||||
|
}
|
||||||
|
var token = (responseJson != null && responseJson.isNotEmpty)
|
||||||
|
? LoginModel.fromJson(responseJson).token
|
||||||
|
: "";
|
||||||
|
var email = (responseJson != null && responseJson.isNotEmpty)
|
||||||
|
? LoginModel.fromJson(responseJson).email
|
||||||
|
: "";
|
||||||
|
var pk = (responseJson != null && responseJson.isNotEmpty)
|
||||||
|
? LoginModel.fromJson(responseJson).userId
|
||||||
|
: 0;
|
||||||
|
|
||||||
|
await preferences.setString(
|
||||||
|
'LastUser', (user != null && user.length > 0) ? user : "");
|
||||||
|
await preferences.setString(
|
||||||
|
'LastToken', (token != null && token.length > 0) ? token : "");
|
||||||
|
await preferences.setString(
|
||||||
|
'LastEmail', (email != null && email.length > 0) ? email : "");
|
||||||
|
await preferences.setInt('LastUserId', (pk != null && pk > 0) ? pk : 0);
|
||||||
|
}
|
10
lib/common/functions/save_logout.dart
Normal file
10
lib/common/functions/save_logout.dart
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
|
saveLogout() async {
|
||||||
|
SharedPreferences preferences = await SharedPreferences.getInstance();
|
||||||
|
|
||||||
|
await preferences.setString('LastUser', "");
|
||||||
|
await preferences.setString('LastToken', "");
|
||||||
|
await preferences.setString('LastEmail', "");
|
||||||
|
await preferences.setInt('LastUserId', 0);
|
||||||
|
}
|
25
lib/common/functions/show_dialog_single_button.dart
Normal file
25
lib/common/functions/show_dialog_single_button.dart
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
void showDialogSingleButton(
|
||||||
|
BuildContext context, String title, String message, String buttonLabel) {
|
||||||
|
// flutter defined function
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
// return object of type Dialog
|
||||||
|
return AlertDialog(
|
||||||
|
title: new Text(title),
|
||||||
|
content: new Text(message),
|
||||||
|
actions: <Widget>[
|
||||||
|
// usually buttons at the bottom of the dialog
|
||||||
|
new FlatButton(
|
||||||
|
child: new Text(buttonLabel),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
72
lib/common/platform/platform_scaffold.dart
Normal file
72
lib/common/platform/platform_scaffold.dart
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class PlatformScaffold extends StatelessWidget {
|
||||||
|
final Key key;
|
||||||
|
final PreferredSizeWidget appBar;
|
||||||
|
final Widget body;
|
||||||
|
final Widget floatingActionButton;
|
||||||
|
final FloatingActionButtonLocation floatingActionButtonLocation;
|
||||||
|
final FloatingActionButtonAnimator floatingActionButtonAnimator;
|
||||||
|
final List<Widget> persistentFooterButtons;
|
||||||
|
final Widget drawer;
|
||||||
|
final Widget endDrawer;
|
||||||
|
final Widget bottomNavigationBar;
|
||||||
|
final Color backgroundColor;
|
||||||
|
final bool resizeToAvoidBottomPadding;
|
||||||
|
final bool primary;
|
||||||
|
|
||||||
|
PlatformScaffold(
|
||||||
|
{this.key,
|
||||||
|
this.appBar,
|
||||||
|
this.body,
|
||||||
|
this.floatingActionButton,
|
||||||
|
this.floatingActionButtonLocation,
|
||||||
|
this.floatingActionButtonAnimator,
|
||||||
|
this.persistentFooterButtons,
|
||||||
|
this.drawer,
|
||||||
|
this.endDrawer,
|
||||||
|
this.bottomNavigationBar,
|
||||||
|
this.backgroundColor,
|
||||||
|
this.resizeToAvoidBottomPadding: true,
|
||||||
|
this.primary: true})
|
||||||
|
: assert(primary != null),
|
||||||
|
super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Platform.isIOS
|
||||||
|
? Scaffold(
|
||||||
|
key: key,
|
||||||
|
appBar: appBar,
|
||||||
|
body: body,
|
||||||
|
floatingActionButton: floatingActionButton,
|
||||||
|
persistentFooterButtons: persistentFooterButtons,
|
||||||
|
floatingActionButtonLocation: floatingActionButtonLocation,
|
||||||
|
floatingActionButtonAnimator: floatingActionButtonAnimator,
|
||||||
|
drawer: endDrawer,
|
||||||
|
endDrawer: drawer,
|
||||||
|
bottomNavigationBar: bottomNavigationBar,
|
||||||
|
backgroundColor: backgroundColor,
|
||||||
|
resizeToAvoidBottomPadding: resizeToAvoidBottomPadding,
|
||||||
|
primary: primary,
|
||||||
|
)
|
||||||
|
: Scaffold(
|
||||||
|
key: key,
|
||||||
|
appBar: appBar,
|
||||||
|
body: body,
|
||||||
|
floatingActionButton: floatingActionButton,
|
||||||
|
persistentFooterButtons: persistentFooterButtons,
|
||||||
|
floatingActionButtonLocation: floatingActionButtonLocation,
|
||||||
|
floatingActionButtonAnimator: floatingActionButtonAnimator,
|
||||||
|
drawer: drawer,
|
||||||
|
endDrawer: endDrawer,
|
||||||
|
bottomNavigationBar: bottomNavigationBar,
|
||||||
|
backgroundColor: backgroundColor,
|
||||||
|
resizeToAvoidBottomPadding: resizeToAvoidBottomPadding,
|
||||||
|
primary: primary,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
54
lib/common/widgets/basic_drawer.dart
Normal file
54
lib/common/widgets/basic_drawer.dart
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:local_spend/common/apifunctions/request_logout_api.dart';
|
||||||
|
|
||||||
|
class BasicDrawer extends StatefulWidget {
|
||||||
|
@override
|
||||||
|
_BasicDrawerState createState() => _BasicDrawerState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _BasicDrawerState extends State<BasicDrawer> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Drawer(
|
||||||
|
child: Container(
|
||||||
|
padding: new EdgeInsets.all(32.0),
|
||||||
|
child: ListView(
|
||||||
|
children: <Widget>[
|
||||||
|
ListTile(
|
||||||
|
title: Text(
|
||||||
|
"Submit Receipt",
|
||||||
|
style: TextStyle(color: Colors.black, fontSize: 20.0),
|
||||||
|
),
|
||||||
|
onTap: () {
|
||||||
|
requestLogoutAPI(context);
|
||||||
|
Navigator.of(context).pushNamed('/ReceiptPage');
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
title: Text(
|
||||||
|
"About",
|
||||||
|
style: TextStyle(color: Colors.black, fontSize: 20.0),
|
||||||
|
),
|
||||||
|
onTap: () {
|
||||||
|
SystemChannels.textInput.invokeMethod('TextInput.hide');
|
||||||
|
// Here I have not implemented an actual about screen, but if you did you would navigate to it's route
|
||||||
|
// Navigator.of(context).pushReplacementNamed('/AboutScreen');
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
title: Text(
|
||||||
|
"Logout",
|
||||||
|
style: TextStyle(color: Colors.black, fontSize: 20.0),
|
||||||
|
),
|
||||||
|
onTap: () {
|
||||||
|
requestLogoutAPI(context);
|
||||||
|
Navigator.of(context).pushReplacementNamed('/LoginPage');
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
46
lib/config.dart
Normal file
46
lib/config.dart
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
|
|
||||||
|
part 'config.g.dart';
|
||||||
|
|
||||||
|
@JsonSerializable(createToJson: false)
|
||||||
|
class Config {
|
||||||
|
final String env;
|
||||||
|
final bool production;
|
||||||
|
final String apiKey;
|
||||||
|
|
||||||
|
Config({this.env, this.production, this.apiKey});
|
||||||
|
|
||||||
|
factory Config.fromJson(Map<String, dynamic> json) => _$ConfigFromJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
class ConfigWrapper extends StatelessWidget {
|
||||||
|
ConfigWrapper({Key key, this.config, this.child});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return new _InheritedConfig(config: this.config, child: this.child);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Config of(BuildContext context) {
|
||||||
|
final _InheritedConfig inheritedConfig =
|
||||||
|
context.inheritFromWidgetOfExactType(_InheritedConfig);
|
||||||
|
return inheritedConfig.config;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Config config;
|
||||||
|
final Widget child;
|
||||||
|
}
|
||||||
|
|
||||||
|
class _InheritedConfig extends InheritedWidget {
|
||||||
|
const _InheritedConfig(
|
||||||
|
{Key key, @required this.config, @required Widget child})
|
||||||
|
: assert(config != null),
|
||||||
|
assert(child != null),
|
||||||
|
super(key: key, child: child);
|
||||||
|
final Config config;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool updateShouldNotify(_InheritedConfig oldWidget) =>
|
||||||
|
config != oldWidget.config;
|
||||||
|
}
|
14
lib/config.g.dart
Normal file
14
lib/config.g.dart
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'config.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonSerializableGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
Config _$ConfigFromJson(Map<String, dynamic> json) {
|
||||||
|
return Config(
|
||||||
|
env: json['env'] as String,
|
||||||
|
production: json['production'] as bool,
|
||||||
|
apiKey: json['apiKey'] as String);
|
||||||
|
}
|
6
lib/env/dev.dart
vendored
Normal file
6
lib/env/dev.dart
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
|
|
||||||
|
part 'dev.g.dart';
|
||||||
|
|
||||||
|
@JsonLiteral('dev.json', asConst: true)
|
||||||
|
Map<String, dynamic> get config => _$configJsonLiteral;
|
13
lib/env/dev.g.dart
vendored
Normal file
13
lib/env/dev.g.dart
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'dev.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonLiteralGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
const _$configJsonLiteral = {
|
||||||
|
'env': 'DEV',
|
||||||
|
'production': false,
|
||||||
|
'apiUrl': 'https://dev.peartrade.org/api'
|
||||||
|
};
|
5
lib/env/dev.json
vendored
Normal file
5
lib/env/dev.json
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"env": "DEV",
|
||||||
|
"production": false,
|
||||||
|
"apiUrl": "https://dev.peartrade.org/api"
|
||||||
|
}
|
6
lib/env/prod.dart
vendored
Normal file
6
lib/env/prod.dart
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
|
|
||||||
|
part 'prod.g.dart';
|
||||||
|
|
||||||
|
@JsonLiteral('prod.json', asConst: true)
|
||||||
|
Map<String, dynamic> get config => _$configJsonLiteral;
|
13
lib/env/prod.g.dart
vendored
Normal file
13
lib/env/prod.g.dart
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'prod.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonLiteralGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
const _$configJsonLiteral = {
|
||||||
|
'env': 'PROD',
|
||||||
|
'production': true,
|
||||||
|
'apiUrl': 'https://www.peartrade.org/api'
|
||||||
|
};
|
5
lib/env/prod.json
vendored
Normal file
5
lib/env/prod.json
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"env": "PROD",
|
||||||
|
"production": true,
|
||||||
|
"apiUrl": "https://www.peartrade.org/api"
|
||||||
|
}
|
|
@ -1,125 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class LoginPage extends StatefulWidget {
|
|
||||||
|
|
||||||
@override
|
|
||||||
_LoginPageState createState() => _LoginPageState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _LoginPageState extends State<LoginPage> {
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
|
|
||||||
final email = TextFormField(
|
|
||||||
keyboardType: TextInputType.emailAddress,
|
|
||||||
autofocus: true,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
hintText: 'Email',
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
final password = TextFormField(
|
|
||||||
autofocus: false,
|
|
||||||
obscureText: true,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
hintText: 'Password',
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
return Scaffold(
|
|
||||||
body: Center(
|
|
||||||
child: ListView(
|
|
||||||
children: <Widget>[
|
|
||||||
email,
|
|
||||||
password
|
|
||||||
]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MyHomePage extends StatefulWidget {
|
|
||||||
MyHomePage({Key key, this.title}) : super(key: key);
|
|
||||||
|
|
||||||
// This widget is the home page of your application. It is stateful, meaning
|
|
||||||
// that it has a State object (defined below) that contains fields that affect
|
|
||||||
// how it looks.
|
|
||||||
|
|
||||||
// This class is the configuration for the state. It holds the values (in this
|
|
||||||
// case the title) provided by the parent (in this case the App widget) and
|
|
||||||
// used by the build method of the State. Fields in a Widget subclass are
|
|
||||||
// always marked "final".
|
|
||||||
|
|
||||||
final String title;
|
|
||||||
|
|
||||||
@override
|
|
||||||
_MyHomePageState createState() => _MyHomePageState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _MyHomePageState extends State<MyHomePage> {
|
|
||||||
int _counter = 0;
|
|
||||||
|
|
||||||
void _incrementCounter() {
|
|
||||||
setState(() {
|
|
||||||
// This call to setState tells the Flutter framework that something has
|
|
||||||
// changed in this State, which causes it to rerun the build method below
|
|
||||||
// so that the display can reflect the updated values. If we changed
|
|
||||||
// _counter without calling setState(), then the build method would not be
|
|
||||||
// called again, and so nothing would appear to happen.
|
|
||||||
_counter++;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
// This method is rerun every time setState is called, for instance as done
|
|
||||||
// by the _incrementCounter method above.
|
|
||||||
//
|
|
||||||
// The Flutter framework has been optimized to make rerunning build methods
|
|
||||||
// fast, so that you can just rebuild anything that needs updating rather
|
|
||||||
// than having to individually change instances of widgets.
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
// Here we take the value from the MyHomePage object that was created by
|
|
||||||
// the App.build method, and use it to set our appbar title.
|
|
||||||
title: Text(widget.title + 'derpaderp'),
|
|
||||||
),
|
|
||||||
body: Center(
|
|
||||||
// Center is a layout widget. It takes a single child and positions it
|
|
||||||
// in the middle of the parent.
|
|
||||||
child: Column(
|
|
||||||
// Column is also layout widget. It takes a list of children and
|
|
||||||
// arranges them vertically. By default, it sizes itself to fit its
|
|
||||||
// children horizontally, and tries to be as tall as its parent.
|
|
||||||
//
|
|
||||||
// Invoke "debug painting" (press "p" in the console, choose the
|
|
||||||
// "Toggle Debug Paint" action from the Flutter Inspector in Android
|
|
||||||
// Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
|
|
||||||
// to see the wireframe for each widget.
|
|
||||||
//
|
|
||||||
// Column has various properties to control how it sizes itself and
|
|
||||||
// how it positions its children. Here we use mainAxisAlignment to
|
|
||||||
// center the children vertically; the main axis here is the vertical
|
|
||||||
// axis because Columns are vertical (the cross axis would be
|
|
||||||
// horizontal).
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: <Widget>[
|
|
||||||
Text(
|
|
||||||
'You have pushed the button this many times:',
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
'$_counter',
|
|
||||||
style: Theme.of(context).textTheme.display1,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
floatingActionButton: FloatingActionButton(
|
|
||||||
onPressed: _incrementCounter,
|
|
||||||
tooltip: 'Increment',
|
|
||||||
child: Icon(Icons.add),
|
|
||||||
), // This trailing comma makes auto-formatting nicer for build methods.
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,18 +1,29 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:local_spend/login_page.dart';
|
import 'package:local_spend/pages/home_page.dart';
|
||||||
|
import 'package:local_spend/pages/login_page.dart';
|
||||||
|
import 'package:local_spend/pages/receipt_page.dart';
|
||||||
|
import 'package:local_spend/pages/spash_screen.dart';
|
||||||
|
import 'package:local_spend/config.dart';
|
||||||
|
|
||||||
void main() => runApp(MyApp());
|
void main() {
|
||||||
|
runApp(MyApp());
|
||||||
|
}
|
||||||
|
|
||||||
class MyApp extends StatelessWidget {
|
class MyApp extends StatelessWidget {
|
||||||
// This widget is the root of your application.
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MaterialApp(
|
//var config = ConfigWrapper.of(context);
|
||||||
title: 'LocalSpend Tracker',
|
return new MaterialApp(
|
||||||
theme: ThemeData(
|
title: "Splash and Token Authentication",
|
||||||
primarySwatch: Colors.blueGrey,
|
// theme: new ThemeData(
|
||||||
),
|
// primarySwatch: config.production ? Colors.green : Colors.yellow,
|
||||||
home: LoginPage(),
|
// ),
|
||||||
|
routes: <String, WidgetBuilder>{
|
||||||
|
"/HomePage": (BuildContext context) => HomePage(),
|
||||||
|
"/LoginPage": (BuildContext context) => LoginPage(),
|
||||||
|
"/ReceiptPage": (BuildContext context) => ReceiptPage(),
|
||||||
|
},
|
||||||
|
home: SplashScreen(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
7
lib/main_dev.dart
Normal file
7
lib/main_dev.dart
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:local_spend/config.dart';
|
||||||
|
import 'package:local_spend/env/dev.dart';
|
||||||
|
import 'package:local_spend/main.dart';
|
||||||
|
|
||||||
|
void main() => runApp(
|
||||||
|
new ConfigWrapper(config: Config.fromJson(config), child: new MyApp()));
|
21
lib/model/json/login_model.dart
Normal file
21
lib/model/json/login_model.dart
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
class LoginModel {
|
||||||
|
final String userName;
|
||||||
|
final String token;
|
||||||
|
final String email;
|
||||||
|
final int userId;
|
||||||
|
|
||||||
|
LoginModel(this.userName, this.token, this.email, this.userId);
|
||||||
|
|
||||||
|
LoginModel.fromJson(Map<String, dynamic> json)
|
||||||
|
: userName = json['name'],
|
||||||
|
token = json['token'],
|
||||||
|
email = json['email'],
|
||||||
|
userId = json['pk'];
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => {
|
||||||
|
'name': userName,
|
||||||
|
'token': token,
|
||||||
|
'email': email,
|
||||||
|
'pk': userId,
|
||||||
|
};
|
||||||
|
}
|
49
lib/pages/home_page.dart
Normal file
49
lib/pages/home_page.dart
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:local_spend/common/platform/platform_scaffold.dart';
|
||||||
|
import 'package:local_spend/common/widgets/basic_drawer.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
|
class HomePage extends StatefulWidget {
|
||||||
|
@override
|
||||||
|
_HomePageState createState() => _HomePageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _HomePageState extends State<HomePage> {
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_saveCurrentRoute("/HomePage");
|
||||||
|
}
|
||||||
|
|
||||||
|
_saveCurrentRoute(String lastRoute) async {
|
||||||
|
SharedPreferences preferences = await SharedPreferences.getInstance();
|
||||||
|
await preferences.setString('LastScreenRoute', lastRoute);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return PlatformScaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(
|
||||||
|
"Home Page",
|
||||||
|
style: TextStyle(color: Colors.black),
|
||||||
|
),
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
iconTheme: IconThemeData(color: Colors.black),
|
||||||
|
elevation: Theme.of(context).platform == TargetPlatform.iOS ? 0.0 : 6.0,
|
||||||
|
),
|
||||||
|
drawer: BasicDrawer(),
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
body: Container(
|
||||||
|
padding: EdgeInsets.all(32.0),
|
||||||
|
child: Center(
|
||||||
|
child: Column(
|
||||||
|
children: <Widget>[
|
||||||
|
Text('This is the Home page'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
188
lib/pages/login_page.dart
Normal file
188
lib/pages/login_page.dart
Normal file
|
@ -0,0 +1,188 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/gestures.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:local_spend/common/apifunctions/request_login_api.dart';
|
||||||
|
import 'package:local_spend/common/functions/show_dialog_single_button.dart';
|
||||||
|
import 'package:local_spend/common/platform/platform_scaffold.dart';
|
||||||
|
import 'package:local_spend/common/widgets/basic_drawer.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
|
const URL = "https://flutter.io/";
|
||||||
|
|
||||||
|
class LoginPage extends StatefulWidget {
|
||||||
|
@override
|
||||||
|
State<StatefulWidget> createState() {
|
||||||
|
return new LoginPageState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LoginPageState extends State<LoginPage> {
|
||||||
|
final TextEditingController _emailController = TextEditingController();
|
||||||
|
final TextEditingController _passwordController = TextEditingController();
|
||||||
|
String _welcomeString = "";
|
||||||
|
|
||||||
|
Future launchURL(String url) async {
|
||||||
|
if (await canLaunch(url)) {
|
||||||
|
await launch(url, forceSafariVC: true, forceWebView: true);
|
||||||
|
} else {
|
||||||
|
showDialogSingleButton(
|
||||||
|
context,
|
||||||
|
"Unable to reach your website.",
|
||||||
|
"Currently unable to reach the website $URL. Please try again at a later time.",
|
||||||
|
"OK");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_saveCurrentRoute("/LoginPage");
|
||||||
|
}
|
||||||
|
|
||||||
|
_saveCurrentRoute(String lastRoute) async {
|
||||||
|
SharedPreferences preferences = await SharedPreferences.getInstance();
|
||||||
|
await preferences.setString('LastPageRoute', lastRoute);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
var drawer = Drawer();
|
||||||
|
return WillPopScope(
|
||||||
|
onWillPop: () {
|
||||||
|
if (Navigator.canPop(context)) {
|
||||||
|
Navigator.of(context).pushNamedAndRemoveUntil(
|
||||||
|
'/HomePage', (Route<dynamic> route) => false);
|
||||||
|
} else {
|
||||||
|
Navigator.of(context).pushReplacementNamed('/HomePage');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: PlatformScaffold(
|
||||||
|
drawer: BasicDrawer(),
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(
|
||||||
|
"LOGIN",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 30.0,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
centerTitle: true,
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
iconTheme: IconThemeData(color: Colors.black),
|
||||||
|
),
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
body: Container(
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.fromLTRB(30.0, 0.0, 30.0, 0.0),
|
||||||
|
child: ListView(
|
||||||
|
children: <Widget>[
|
||||||
|
Container(
|
||||||
|
alignment: Alignment.topCenter,
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.fromLTRB(0.0, 40.0, 0.0, 15.0),
|
||||||
|
child: Text(
|
||||||
|
"Local Loop",
|
||||||
|
style: TextStyle(fontSize: 40.0, color: Colors.black),
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.fromLTRB(0.0, 5.0, 0.0, 78.0),
|
||||||
|
child: RichText(
|
||||||
|
text: TextSpan(
|
||||||
|
children: [
|
||||||
|
TextSpan(
|
||||||
|
text:
|
||||||
|
'This is the logon page.',
|
||||||
|
style: new TextStyle(
|
||||||
|
fontSize: 20.0,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
TextSpan(
|
||||||
|
text:
|
||||||
|
' It is currently in development.',
|
||||||
|
style: new TextStyle(
|
||||||
|
fontSize: 20.0,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"Email",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 18.0,
|
||||||
|
color: Colors.black,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.fromLTRB(0.0, 5.0, 0.0, 0.0),
|
||||||
|
child: TextField(
|
||||||
|
controller: _emailController,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: "Use your login email",
|
||||||
|
),
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 18.0,
|
||||||
|
color: Colors.grey,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.fromLTRB(0.0, 35.0, 0.0, 0.0),
|
||||||
|
child: Text(
|
||||||
|
"Password",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 18.0,
|
||||||
|
color: Colors.black,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.fromLTRB(0.0, 5.0, 0.0, 0.0),
|
||||||
|
child: TextField(
|
||||||
|
controller: _passwordController,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: 'Your password, keep it secret, keep it safe.',
|
||||||
|
),
|
||||||
|
obscureText: true,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 18.0,
|
||||||
|
color: Colors.grey,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.fromLTRB(0.0, 70.0, 0.0, 0.0),
|
||||||
|
child: Container(
|
||||||
|
height: 65.0,
|
||||||
|
child: RaisedButton(
|
||||||
|
onPressed: () {
|
||||||
|
SystemChannels.textInput.invokeMethod('TextInput.hide');
|
||||||
|
requestLoginAPI(context, _emailController.text,
|
||||||
|
_passwordController.text);
|
||||||
|
},
|
||||||
|
child: Text("LOGIN",
|
||||||
|
style:
|
||||||
|
TextStyle(color: Colors.white, fontSize: 22.0)),
|
||||||
|
color: Colors.blue,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
187
lib/pages/receipt_page.dart
Normal file
187
lib/pages/receipt_page.dart
Normal file
|
@ -0,0 +1,187 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:local_spend/common/apifunctions/request_login_api.dart';
|
||||||
|
import 'package:local_spend/common/functions/show_dialog_single_button.dart';
|
||||||
|
import 'package:local_spend/common/platform/platform_scaffold.dart';
|
||||||
|
import 'package:local_spend/common/widgets/basic_drawer.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
|
const URL = "https://flutter.io/";
|
||||||
|
|
||||||
|
class ReceiptPage extends StatefulWidget {
|
||||||
|
@override
|
||||||
|
State<StatefulWidget> createState() {
|
||||||
|
return new ReceiptPageState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ReceiptPageState extends State<ReceiptPage> {
|
||||||
|
final TextEditingController _emailController = TextEditingController();
|
||||||
|
final TextEditingController _passwordController = TextEditingController();
|
||||||
|
String _welcomeString = "";
|
||||||
|
|
||||||
|
Future launchURL(String url) async {
|
||||||
|
if (await canLaunch(url)) {
|
||||||
|
await launch(url, forceSafariVC: true, forceWebView: true);
|
||||||
|
} else {
|
||||||
|
showDialogSingleButton(
|
||||||
|
context,
|
||||||
|
"Unable to reach your website.",
|
||||||
|
"Currently unable to reach the website $URL. Please try again at a later time.",
|
||||||
|
"OK");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_saveCurrentRoute("/LoginPage");
|
||||||
|
}
|
||||||
|
|
||||||
|
_saveCurrentRoute(String lastRoute) async {
|
||||||
|
SharedPreferences preferences = await SharedPreferences.getInstance();
|
||||||
|
await preferences.setString('LastPageRoute', lastRoute);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
var drawer = Drawer();
|
||||||
|
return WillPopScope(
|
||||||
|
onWillPop: () {
|
||||||
|
if (Navigator.canPop(context)) {
|
||||||
|
Navigator.of(context).pushNamedAndRemoveUntil(
|
||||||
|
'/HomePage', (Route<dynamic> route) => false);
|
||||||
|
} else {
|
||||||
|
Navigator.of(context).pushReplacementNamed('/HomePage');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: PlatformScaffold(
|
||||||
|
drawer: BasicDrawer(),
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(
|
||||||
|
"LOGIN",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 30.0,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
centerTitle: true,
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
iconTheme: IconThemeData(color: Colors.black),
|
||||||
|
),
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
body: Container(
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.fromLTRB(30.0, 0.0, 30.0, 0.0),
|
||||||
|
child: ListView(
|
||||||
|
children: <Widget>[
|
||||||
|
Container(
|
||||||
|
alignment: Alignment.topCenter,
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.fromLTRB(0.0, 40.0, 0.0, 15.0),
|
||||||
|
child: Text(
|
||||||
|
"Local Loop",
|
||||||
|
style: TextStyle(fontSize: 40.0, color: Colors.black),
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.fromLTRB(0.0, 5.0, 0.0, 78.0),
|
||||||
|
child: RichText(
|
||||||
|
text: TextSpan(
|
||||||
|
children: [
|
||||||
|
TextSpan(
|
||||||
|
text:
|
||||||
|
'This is the logon page.',
|
||||||
|
style: new TextStyle(
|
||||||
|
fontSize: 20.0,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
TextSpan(
|
||||||
|
text:
|
||||||
|
' It is currently in development.',
|
||||||
|
style: new TextStyle(
|
||||||
|
fontSize: 20.0,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"Email",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 18.0,
|
||||||
|
color: Colors.black,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.fromLTRB(0.0, 5.0, 0.0, 0.0),
|
||||||
|
child: TextField(
|
||||||
|
controller: _emailController,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: "Use your login email",
|
||||||
|
),
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 18.0,
|
||||||
|
color: Colors.grey,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.fromLTRB(0.0, 35.0, 0.0, 0.0),
|
||||||
|
child: Text(
|
||||||
|
"Password",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 18.0,
|
||||||
|
color: Colors.black,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.fromLTRB(0.0, 5.0, 0.0, 0.0),
|
||||||
|
child: TextField(
|
||||||
|
controller: _passwordController,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: 'Your password, keep it secret, keep it safe.',
|
||||||
|
),
|
||||||
|
obscureText: true,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 18.0,
|
||||||
|
color: Colors.grey,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.fromLTRB(0.0, 70.0, 0.0, 0.0),
|
||||||
|
child: Container(
|
||||||
|
height: 65.0,
|
||||||
|
child: RaisedButton(
|
||||||
|
onPressed: () {
|
||||||
|
SystemChannels.textInput.invokeMethod('TextInput.hide');
|
||||||
|
requestLoginAPI(context, _emailController.text,
|
||||||
|
_passwordController.text);
|
||||||
|
},
|
||||||
|
child: Text("LOGIN",
|
||||||
|
style:
|
||||||
|
TextStyle(color: Colors.white, fontSize: 22.0)),
|
||||||
|
color: Colors.blue,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
61
lib/pages/spash_screen.dart
Normal file
61
lib/pages/spash_screen.dart
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:local_spend/common/platform/platform_scaffold.dart';
|
||||||
|
|
||||||
|
class SplashScreen extends StatefulWidget {
|
||||||
|
@override
|
||||||
|
_SplashScreenState createState() => _SplashScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SplashScreenState extends State<SplashScreen> {
|
||||||
|
final int splashDuration = 3;
|
||||||
|
|
||||||
|
startTime() async {
|
||||||
|
return Timer(Duration(seconds: splashDuration), () {
|
||||||
|
SystemChannels.textInput.invokeMethod('TextInput.hide');
|
||||||
|
Navigator.of(context).pushReplacementNamed('/HomePage');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
startTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
var drawer = Drawer();
|
||||||
|
|
||||||
|
return PlatformScaffold(
|
||||||
|
drawer: drawer,
|
||||||
|
body: Container(
|
||||||
|
decoration: BoxDecoration(color: Colors.black),
|
||||||
|
child: Column(
|
||||||
|
children: <Widget>[
|
||||||
|
Expanded(
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(color: Colors.black),
|
||||||
|
alignment: FractionalOffset(0.5, 0.3),
|
||||||
|
child: Text(
|
||||||
|
"Local Loop",
|
||||||
|
style: TextStyle(fontSize: 40.0, color: Colors.white),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
margin: EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 30.0),
|
||||||
|
child: Text(
|
||||||
|
"© Copyright Statement 2018",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16.0,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
331
pubspec.lock
331
pubspec.lock
|
@ -1,6 +1,20 @@
|
||||||
# Generated by pub
|
# Generated by pub
|
||||||
# See https://www.dartlang.org/tools/pub/glossary#lockfile
|
# See https://www.dartlang.org/tools/pub/glossary#lockfile
|
||||||
packages:
|
packages:
|
||||||
|
analyzer:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: analyzer
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.36.2"
|
||||||
|
args:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: args
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.5.1"
|
||||||
async:
|
async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -15,6 +29,62 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.4"
|
version: "1.0.4"
|
||||||
|
build:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: build
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.4"
|
||||||
|
build_config:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: build_config
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.3.2"
|
||||||
|
build_daemon:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: build_daemon
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.5.0"
|
||||||
|
build_resolvers:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: build_resolvers
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.4"
|
||||||
|
build_runner:
|
||||||
|
dependency: "direct dev"
|
||||||
|
description:
|
||||||
|
name: build_runner
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.3.3"
|
||||||
|
build_runner_core:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: build_runner_core
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.3"
|
||||||
|
built_collection:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: built_collection
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "4.2.0"
|
||||||
|
built_value:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: built_value
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "6.4.0"
|
||||||
charcode:
|
charcode:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -22,6 +92,13 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.2"
|
version: "1.1.2"
|
||||||
|
code_builder:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: code_builder
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "3.2.0"
|
||||||
collection:
|
collection:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -29,6 +106,27 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.14.11"
|
version: "1.14.11"
|
||||||
|
convert:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: convert
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.1"
|
||||||
|
crypto:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: crypto
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.6"
|
||||||
|
csslib:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: csslib
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.16.0"
|
||||||
cupertino_icons:
|
cupertino_icons:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -36,6 +134,20 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.1.2"
|
version: "0.1.2"
|
||||||
|
dart_style:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: dart_style
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.7"
|
||||||
|
fixnum:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: fixnum
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.10.9"
|
||||||
flutter:
|
flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description: flutter
|
description: flutter
|
||||||
|
@ -46,6 +158,97 @@ packages:
|
||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
front_end:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: front_end
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.1.17"
|
||||||
|
glob:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: glob
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.7"
|
||||||
|
graphs:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: graphs
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.2.0"
|
||||||
|
html:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: html
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.14.0+2"
|
||||||
|
http:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: http
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.12.0+2"
|
||||||
|
http_multi_server:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: http_multi_server
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.6"
|
||||||
|
http_parser:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: http_parser
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.3"
|
||||||
|
io:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: io
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.3.3"
|
||||||
|
js:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: js
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.6.1+1"
|
||||||
|
json_annotation:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: json_annotation
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.0"
|
||||||
|
json_serializable:
|
||||||
|
dependency: "direct dev"
|
||||||
|
description:
|
||||||
|
name: json_serializable
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.1"
|
||||||
|
kernel:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: kernel
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.3.17"
|
||||||
|
logging:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: logging
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.11.3+2"
|
||||||
matcher:
|
matcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -60,6 +263,27 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.6"
|
version: "1.1.6"
|
||||||
|
mime:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: mime
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.9.6+2"
|
||||||
|
package_config:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: package_config
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.5"
|
||||||
|
package_resolver:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: package_resolver
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.10"
|
||||||
path:
|
path:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -67,6 +291,34 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.6.2"
|
version: "1.6.2"
|
||||||
|
pedantic:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: pedantic
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.4.0"
|
||||||
|
pool:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: pool
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.4.0"
|
||||||
|
pub_semver:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: pub_semver
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.4.2"
|
||||||
|
pubspec_parse:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: pubspec_parse
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.1.4"
|
||||||
quiver:
|
quiver:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -74,18 +326,46 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.1"
|
version: "2.0.1"
|
||||||
|
shared_preferences:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: shared_preferences
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.4.3"
|
||||||
|
shelf:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shelf
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.7.5"
|
||||||
|
shelf_web_socket:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shelf_web_socket
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.2.3"
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.99"
|
version: "0.0.99"
|
||||||
|
source_gen:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: source_gen
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.9.4+2"
|
||||||
source_span:
|
source_span:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: source_span
|
name: source_span
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.4.1"
|
version: "1.5.4"
|
||||||
stack_trace:
|
stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -100,6 +380,13 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.6.8"
|
version: "1.6.8"
|
||||||
|
stream_transform:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: stream_transform
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.0.16+1"
|
||||||
string_scanner:
|
string_scanner:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -113,14 +400,21 @@ packages:
|
||||||
name: term_glyph
|
name: term_glyph
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.1"
|
version: "1.1.0"
|
||||||
test_api:
|
test_api:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.2.1"
|
version: "0.2.2"
|
||||||
|
timing:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: timing
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.1.1+1"
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -128,6 +422,13 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.6"
|
version: "1.1.6"
|
||||||
|
url_launcher:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: url_launcher
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.3"
|
||||||
vector_math:
|
vector_math:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -135,5 +436,27 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.8"
|
version: "2.0.8"
|
||||||
|
watcher:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: watcher
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.9.7+10"
|
||||||
|
web_socket_channel:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: web_socket_channel
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.12"
|
||||||
|
yaml:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: yaml
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.15"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=2.0.0 <3.0.0"
|
dart: ">=2.1.1 <3.0.0"
|
||||||
|
flutter: ">=0.1.4 <2.0.0"
|
||||||
|
|
|
@ -15,6 +15,10 @@ environment:
|
||||||
dependencies:
|
dependencies:
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
shared_preferences: ^0.4.2
|
||||||
|
url_launcher: ^3.0.3
|
||||||
|
json_annotation : ^2.2.0
|
||||||
|
http: ^0.12.0+2
|
||||||
|
|
||||||
# The following adds the Cupertino Icons font to your application.
|
# The following adds the Cupertino Icons font to your application.
|
||||||
# Use with the CupertinoIcons class for iOS style icons.
|
# Use with the CupertinoIcons class for iOS style icons.
|
||||||
|
@ -23,6 +27,8 @@ dependencies:
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
build_runner: ^1.1.3
|
||||||
|
json_serializable: ^2.1.2
|
||||||
|
|
||||||
|
|
||||||
# For information on the generic Dart part of this file, see the
|
# For information on the generic Dart part of this file, see the
|
||||||
|
|
Reference in a new issue