diff --git a/assets/images/launch_image.png b/assets/images/launch_image.png index e8d5eb3..0a4042b 100644 Binary files a/assets/images/launch_image.png and b/assets/images/launch_image.png differ diff --git a/assets/zapsplat_sport_air_horn_2x_blasts_002_21151.mp3 b/assets/zapsplat_sport_air_horn_2x_blasts_002_21151.mp3 new file mode 100644 index 0000000..a834946 Binary files /dev/null and b/assets/zapsplat_sport_air_horn_2x_blasts_002_21151.mp3 differ diff --git a/ios/Podfile.lock b/ios/Podfile.lock index f5bffe1..81f2036 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -6,13 +6,13 @@ PODS: - Flutter DEPENDENCIES: - - Flutter (from `.symlinks/flutter/ios`) + - Flutter (from `.symlinks/flutter/ios-profile`) - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) - url_launcher (from `.symlinks/plugins/url_launcher/ios`) EXTERNAL SOURCES: Flutter: - :path: ".symlinks/flutter/ios" + :path: ".symlinks/flutter/ios-profile" shared_preferences: :path: ".symlinks/plugins/shared_preferences/ios" url_launcher: diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index a83a4d3..dff0209 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -281,7 +281,7 @@ ); inputPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", - "${PODS_ROOT}/../.symlinks/flutter/ios/Flutter.framework", + "${PODS_ROOT}/../.symlinks/flutter/ios-profile/Flutter.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( diff --git a/lib/common/apifunctions/find_organisations.dart b/lib/common/apifunctions/find_organisations.dart index 69187e8..68cc339 100644 --- a/lib/common/apifunctions/find_organisations.dart +++ b/lib/common/apifunctions/find_organisations.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'dart:async'; import 'package:http/http.dart' as http; +import 'package:flutter/material.dart'; import 'package:local_spend/common/functions/get_token.dart'; class Organisation { @@ -24,7 +25,7 @@ List jsonToOrganisations(String json) { Map decoded = jsonDecode(json); // print(decoded); - List validated = decoded['unvalidated']; + List validated = decoded['validated']; // Map organisation = validated[0]; // // print(""); @@ -101,4 +102,8 @@ Future> findOrganisations(String search) async { return null; } +} + +class OrganizationController extends TextEditingController { + Organisation organisation; } \ No newline at end of file diff --git a/lib/common/apifunctions/submit_receipt_api.dart b/lib/common/apifunctions/submit_receipt_api.dart index b317542..ed74f92 100644 --- a/lib/common/apifunctions/submit_receipt_api.dart +++ b/lib/common/apifunctions/submit_receipt_api.dart @@ -59,6 +59,14 @@ Future submitReceiptAPI( if (response.statusCode == 200) { final responseJson = json.decode(response.body); + print(responseJson[0]); + + showDialogSingleButton( + context, + responseJson[0] == "" ? responseJson[0] : "Upload Successful", + "Transaction successfully submitted to server", + "OK" + ); return LoginModel.fromJson(responseJson); } else { final responseJson = json.decode(response.body); @@ -68,7 +76,7 @@ Future submitReceiptAPI( context, "Unable to Submit Receipt", // "You may have supplied an invalid 'Email' / 'Password' combination. Please try again or email an administrator.", - responseJson.toString(), + "Message from server: " + responseJson[1], "OK"); return null; } diff --git a/lib/common/functions/showDialogTwoButtons.dart b/lib/common/functions/showDialogTwoButtons.dart index 03ab0d7..af1cd6c 100644 --- a/lib/common/functions/showDialogTwoButtons.dart +++ b/lib/common/functions/showDialogTwoButtons.dart @@ -23,8 +23,8 @@ void showDialogTwoButtons( new FlatButton( child: new Text(buttonLabel2), onPressed: () { - action(context); Navigator.of(context).pop(); + action(context); }, ), ], diff --git a/lib/common/widgets/popupListView.dart b/lib/common/widgets/popupListView.dart index ceea50a..7f5d27c 100644 --- a/lib/common/widgets/popupListView.dart +++ b/lib/common/widgets/popupListView.dart @@ -5,7 +5,7 @@ class PopupListView { Future dialog(context, List options, String title) { return showDialog( context: context, - barrierDismissible: false, + barrierDismissible: true, builder: (BuildContext context) { return SimpleDialog( diff --git a/lib/pages/login_page.dart b/lib/pages/login_page.dart index f0bfc48..2d377a9 100644 --- a/lib/pages/login_page.dart +++ b/lib/pages/login_page.dart @@ -84,8 +84,14 @@ class LoginPageState extends State { // child: ListView( // children: [ body: Container( - decoration: BoxDecoration(color: Colors.white), - child: Container( + decoration: new BoxDecoration( + gradient: new LinearGradient( + colors: [Colors.white, Colors.blue[50]], + stops: [0,1], + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + ), + ), child: Container( margin: EdgeInsets.fromLTRB(60,30,60,0), child: Column( children: [ @@ -143,50 +149,41 @@ class LoginPageState extends State { }, ), ), -// Padding( -// padding: EdgeInsets.fromLTRB(0.0, 25.0, 0.0, 100.0), -// child: Container( -// height: 45.0, -// child: RaisedButton( -// -// onPressed: () { -// login( _emailController.text, -// _passwordController.text); -// // showDialog( -// // barrierDismissible: false, -// // ); -// // print("pressed"); -// }, -// child: Text("GO", -// style: -// TextStyle(color: Colors.white, fontSize: 20.0)), -// color: Colors.blue, -// ), -// ), -// ), + Padding( padding: EdgeInsets.fromLTRB(0.0, 40.0, 0.0, 30.0), child : Material( - child : InkWell( + child: new Container( + child : InkWell( onTap: () => login( _emailController.text, _passwordController.text), child: new Container( width: 100, height: 50, - decoration: new BoxDecoration( -// color: Colors.lightBlueAccent, - borderRadius: new BorderRadius.circular(0.0), - ), child: new Center( child: new Text( 'GO', style: new TextStyle(fontSize: 18, color: Colors.white),), ), ), - splashColor: Colors.lightBlueAccent, + splashColor: Colors.lightBlueAccent, ), - color: Colors.blueAccent, + + decoration: new BoxDecoration( + border: new Border.all(color : Colors.transparent, width: 2), + borderRadius: BorderRadius.all(Radius.circular(2)), + gradient: new LinearGradient( + colors: [ + Colors.blue[300], + Colors.blue[600], + ], + stops: [0,1], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + ), ), ), + ), Padding( padding: EdgeInsets.fromLTRB(0, 10, 0, 50), diff --git a/lib/pages/login_page_old.dart b/lib/pages/login_page_old.dart deleted file mode 100644 index 612fe72..0000000 --- a/lib/pages/login_page_old.dart +++ /dev/null @@ -1,209 +0,0 @@ -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:shared_preferences/shared_preferences.dart'; -import 'package:url_launcher/url_launcher.dart'; - -const URL = "https://flutter.io/"; - -class LoginPage extends StatefulWidget { - @override - State createState() { - return new LoginPageState(); - } -} - -class LoginPageState extends State { - final TextEditingController _emailController = TextEditingController(text: 'test@example.com'); // remove - final TextEditingController _passwordController = TextEditingController(text: 'abc123'); // remove - - FocusNode focusNode; // added so focus can move automatically - - 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"); - - focusNode = FocusNode(); - } - - @override - void dispose() { - focusNode.dispose(); //disposes focus node when form disposed - super.dispose(); - } - - _saveCurrentRoute(String lastRoute) async { - SharedPreferences preferences = await SharedPreferences.getInstance(); - await preferences.setString('LastPageRoute', lastRoute); - } - - void login(String username, String password) { - SystemChannels.textInput.invokeMethod('TextInput.hide'); - requestLoginAPI(context, username, - password); - } - - @override - Widget build(BuildContext context) { - return WillPopScope( - onWillPop: () { - if (Navigator.canPop(context)) { - Navigator.of(context).pushNamedAndRemoveUntil( - '/HomePage', (Route 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, - iconTheme: IconThemeData(color: Colors.black), - ), - body: Container( - child: Padding( - padding: EdgeInsets.fromLTRB(30.0, 0.0, 30.0, 0.0), - child: ListView( - children: [ - 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: 16.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[800], - fontWeight: FontWeight.bold, - ), - onSubmitted: (_) { - FocusScope.of(context).requestFocus(focusNode); - }, - ), - ), - Padding( - padding: EdgeInsets.fromLTRB(0.0, 35.0, 0.0, 0.0), - child: Text( - "PASSWORD", - style: TextStyle( - fontSize: 16.0, - color: Colors.black, - fontWeight: FontWeight.bold, - ), - ), - ), - Padding( - padding: EdgeInsets.fromLTRB(0.0, 5.0, 0.0, 0.0), - child: TextField( - controller: _passwordController, - focusNode: focusNode, - decoration: InputDecoration( - hintText: 'Your password, keep it secret, keep it safe.', - ), - obscureText: true, - style: TextStyle( - fontSize: 18.0, - color: Colors.grey[800], - fontWeight: FontWeight.bold, - ), - onSubmitted: (_) { - login( _emailController.text, - _passwordController.text); - }, - ), - ), - Padding( - padding: EdgeInsets.fromLTRB(0.0, 70.0, 0.0, 0.0), - child: Container( - height: 65.0, - child: RaisedButton( - onPressed: () { - login( _emailController.text, - _passwordController.text); -// showDialog( -// barrierDismissible: false, -// ); -// print("pressed"); - }, - child: Text("LOGIN", - style: - TextStyle(color: Colors.white, fontSize: 22.0)), - color: Colors.blue, - ), - ), - ), - ], - ), - ), - ), - ), - ); - } -} diff --git a/lib/pages/receipt_page.dart b/lib/pages/receipt_page.dart index 3c34a72..ccfd83e 100644 --- a/lib/pages/receipt_page.dart +++ b/lib/pages/receipt_page.dart @@ -16,7 +16,7 @@ import 'package:local_spend/common/widgets/popupListView.dart'; import 'package:local_spend/common/widgets/labeled_checkbox.dart'; const URL = "https://flutter.io/"; -const demonstration = true; +const demonstration = false; class ReceiptPage extends StatefulWidget { @override @@ -32,6 +32,7 @@ class ReceiptPageState extends State { final TextEditingController _recurringController = TextEditingController(text: "None"); final TextEditingController _typeController = TextEditingController(); final TextEditingController _orgController = TextEditingController(); + final OrganizationController _organizationController = OrganizationController(); FocusNode focusNode; // added so focus can move automatically @@ -71,7 +72,7 @@ class ReceiptPageState extends State { // this file is getting really messy sorry everyone - void submitReceipt(String amount, String time, String orgName) async { + void submitReceipt(String amount, String time, Organisation organisation) async { SystemChannels.textInput.invokeMethod('TextInput.hide'); if (demonstration) @@ -89,6 +90,7 @@ class ReceiptPageState extends State { child: new Text("OK"), onPressed: () { Navigator.of(context).pop(); + Navigator.of(context).pushReplacementNamed('/HomePage'); //TODO: Reset form after dialog exit }, ), @@ -96,7 +98,6 @@ class ReceiptPageState extends State { ); }, ).then((_) { - Navigator.of(context).pushReplacementNamed('/HomePage'); }); } else { @@ -105,16 +106,21 @@ class ReceiptPageState extends State { // setting up 'receipt' receipt.amount = amount; receipt.time = formatDate(time); - receipt.organisationName = orgName; + debugPrint(organisation.name + ", " + organisation.streetName + ", " + organisation.town + ", " + organisation.postcode); + receipt.organisationName = organisation.name; + receipt.street = organisation.streetName; + receipt.town = organisation.town; + receipt.postcode = organisation.postcode; // receipt.essential = convertBoolToString(toConvert) - //TODO: initialise receipt with correct values from form +// TODO: Categories // receipt.category = category; // receipt.etc = etc; submitReceiptAPI(context, receipt); + Navigator.of(context).pushReplacementNamed('/HomePage'); } } @@ -166,7 +172,7 @@ class ReceiptPageState extends State { // know that before writing this and it's done now so I'm keeping it. } - String listOrganisations(List organisations, context) { + Organisation listOrganisations(List organisations, context) { if (organisations.length == 0) { showDialogSingleButton( context, @@ -189,7 +195,13 @@ class ReceiptPageState extends State { // dialog.then((value) => debugPrint(value)); - dialog.then((value) => _orgController.text = value); + + dialog.then((value) { + _orgController.text = value; + _organizationController.organisation = organisations.where((thisOrg) => thisOrg.name == value).elementAt(0); + // this may not work when two organisations have the same name, + // then again the popupListView can't display two of the same names properly either + }); //can't return value as it is and thus would block } @@ -305,15 +317,14 @@ class ReceiptPageState extends State { onPressed: () { if (_orgController.text != "") { var organisations = findOrganisations( - _orgController.text); + _orgController.text); // returns Future> var choice = organisations.then((data) => listOrganisations(data, context)); - choice.then((value) => _orgController.text = value); - setState(() { + choice.then((value) => _orgController.text = value.name); + choice.then((value) => _organizationController.organisation = value); - }); } else { // no data entered @@ -354,7 +365,7 @@ class ReceiptPageState extends State { ), onSubmitted: (_) { submitReceipt(_amountController.text, - _timeController.text, _orgController.text); + _timeController.text, _organizationController.organisation); // TODO: make sure organisation is valid // TODO: Add 'find organisation' button which displays a dialog to, well, find the organisation's address or manual entry }, @@ -452,7 +463,7 @@ class ReceiptPageState extends State { height: 65.0, child: RaisedButton( onPressed: () { - submitReceipt(_amountController.text, _timeController.text, _orgController.text); + submitReceipt(_amountController.text, _timeController.text, _organizationController.organisation); }, child: Text("GO", style: diff --git a/lib/pages/settings.dart b/lib/pages/settings.dart index a77d3b4..163761c 100644 --- a/lib/pages/settings.dart +++ b/lib/pages/settings.dart @@ -156,21 +156,22 @@ class SettingsPageState extends State { ), ), - Padding( - padding: EdgeInsets.fromLTRB(0.0, 20.0, 0.0, 0.0), - child: Container( - height: 65.0, - child: RaisedButton( - onPressed: () { - feedback(context); - }, - child: Text("FEEDBACK", - style: - TextStyle(color: Colors.white, fontSize: 22.0)), - color: Colors.green, - ), - ), - ), +// Padding( +// padding: EdgeInsets.fromLTRB(0.0, 20.0, 0.0, 0.0), +// child: Container( +// height: 65.0, +// child: RaisedButton( +// onPressed: () { +// feedback(context); +// }, +// child: Text("FEEDBACK", +// style: +// TextStyle(color: Colors.white, fontSize: 22.0)), +// color: Colors.green, +// ), +// ), +// ), + ], ), ),