WORKS!!!!!!!!

We did it boys, we uploaded a transaction
This commit is contained in:
Felix 2019-07-16 11:28:36 +01:00
parent 7dd00349a8
commit e3ca987aa8
No known key found for this signature in database
GPG key ID: 130EF6DC43E4DD07
12 changed files with 87 additions and 274 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 131 KiB

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

View file

@ -6,13 +6,13 @@ PODS:
- Flutter - Flutter
DEPENDENCIES: DEPENDENCIES:
- Flutter (from `.symlinks/flutter/ios`) - Flutter (from `.symlinks/flutter/ios-profile`)
- shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`)
- url_launcher (from `.symlinks/plugins/url_launcher/ios`) - url_launcher (from `.symlinks/plugins/url_launcher/ios`)
EXTERNAL SOURCES: EXTERNAL SOURCES:
Flutter: Flutter:
:path: ".symlinks/flutter/ios" :path: ".symlinks/flutter/ios-profile"
shared_preferences: shared_preferences:
:path: ".symlinks/plugins/shared_preferences/ios" :path: ".symlinks/plugins/shared_preferences/ios"
url_launcher: url_launcher:

View file

@ -281,7 +281,7 @@
); );
inputPaths = ( inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", "${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"; name = "[CP] Embed Pods Frameworks";
outputPaths = ( outputPaths = (

View file

@ -1,6 +1,7 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:async'; import 'dart:async';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
import 'package:local_spend/common/functions/get_token.dart'; import 'package:local_spend/common/functions/get_token.dart';
class Organisation { class Organisation {
@ -24,7 +25,7 @@ List<Organisation> jsonToOrganisations(String json) {
Map decoded = jsonDecode(json); Map decoded = jsonDecode(json);
// print(decoded); // print(decoded);
List<dynamic> validated = decoded['unvalidated']; List<dynamic> validated = decoded['validated'];
// Map organisation = validated[0]; // Map organisation = validated[0];
// //
// print(""); // print("");
@ -102,3 +103,7 @@ Future<List<Organisation>> findOrganisations(String search) async {
} }
} }
class OrganizationController extends TextEditingController {
Organisation organisation;
}

View file

@ -59,6 +59,14 @@ Future<LoginModel> submitReceiptAPI(
if (response.statusCode == 200) { if (response.statusCode == 200) {
final responseJson = json.decode(response.body); 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); return LoginModel.fromJson(responseJson);
} else { } else {
final responseJson = json.decode(response.body); final responseJson = json.decode(response.body);
@ -68,7 +76,7 @@ Future<LoginModel> submitReceiptAPI(
context, context,
"Unable to Submit Receipt", "Unable to Submit Receipt",
// "You may have supplied an invalid 'Email' / 'Password' combination. Please try again or email an administrator.", // "You may have supplied an invalid 'Email' / 'Password' combination. Please try again or email an administrator.",
responseJson.toString(), "Message from server: " + responseJson[1],
"OK"); "OK");
return null; return null;
} }

View file

@ -23,8 +23,8 @@ void showDialogTwoButtons(
new FlatButton( new FlatButton(
child: new Text(buttonLabel2), child: new Text(buttonLabel2),
onPressed: () { onPressed: () {
action(context);
Navigator.of(context).pop(); Navigator.of(context).pop();
action(context);
}, },
), ),
], ],

View file

@ -5,7 +5,7 @@ class PopupListView {
Future<dynamic> dialog(context, List<String> options, String title) { Future<dynamic> dialog(context, List<String> options, String title) {
return showDialog<dynamic>( return showDialog<dynamic>(
context: context, context: context,
barrierDismissible: false, barrierDismissible: true,
builder: (BuildContext context) { builder: (BuildContext context) {
return SimpleDialog( return SimpleDialog(

View file

@ -84,8 +84,14 @@ class LoginPageState extends State<LoginPage> {
// child: ListView( // child: ListView(
// children: <Widget>[ // children: <Widget>[
body: Container( body: Container(
decoration: BoxDecoration(color: Colors.white), decoration: new BoxDecoration(
child: Container( 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), margin: EdgeInsets.fromLTRB(60,30,60,0),
child: Column( child: Column(
children: <Widget>[ children: <Widget>[
@ -143,50 +149,41 @@ class LoginPageState extends State<LoginPage> {
}, },
), ),
), ),
// 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(
padding: EdgeInsets.fromLTRB(0.0, 40.0, 0.0, 30.0), padding: EdgeInsets.fromLTRB(0.0, 40.0, 0.0, 30.0),
child : Material( child : Material(
child : InkWell( child: new Container(
child : InkWell(
onTap: () => login( _emailController.text, _passwordController.text), onTap: () => login( _emailController.text, _passwordController.text),
child: new Container( child: new Container(
width: 100, width: 100,
height: 50, height: 50,
decoration: new BoxDecoration(
// color: Colors.lightBlueAccent,
borderRadius: new BorderRadius.circular(0.0),
),
child: new Center( child: new Center(
child: new Text( child: new Text(
'GO', style: new TextStyle(fontSize: 18, color: Colors.white),), '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(
padding: EdgeInsets.fromLTRB(0, 10, 0, 50), padding: EdgeInsets.fromLTRB(0, 10, 0, 50),

View file

@ -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<StatefulWidget> createState() {
return new LoginPageState();
}
}
class LoginPageState extends State<LoginPage> {
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<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,
iconTheme: IconThemeData(color: Colors.black),
),
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: 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,
),
),
),
],
),
),
),
),
);
}
}

View file

@ -16,7 +16,7 @@ import 'package:local_spend/common/widgets/popupListView.dart';
import 'package:local_spend/common/widgets/labeled_checkbox.dart'; import 'package:local_spend/common/widgets/labeled_checkbox.dart';
const URL = "https://flutter.io/"; const URL = "https://flutter.io/";
const demonstration = true; const demonstration = false;
class ReceiptPage extends StatefulWidget { class ReceiptPage extends StatefulWidget {
@override @override
@ -32,6 +32,7 @@ class ReceiptPageState extends State<ReceiptPage> {
final TextEditingController _recurringController = TextEditingController(text: "None"); final TextEditingController _recurringController = TextEditingController(text: "None");
final TextEditingController _typeController = TextEditingController(); final TextEditingController _typeController = TextEditingController();
final TextEditingController _orgController = TextEditingController(); final TextEditingController _orgController = TextEditingController();
final OrganizationController _organizationController = OrganizationController();
FocusNode focusNode; // added so focus can move automatically FocusNode focusNode; // added so focus can move automatically
@ -71,7 +72,7 @@ class ReceiptPageState extends State<ReceiptPage> {
// this file is getting really messy sorry everyone // 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'); SystemChannels.textInput.invokeMethod('TextInput.hide');
if (demonstration) if (demonstration)
@ -89,6 +90,7 @@ class ReceiptPageState extends State<ReceiptPage> {
child: new Text("OK"), child: new Text("OK"),
onPressed: () { onPressed: () {
Navigator.of(context).pop(); Navigator.of(context).pop();
Navigator.of(context).pushReplacementNamed('/HomePage');
//TODO: Reset form after dialog exit //TODO: Reset form after dialog exit
}, },
), ),
@ -96,7 +98,6 @@ class ReceiptPageState extends State<ReceiptPage> {
); );
}, },
).then((_) { ).then((_) {
Navigator.of(context).pushReplacementNamed('/HomePage');
}); });
} }
else { else {
@ -105,16 +106,21 @@ class ReceiptPageState extends State<ReceiptPage> {
// setting up 'receipt' // setting up 'receipt'
receipt.amount = amount; receipt.amount = amount;
receipt.time = formatDate(time); 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) // receipt.essential = convertBoolToString(toConvert)
//TODO: initialise receipt with correct values from form // TODO: Categories
// receipt.category = category; // receipt.category = category;
// receipt.etc = etc; // receipt.etc = etc;
submitReceiptAPI(context, receipt); submitReceiptAPI(context, receipt);
Navigator.of(context).pushReplacementNamed('/HomePage');
} }
} }
@ -166,7 +172,7 @@ class ReceiptPageState extends State<ReceiptPage> {
// know that before writing this and it's done now so I'm keeping it. // know that before writing this and it's done now so I'm keeping it.
} }
String listOrganisations(List<Organisation> organisations, context) { Organisation listOrganisations(List<Organisation> organisations, context) {
if (organisations.length == 0) { if (organisations.length == 0) {
showDialogSingleButton( showDialogSingleButton(
context, context,
@ -189,7 +195,13 @@ class ReceiptPageState extends State<ReceiptPage> {
// dialog.then((value) => debugPrint(value)); // 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 <future> and thus would block //can't return value as it is <future> and thus would block
} }
@ -305,15 +317,14 @@ class ReceiptPageState extends State<ReceiptPage> {
onPressed: () { onPressed: () {
if (_orgController.text != "") { if (_orgController.text != "") {
var organisations = findOrganisations( var organisations = findOrganisations(
_orgController.text); _orgController.text); // returns Future<List<Organisation>>
var choice = organisations.then((data) => var choice = organisations.then((data) =>
listOrganisations(data, context)); listOrganisations(data, context));
choice.then((value) => _orgController.text = value); choice.then((value) => _orgController.text = value.name);
setState(() { choice.then((value) => _organizationController.organisation = value);
});
} else { } else {
// no data entered // no data entered
@ -354,7 +365,7 @@ class ReceiptPageState extends State<ReceiptPage> {
), ),
onSubmitted: (_) { onSubmitted: (_) {
submitReceipt(_amountController.text, submitReceipt(_amountController.text,
_timeController.text, _orgController.text); _timeController.text, _organizationController.organisation);
// TODO: make sure organisation is valid // 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 // 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<ReceiptPage> {
height: 65.0, height: 65.0,
child: RaisedButton( child: RaisedButton(
onPressed: () { onPressed: () {
submitReceipt(_amountController.text, _timeController.text, _orgController.text); submitReceipt(_amountController.text, _timeController.text, _organizationController.organisation);
}, },
child: Text("GO", child: Text("GO",
style: style:

View file

@ -156,21 +156,22 @@ class SettingsPageState extends State<SettingsPage> {
), ),
), ),
Padding( // Padding(
padding: EdgeInsets.fromLTRB(0.0, 20.0, 0.0, 0.0), // padding: EdgeInsets.fromLTRB(0.0, 20.0, 0.0, 0.0),
child: Container( // child: Container(
height: 65.0, // height: 65.0,
child: RaisedButton( // child: RaisedButton(
onPressed: () { // onPressed: () {
feedback(context); // feedback(context);
}, // },
child: Text("FEEDBACK", // child: Text("FEEDBACK",
style: // style:
TextStyle(color: Colors.white, fontSize: 22.0)), // TextStyle(color: Colors.white, fontSize: 22.0)),
color: Colors.green, // color: Colors.green,
), // ),
), // ),
), // ),
], ],
), ),
), ),