Code is B-E-A-U-TIFUL! All complies to standards.

Complies to flutter/dart 'pedantic' coding standards (their name, not mine)
This commit is contained in:
Felix 2019-08-21 14:53:52 +01:00
parent 19021a9a09
commit 55310068ea
55 changed files with 915 additions and 785 deletions

1
.gitignore vendored
View File

@ -236,3 +236,4 @@ fabric.properties
# End of https://www.gitignore.io/api/android,flutter,androidstudio # End of https://www.gitignore.io/api/android,flutter,androidstudio
lib/common/felixApiCreds.dart lib/common/felixApiCreds.dart
android/app/src/main/AndroidManifest.xml

18
analysis_options.yaml Normal file
View File

@ -0,0 +1,18 @@
include: package:pedantic/analysis_options.yaml
analyzer:
exclude:
- lib/src/locations.g.dart
linter:
rules:
- always_declare_return_types
- camel_case_types
- empty_constructor_bodies
- annotate_overrides
- avoid_init_to_null
- constant_identifier_names
- one_member_abstracts
- slash_for_doc_comments
- sort_constructors_first
- unnecessary_brace_in_string_interps

View File

@ -25,7 +25,7 @@ apply plugin: 'com.android.application'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android { android {
compileSdkVersion 27 compileSdkVersion 28
lintOptions { lintOptions {
disable 'InvalidPackage' disable 'InvalidPackage'

View File

@ -14,8 +14,14 @@
FlutterApplication and put your custom class here. --> FlutterApplication and put your custom class here. -->
<application <application
android:name="io.flutter.app.FlutterApplication" android:name="io.flutter.app.FlutterApplication"
android:label="local_spend" android:label="SpendTracker"
android:icon="@mipmap/ic_launcher"> android:icon="@mipmap/ic_launcher">
<meta-data android:name="com.google.android.geo.API_KEY"
android:value="AIzaSyDfCRFolRWvgfgSK0UCl5n5rNb5CS7O7KI"/>
<!-- Please don't be stupid with the above key-->
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:launchMode="singleTop" android:launchMode="singleTop"
@ -31,10 +37,6 @@
android:name="io.flutter.app.android.SplashScreenUntilFirstFrame" android:name="io.flutter.app.android.SplashScreenUntilFirstFrame"
android:value="true" /> android:value="true" />
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="API KEY HERE" />
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN"/> <action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/> <category android:name="android.intent.category.LAUNCHER"/>

View File

@ -1,5 +1,5 @@
# Uncomment this line to define a global platform for your project # Uncomment this line to define a global platform for your project
# platform :ios, '9.0' platform :ios, '9.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency. # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true' ENV['COCOAPODS_DISABLE_STATS'] = 'true'

View File

@ -1,5 +1,13 @@
PODS: PODS:
- Flutter (1.0.0) - Flutter (1.0.0)
- google_maps_flutter (0.0.1):
- Flutter
- GoogleMaps
- GoogleMaps (3.3.0):
- GoogleMaps/Maps (= 3.3.0)
- GoogleMaps/Base (3.3.0)
- GoogleMaps/Maps (3.3.0):
- GoogleMaps/Base
- shared_preferences (0.0.1): - shared_preferences (0.0.1):
- Flutter - Flutter
- url_launcher (0.0.1): - url_launcher (0.0.1):
@ -7,12 +15,19 @@ PODS:
DEPENDENCIES: DEPENDENCIES:
- Flutter (from `.symlinks/flutter/ios`) - Flutter (from `.symlinks/flutter/ios`)
- google_maps_flutter (from `.symlinks/plugins/google_maps_flutter/ios`)
- 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`)
SPEC REPOS:
https://github.com/cocoapods/specs.git:
- GoogleMaps
EXTERNAL SOURCES: EXTERNAL SOURCES:
Flutter: Flutter:
:path: ".symlinks/flutter/ios" :path: ".symlinks/flutter/ios"
google_maps_flutter:
:path: ".symlinks/plugins/google_maps_flutter/ios"
shared_preferences: shared_preferences:
:path: ".symlinks/plugins/shared_preferences/ios" :path: ".symlinks/plugins/shared_preferences/ios"
url_launcher: url_launcher:
@ -20,9 +35,11 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS: SPEC CHECKSUMS:
Flutter: 58dd7d1b27887414a370fcccb9e645c08ffd7a6a Flutter: 58dd7d1b27887414a370fcccb9e645c08ffd7a6a
google_maps_flutter: 78a52114c898b42ea647919679a4c58b70abe876
GoogleMaps: cfee83da305b9aaeccf92c24ac79df11c3003492
shared_preferences: 1feebfa37bb57264736e16865e7ffae7fc99b523 shared_preferences: 1feebfa37bb57264736e16865e7ffae7fc99b523
url_launcher: 0067ddb8f10d36786672aa0722a21717dba3a298 url_launcher: 0067ddb8f10d36786672aa0722a21717dba3a298
PODFILE CHECKSUM: aff02bfeed411c636180d6812254b2daeea14d09 PODFILE CHECKSUM: 3389836f37640698630b8f0670315d626d5f1469
COCOAPODS: 1.7.5 COCOAPODS: 1.7.5

View File

@ -163,6 +163,7 @@
9705A1C41CF9048500538489 /* Embed Frameworks */, 9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
ACE3DC71CDB8FA5537935604 /* [CP] Embed Pods Frameworks */, ACE3DC71CDB8FA5537935604 /* [CP] Embed Pods Frameworks */,
E6C2807EE928990FB790046F /* [CP] Copy Pods Resources */,
); );
buildRules = ( buildRules = (
); );
@ -292,6 +293,24 @@
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0; showEnvVarsInLog = 0;
}; };
E6C2807EE928990FB790046F /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh",
"${PODS_ROOT}/GoogleMaps/Maps/Frameworks/GoogleMaps.framework/Resources/GoogleMaps.bundle",
);
name = "[CP] Copy Pods Resources";
outputPaths = (
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/GoogleMaps.bundle",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */ /* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */
@ -390,6 +409,7 @@
"$(PROJECT_DIR)/Flutter", "$(PROJECT_DIR)/Flutter",
); );
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = ( LIBRARY_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
@ -519,6 +539,7 @@
"$(PROJECT_DIR)/Flutter", "$(PROJECT_DIR)/Flutter",
); );
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = ( LIBRARY_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
@ -546,6 +567,7 @@
"$(PROJECT_DIR)/Flutter", "$(PROJECT_DIR)/Flutter",
); );
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = ( LIBRARY_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",

View File

@ -1,10 +1,12 @@
#include "AppDelegate.h" #include "AppDelegate.h"
#include "GeneratedPluginRegistrant.h" #include "GeneratedPluginRegistrant.h"
#import "GoogleMaps/GoogleMaps.h"
@implementation AppDelegate @implementation AppDelegate
- (BOOL)application:(UIApplication *)application - (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[GMSServices provideAPIKey:@"AIzaSyDfCRFolRWvgfgSK0UCl5n5rNb5CS7O7KI"];
[GeneratedPluginRegistrant registerWithRegistry:self]; [GeneratedPluginRegistrant registerWithRegistry:self];
// Override point for customization after application launch. // Override point for customization after application launch.
return [super application:application didFinishLaunchingWithOptions:launchOptions]; return [super application:application didFinishLaunchingWithOptions:launchOptions];

View File

@ -2,7 +2,6 @@ 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:local_spend/common/functions/get_token.dart'; import 'package:local_spend/common/functions/get_token.dart';
import 'package:flutter/material.dart';
Future<List<String>> getCategories() async { Future<List<String>> getCategories() async {
const url = "https://dev.localspend.co.uk/api/search/category"; const url = "https://dev.localspend.co.uk/api/search/category";
@ -13,10 +12,10 @@ Future<List<String>> getCategories() async {
}); });
Map<String, String> body = { Map<String, String> body = {
"session_key":token, "session_key": token,
}; };
final response = await http.post ( final response = await http.post(
url, url,
body: json.encode(body), body: json.encode(body),
); );
@ -36,9 +35,8 @@ Future<List<String>> getCategories() async {
// print(categoriesJSON['11']); // prints "Banana" // print(categoriesJSON['11']); // prints "Banana"
int i = 1; // starts on 1. that was annoying to debug! int i = 1; // starts on 1. that was annoying to debug!
while (true) { while (true) {
if (categoriesJSON[i.toString()] != null) { if (categoriesJSON[i.toString()] != null) {
// print("Iteration " + i.toString()); // print("Iteration " + i.toString());
// print(categoriesJSON[i.toString()]); // print(categoriesJSON[i.toString()]);
@ -61,10 +59,10 @@ Future<List<String>> getCategories() async {
// print(categories[10].name.toString()); // prints "Banana" // print(categories[10].name.toString()); // prints "Banana"
return categories; // categories is List<Category> return categories; // categories is List<Category>
// Category is defined at the top^^ // Category is defined at the top^^
} else { } else {
// not successful // not successful
return null; return null;
} }
} }

View File

@ -1,39 +1,32 @@
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 {
var id = 0;
var name = "";
var postcode = "";
var streetName = ""; //street_name
var town = "";
Organisation( Organisation(
this.id, this.id,
this.name, this.name,
this.postcode, this.postcode,
this.streetName, this.streetName,
this.town, this.town,
); );
var id = 0;
var name = "";
var postcode = "";
var streetName = ""; //street_name
var town = "";
} }
class Organisations { class Organisations {
List<Organisation> getTestData() { List<Organisation> getTestData() {
var numItems = 10; var numItems = 10;
var itemsList = new List<Organisation>(); var itemsList = new List<Organisation>();
for (int i = 0; i < numItems; i++) { for (int i = 0; i < numItems; i++) {
itemsList.add(new Organisation( itemsList.add(new Organisation(i, "Payee " + (i + 1).toString(),
i, "tee hee hee", "yeet street", "Robloxia"));
"Payee " + (i + 1).toString(),
"tee hee hee",
"yeet street",
"Robloxia"
));
} }
return itemsList; return itemsList;
@ -72,11 +65,11 @@ class Organisations {
}); });
Map<String, String> body = { Map<String, String> body = {
"search_name":search, "search_name": search,
"session_key":token, "session_key": token,
}; };
final response = await http.post ( final response = await http.post(
url, url,
body: json.encode(body), body: json.encode(body),
); );
@ -88,6 +81,5 @@ class Organisations {
// not successful // not successful
return null; return null;
} }
} }
} }

View File

@ -5,13 +5,13 @@ import 'package:shared_preferences/shared_preferences.dart';
import 'package:charts_flutter/flutter.dart' as charts; import 'package:charts_flutter/flutter.dart' as charts;
class GraphData { class GraphData {
var chartType;
List<charts.Series<dynamic, DateTime>> graph;
GraphData( GraphData(
this.chartType, this.chartType,
); );
var chartType;
List<charts.Series<dynamic, DateTime>> graph;
List<TimeSeriesSpend> cachedData; List<TimeSeriesSpend> cachedData;
bool loaded = false; bool loaded = false;
@ -49,7 +49,8 @@ class GraphData {
List<TimeSeriesSpend> timeSeriesSpendList = new List<TimeSeriesSpend>(); List<TimeSeriesSpend> timeSeriesSpendList = new List<TimeSeriesSpend>();
for (int i = 0; i < labels.length; i++) { for (int i = 0; i < labels.length; i++) {
timeSeriesSpendList.add(new TimeSeriesSpend(data[i]*1.00, DateTime.parse(labels[i]))); timeSeriesSpendList.add(
new TimeSeriesSpend(data[i] * 1.00, DateTime.parse(labels[i])));
// print(timeSeriesSpendList[i].time.toString() + " : " + timeSeriesSpendList[i].spend.toString()); // print(timeSeriesSpendList[i].time.toString() + " : " + timeSeriesSpendList[i].spend.toString());
} }
@ -131,7 +132,8 @@ class GraphData {
List<TimeSeriesSpend> timeSeriesSpendList = new List<TimeSeriesSpend>(); List<TimeSeriesSpend> timeSeriesSpendList = new List<TimeSeriesSpend>();
for (int i = 0; i < labels.length; i++) { for (int i = 0; i < labels.length; i++) {
timeSeriesSpendList.add(new TimeSeriesSpend(data[i]*1.00, DateTime.parse(labels[i]))); timeSeriesSpendList.add(
new TimeSeriesSpend(data[i] * 1.00, DateTime.parse(labels[i])));
// print(timeSeriesSpendList[i].time.toString() + " : " + timeSeriesSpendList[i].spend.toString()); // print(timeSeriesSpendList[i].time.toString() + " : " + timeSeriesSpendList[i].spend.toString());
} }
@ -154,18 +156,16 @@ class GraphData {
return null; return null;
} }
} }
} }
class OrgGraphData { class OrgGraphData {
var chartType;
List<charts.Series<dynamic, DateTime>> graph;
OrgGraphData( OrgGraphData(
this.chartType, this.chartType,
); );
var chartType;
List<charts.Series<dynamic, DateTime>> graph;
List<TimeSeriesSpend> cachedData; List<TimeSeriesSpend> cachedData;
bool loaded = false; bool loaded = false;
@ -203,7 +203,8 @@ class OrgGraphData {
List<TimeSeriesSpend> timeSeriesSpendList = new List<TimeSeriesSpend>(); List<TimeSeriesSpend> timeSeriesSpendList = new List<TimeSeriesSpend>();
for (int i = 0; i < labels.length; i++) { for (int i = 0; i < labels.length; i++) {
timeSeriesSpendList.add(new TimeSeriesSpend(data[i]*1.00, DateTime.parse(labels[i]))); timeSeriesSpendList.add(
new TimeSeriesSpend(data[i] * 1.00, DateTime.parse(labels[i])));
// print(timeSeriesSpendList[i].time.toString() + " : " + timeSeriesSpendList[i].spend.toString()); // print(timeSeriesSpendList[i].time.toString() + " : " + timeSeriesSpendList[i].spend.toString());
} }
@ -285,7 +286,8 @@ class OrgGraphData {
List<TimeSeriesSpend> timeSeriesSpendList = new List<TimeSeriesSpend>(); List<TimeSeriesSpend> timeSeriesSpendList = new List<TimeSeriesSpend>();
for (int i = 0; i < labels.length; i++) { for (int i = 0; i < labels.length; i++) {
timeSeriesSpendList.add(new TimeSeriesSpend(data[i]*1.00, DateTime.parse(labels[i]))); timeSeriesSpendList.add(
new TimeSeriesSpend(data[i] * 1.00, DateTime.parse(labels[i])));
// print(timeSeriesSpendList[i].time.toString() + " : " + timeSeriesSpendList[i].spend.toString()); // print(timeSeriesSpendList[i].time.toString() + " : " + timeSeriesSpendList[i].spend.toString());
} }
@ -308,14 +310,11 @@ class OrgGraphData {
return null; return null;
} }
} }
} }
class TimeSeriesSpend { class TimeSeriesSpend {
TimeSeriesSpend(this.spend, this.time);
final DateTime time; final DateTime time;
final double spend; final double spend;
TimeSeriesSpend(this.spend, this.time);
} }

View File

@ -13,9 +13,11 @@ Future<void> _incorrectDialog(BuildContext context, bool isLoginWrong) async {
builder: (BuildContext context) { builder: (BuildContext context) {
return AnimatedContainer( return AnimatedContainer(
duration: Duration(seconds: 2), duration: Duration(seconds: 2),
child : AlertDialog( child: AlertDialog(
title: Text("Uh-oh!"), title: Text("Uh-oh!"),
content: Text(isLoginWrong ? "Incorrect login details. Please try again." : "Our servers are having issues at the moment; sorry for the inconvenience. Please try again later."), content: Text(isLoginWrong
? "Incorrect login details. Please try again."
: "Our servers are having issues at the moment; sorry for the inconvenience. Please try again later."),
actions: <Widget>[ actions: <Widget>[
FlatButton( FlatButton(
child: Text('OK'), child: Text('OK'),
@ -30,7 +32,8 @@ Future<void> _incorrectDialog(BuildContext context, bool isLoginWrong) async {
); );
} }
Future<LoginModel> requestLoginAPI(BuildContext context, String email, String password) async { Future<LoginModel> requestLoginAPI(
BuildContext context, String email, String password) async {
final url = "https://dev.localspend.co.uk/api/login"; final url = "https://dev.localspend.co.uk/api/login";
Map<String, String> body = { Map<String, String> body = {
@ -38,19 +41,19 @@ Future<LoginModel> requestLoginAPI(BuildContext context, String email, String pa
'password': password, 'password': password,
}; };
// debugPrint('$body');
try { try {
final response = await http.post( final response = await http
url, .post(
body: json.encode(body), url,
).timeout(Duration(seconds: 5)); body: json.encode(body),
)
.timeout(Duration(seconds: 5));
if (response.statusCode == 200) { if (response.statusCode == 200) {
final responseJson = json.decode(response.body); final responseJson = json.decode(response.body);
saveCurrentLogin(responseJson, body["email"]); saveCurrentLogin(responseJson, body["email"]);
Navigator.of(context).pushReplacementNamed('/HomePage'); await Navigator.of(context).pushReplacementNamed('/HomePage');
return LoginModel.fromJson(responseJson); return LoginModel.fromJson(responseJson);
} else { } else {
@ -58,15 +61,15 @@ Future<LoginModel> requestLoginAPI(BuildContext context, String email, String pa
saveCurrentLogin(responseJson, body["email"]); saveCurrentLogin(responseJson, body["email"]);
_incorrectDialog(context, true); await _incorrectDialog(context, true);
return null; return null;
} }
} on TimeoutException catch (_) { } on TimeoutException catch (_) {
_incorrectDialog(context, false); await _incorrectDialog(context, false);
} catch (error) { } catch (error) {
debugPrint(error.toString()); debugPrint(error.toString());
_incorrectDialog(context, false); await _incorrectDialog(context, false);
} }
return null;
} }

View File

@ -17,7 +17,7 @@ Future<LoginModel> requestLogoutAPI(BuildContext context) async {
}); });
Map<String, String> body = { Map<String, String> body = {
"Token":token, "Token": token,
}; };
final response = await http.post( final response = await http.post(

View File

@ -28,7 +28,7 @@ Future<LoginModel> submitReceiptAPI(
SharedPreferences preferences = await SharedPreferences.getInstance(); SharedPreferences preferences = await SharedPreferences.getInstance();
Map<String, String> body = { Map<String, String> body = {
'transaction_type' : "3", 'transaction_type': "3",
'transaction_value': receipt.amount, 'transaction_value': receipt.amount,
'purchase_time': receipt.time, 'purchase_time': receipt.time,
'category': receipt.category, 'category': receipt.category,
@ -38,7 +38,6 @@ Future<LoginModel> submitReceiptAPI(
'street_name': receipt.street, 'street_name': receipt.street,
'postcode': receipt.postcode, 'postcode': receipt.postcode,
'town': receipt.town, 'town': receipt.town,
'session_key': preferences.get('LastToken'), 'session_key': preferences.get('LastToken'),
}; };
@ -61,13 +60,11 @@ Future<LoginModel> submitReceiptAPI(
context, context,
responseJson[0] == "" ? responseJson[0] : "Upload Successful", responseJson[0] == "" ? responseJson[0] : "Upload Successful",
"Transaction successfully submitted to server", "Transaction successfully submitted to server",
"OK" "OK");
);
return LoginModel.fromJson(responseJson); return LoginModel.fromJson(responseJson);
} else { } else {
final responseJson = json.decode(response.body); final responseJson = json.decode(response.body);
showDialogSingleButton( showDialogSingleButton(
context, context,
"Unable to Submit Receipt", "Unable to Submit Receipt",

View File

@ -103,7 +103,8 @@ class AboutListTile extends StatelessWidget {
return ListTile( return ListTile(
leading: icon, leading: icon,
title: child ?? title: child ??
Text(MaterialLocalizations.of(context).aboutListTileTitle(applicationName ?? _defaultApplicationName(context))), Text(MaterialLocalizations.of(context).aboutListTileTitle(
applicationName ?? _defaultApplicationName(context))),
onTap: () { onTap: () {
showAboutDialog( showAboutDialog(
context: context, context: context,
@ -178,13 +179,14 @@ void showLicensePage({
String applicationLegalese, String applicationLegalese,
}) { }) {
assert(context != null); assert(context != null);
Navigator.push(context, MaterialPageRoute<void>( Navigator.push(
builder: (BuildContext context) => LicensePage( context,
applicationName: applicationName, MaterialPageRoute<void>(
applicationVersion: applicationVersion, builder: (BuildContext context) => LicensePage(
applicationLegalese: applicationLegalese, applicationName: applicationName,
) applicationVersion: applicationVersion,
)); applicationLegalese: applicationLegalese,
)));
} }
/// An about box. This is a dialog box with the application's icon, name, /// An about box. This is a dialog box with the application's icon, name,
@ -256,15 +258,22 @@ class AboutDialog extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
assert(debugCheckHasMaterialLocalizations(context)); assert(debugCheckHasMaterialLocalizations(context));
final String name = applicationName ?? _defaultApplicationName(context); final String name = applicationName ?? _defaultApplicationName(context);
final String version = applicationVersion ?? _defaultApplicationVersion(context); final String version =
applicationVersion ?? _defaultApplicationVersion(context);
final Widget icon = applicationIcon ?? _defaultApplicationIcon(context); final Widget icon = applicationIcon ?? _defaultApplicationIcon(context);
List<Widget> body = <Widget>[]; List<Widget> body = <Widget>[];
if (icon != null) if (icon != null) {
body.add(IconTheme(data: const IconThemeData(size: 45.0), child: icon)); body.add(
IconTheme(
data: const IconThemeData(size: 45.0),
child: icon
),
);
}
body.add(Expanded( body.add(Expanded(
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0), padding: const EdgeInsets.symmetric(horizontal: 24.0),
child: ListBody( child: ListBody(
children: <Widget>[ children: <Widget>[
Container( Container(
@ -272,7 +281,8 @@ class AboutDialog extends StatelessWidget {
child: Text(name, style: Theme.of(context).textTheme.title), child: Text(name, style: Theme.of(context).textTheme.title),
), ),
Text(version, style: Theme.of(context).textTheme.body1), Text(version, style: Theme.of(context).textTheme.body1),
Text(applicationLegalese ?? '', style: Theme.of(context).textTheme.caption), Text(applicationLegalese ?? '',
style: Theme.of(context).textTheme.caption),
], ],
), ),
), ),
@ -283,15 +293,15 @@ class AboutDialog extends StatelessWidget {
children: body, children: body,
), ),
]; ];
if (children != null) if (children != null) body.addAll(children);
body.addAll(children);
return AlertDialog( return AlertDialog(
content: SingleChildScrollView( content: SingleChildScrollView(
child: ListBody(children: body), child: ListBody(children: body),
), ),
actions: <Widget>[ actions: <Widget>[
FlatButton( FlatButton(
child: Text(MaterialLocalizations.of(context).viewLicensesButtonLabel), child:
Text(MaterialLocalizations.of(context).viewLicensesButtonLabel),
onPressed: () { onPressed: () {
showLicensePage( showLicensePage(
context: context, context: context,
@ -376,7 +386,7 @@ class _LicensePageState extends State<LicensePage> {
int debugFlowId = -1; int debugFlowId = -1;
assert(() { assert(() {
final dev.Flow flow = dev.Flow.begin(); final dev.Flow flow = dev.Flow.begin();
dev.Timeline.timeSync('_initLicenses()', () { }, flow: flow); dev.Timeline.timeSync('_initLicenses()', () {}, flow: flow);
debugFlowId = flow.id; debugFlowId = flow.id;
return true; return true;
}()); }());
@ -385,11 +395,12 @@ class _LicensePageState extends State<LicensePage> {
return; return;
} }
assert(() { assert(() {
dev.Timeline.timeSync('_initLicenses()', () { }, flow: dev.Flow.step(debugFlowId)); dev.Timeline.timeSync('_initLicenses()', () {},
flow: dev.Flow.step(debugFlowId));
return true; return true;
}()); }());
final List<LicenseParagraph> paragraphs = final List<LicenseParagraph> paragraphs =
await SchedulerBinding.instance.scheduleTask<List<LicenseParagraph>>( await SchedulerBinding.instance.scheduleTask<List<LicenseParagraph>>(
license.paragraphs.toList, license.paragraphs.toList,
Priority.animation, Priority.animation,
debugLabel: 'License', debugLabel: 'License',
@ -404,8 +415,7 @@ class _LicensePageState extends State<LicensePage> {
)); ));
_licenses.add(Container( _licenses.add(Container(
decoration: const BoxDecoration( decoration: const BoxDecoration(
border: Border(bottom: BorderSide(width: 0.0)) border: Border(bottom: BorderSide(width: 0.0))),
),
child: Text( child: Text(
license.packages.join(', '), license.packages.join(', '),
style: const TextStyle(fontWeight: FontWeight.bold), style: const TextStyle(fontWeight: FontWeight.bold),
@ -425,7 +435,8 @@ class _LicensePageState extends State<LicensePage> {
} else { } else {
assert(paragraph.indent >= 0); assert(paragraph.indent >= 0);
_licenses.add(Padding( _licenses.add(Padding(
padding: EdgeInsetsDirectional.only(top: 8.0, start: 16.0 * paragraph.indent), padding: EdgeInsetsDirectional.only(
top: 8.0, start: 16.0 * paragraph.indent),
child: Text(paragraph.text), child: Text(paragraph.text),
)); ));
} }
@ -436,7 +447,8 @@ class _LicensePageState extends State<LicensePage> {
_loaded = true; _loaded = true;
}); });
assert(() { assert(() {
dev.Timeline.timeSync('Build scheduled', () { }, flow: dev.Flow.end(debugFlowId)); dev.Timeline.timeSync('Build scheduled', () {},
flow: dev.Flow.end(debugFlowId));
return true; return true;
}()); }());
} }
@ -444,16 +456,27 @@ class _LicensePageState extends State<LicensePage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
assert(debugCheckHasMaterialLocalizations(context)); assert(debugCheckHasMaterialLocalizations(context));
final String name = widget.applicationName ?? _defaultApplicationName(context); final String name =
final String version = widget.applicationVersion ?? _defaultApplicationVersion(context); widget.applicationName ?? _defaultApplicationName(context);
final MaterialLocalizations localizations = MaterialLocalizations.of(context); final String version =
widget.applicationVersion ?? _defaultApplicationVersion(context);
final MaterialLocalizations localizations =
MaterialLocalizations.of(context);
final List<Widget> contents = <Widget>[ final List<Widget> contents = <Widget>[
Text(name, style: Theme.of(context).textTheme.headline, textAlign: TextAlign.center), Text(name,
Text(version, style: Theme.of(context).textTheme.body1, textAlign: TextAlign.center), style: Theme.of(context).textTheme.headline,
textAlign: TextAlign.center),
Text(version,
style: Theme.of(context).textTheme.body1,
textAlign: TextAlign.center),
Container(height: 18.0), Container(height: 18.0),
Text(widget.applicationLegalese ?? '', style: Theme.of(context).textTheme.caption, textAlign: TextAlign.center), Text(widget.applicationLegalese ?? '',
style: Theme.of(context).textTheme.caption,
textAlign: TextAlign.center),
Container(height: 18.0), Container(height: 18.0),
Text('Powered by Flutter', style: Theme.of(context).textTheme.body1, textAlign: TextAlign.center), Text('Powered by Flutter',
style: Theme.of(context).textTheme.body1,
textAlign: TextAlign.center),
Container(height: 24.0), Container(height: 24.0),
]; ];
contents.addAll(_licenses); contents.addAll(_licenses);
@ -480,7 +503,8 @@ class _LicensePageState extends State<LicensePage> {
bottom: false, bottom: false,
child: Scrollbar( child: Scrollbar(
child: ListView( child: ListView(
padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 12.0), padding:
const EdgeInsets.symmetric(horizontal: 8.0, vertical: 12.0),
children: contents, children: contents,
), ),
), ),
@ -499,7 +523,8 @@ String _defaultApplicationName(BuildContext context) {
// can provide an explicit applicationName to the widgets defined in this // can provide an explicit applicationName to the widgets defined in this
// file, instead of relying on the default. // file, instead of relying on the default.
final Title ancestorTitle = context.ancestorWidgetOfExactType(Title); final Title ancestorTitle = context.ancestorWidgetOfExactType(Title);
return ancestorTitle?.title ?? Platform.resolvedExecutable.split(Platform.pathSeparator).last; return ancestorTitle?.title ??
Platform.resolvedExecutable.split(Platform.pathSeparator).last;
} }
String _defaultApplicationVersion(BuildContext context) { String _defaultApplicationVersion(BuildContext context) {

View File

@ -2,8 +2,7 @@ import 'package:flutter/material.dart';
final TextEditingController _feedbackController = TextEditingController(); final TextEditingController _feedbackController = TextEditingController();
void feedback( void feedback(BuildContext context) {
BuildContext context) {
// flutter defined function // flutter defined function
showDialog( showDialog(
context: context, context: context,
@ -15,13 +14,11 @@ void feedback(
children: <Widget>[ children: <Widget>[
Text("We would love to hear your thoughts."), Text("We would love to hear your thoughts."),
Text("\nThis section needs to be fixed."), Text("\nThis section needs to be fixed."),
Container( Container(
margin: const EdgeInsets.fromLTRB(0, 20, 0, 0), margin: const EdgeInsets.fromLTRB(0, 20, 0, 0),
width: 200, width: 200,
height: 70, height: 70,
child: new TextField(
child : new TextField(
controller: _feedbackController, controller: _feedbackController,
decoration: InputDecoration( decoration: InputDecoration(
hintText: 'Enter your feedback here', hintText: 'Enter your feedback here',
@ -41,7 +38,7 @@ void feedback(
), ),
new Container( new Container(
padding: const EdgeInsets.fromLTRB(0, 10, 0, 0), padding: const EdgeInsets.fromLTRB(0, 10, 0, 0),
child : new FlatButton( child: new FlatButton(
child: new Text("Submit"), child: new Text("Submit"),
onPressed: () { onPressed: () {
submit(_feedbackController.text); submit(_feedbackController.text);
@ -58,4 +55,4 @@ void feedback(
void submit(String feedback) { void submit(String feedback) {
debugPrint(feedback); debugPrint(feedback);
} }

View File

@ -1,6 +1,7 @@
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'dart:async';
getToken() async { Future<String> getToken() async {
SharedPreferences preferences = await SharedPreferences.getInstance(); SharedPreferences preferences = await SharedPreferences.getInstance();
String getToken = preferences.getString("LastToken"); String getToken = preferences.getString("LastToken");

View File

@ -2,16 +2,16 @@ import 'package:flutter/material.dart';
import 'package:local_spend/common/apifunctions/request_logout_api.dart'; import 'package:local_spend/common/apifunctions/request_logout_api.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
logout(context) { void logout(context) {
requestLogoutAPI(context); requestLogoutAPI(context);
Navigator.of(context).pushReplacementNamed('/LoginPage'); Navigator.of(context).pushReplacementNamed('/LoginPage');
_clearLoginDetails(); _clearLoginDetails();
} }
_clearLoginDetails() async { void _clearLoginDetails() async {
SharedPreferences preferences = await SharedPreferences.getInstance(); SharedPreferences preferences = await SharedPreferences.getInstance();
preferences.setString('username', ""); await preferences.setString('username', "");
preferences.setString('password', ""); await preferences.setString('password', "");
print("details cleared"); print("details cleared");
} }

View File

@ -1,7 +1,7 @@
import 'package:local_spend/model/json/login_model.dart'; import 'package:local_spend/model/json/login_model.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
saveCurrentLogin(Map responseJson, loginEmail) async { void saveCurrentLogin(Map responseJson, loginEmail) async {
SharedPreferences preferences = await SharedPreferences.getInstance(); SharedPreferences preferences = await SharedPreferences.getInstance();
var user; var user;
@ -13,9 +13,7 @@ saveCurrentLogin(Map responseJson, loginEmail) async {
var token = (responseJson != null && responseJson.isNotEmpty) var token = (responseJson != null && responseJson.isNotEmpty)
? LoginModel.fromJson(responseJson).token ? LoginModel.fromJson(responseJson).token
: ""; : "";
var email = (loginEmail != null) var email = (loginEmail != null) ? loginEmail : "";
? loginEmail
: "";
var userType = (responseJson != null && responseJson.isNotEmpty) var userType = (responseJson != null && responseJson.isNotEmpty)
? LoginModel.fromJson(responseJson).userType ? LoginModel.fromJson(responseJson).userType
: ""; : "";
@ -23,9 +21,9 @@ saveCurrentLogin(Map responseJson, loginEmail) async {
await preferences.setString( await preferences.setString(
'LastUser', (user != null && user.length > 0) ? user : ""); 'LastUser', (user != null && user.length > 0) ? user : "");
await preferences.setString( await preferences.setString(
'LastToken', (token != null && token.length > 0) ? token : ""); 'LastToken', (token != null && token.isNotEmpty) ? token : "");
await preferences.setString( await preferences.setString(
'LastEmail', (email != null && email.length > 0) ? email : ""); 'LastEmail', (email != null && email.length > 0) ? email : "");
await preferences.setString( await preferences.setString('LastUserType',
'LastUserType', (userType != null && userType.length > 0) ? userType : ""); (userType != null && userType.isNotEmpty) ? userType : "");
} }

View File

@ -1,6 +1,6 @@
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
saveLogout() async { void saveLogout() async {
SharedPreferences preferences = await SharedPreferences.getInstance(); SharedPreferences preferences = await SharedPreferences.getInstance();
await preferences.setString('LastUser', ""); await preferences.setString('LastUser', "");

View File

@ -1,7 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
void showDialogTwoButtons( void showDialogTwoButtons(BuildContext context, String title, String message,
BuildContext context, String title, String message, String buttonLabel1, String buttonLabel2, Function action) { String buttonLabel1, String buttonLabel2, Function action) {
// flutter defined function // flutter defined function
showDialog( showDialog(
context: context, context: context,

View File

@ -4,6 +4,25 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class PlatformScaffold extends StatelessWidget { class PlatformScaffold extends StatelessWidget {
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
final Key key; final Key key;
final PreferredSizeWidget appBar; final PreferredSizeWidget appBar;
final Widget body; final Widget body;
@ -18,23 +37,6 @@ class PlatformScaffold extends StatelessWidget {
final bool resizeToAvoidBottomPadding; final bool resizeToAvoidBottomPadding;
final bool primary; 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 @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Platform.isIOS return Platform.isIOS

View File

@ -2,10 +2,6 @@ import 'package:flutter/material.dart';
import 'package:simple_animations/simple_animations.dart'; import 'package:simple_animations/simple_animations.dart';
class AnimatedBackground extends StatelessWidget { class AnimatedBackground extends StatelessWidget {
final List<Color> animateColors;
final Color lastColor;
final Alignment begin, end;
final int duration;
AnimatedBackground( AnimatedBackground(
this.animateColors, this.animateColors,
@ -15,6 +11,11 @@ class AnimatedBackground extends StatelessWidget {
this.duration, this.duration,
); );
final List<Color> animateColors;
final Color lastColor;
final Alignment begin, end;
final int duration;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final tween = MultiTrackTween([ final tween = MultiTrackTween([
@ -37,4 +38,4 @@ class AnimatedBackground extends StatelessWidget {
}, },
); );
} }
} }

View File

@ -4,9 +4,6 @@ import 'package:charts_flutter/flutter.dart' as charts;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class DonutAutoLabelChart extends StatelessWidget { class DonutAutoLabelChart extends StatelessWidget {
final List<charts.Series> seriesList;
final bool animate;
DonutAutoLabelChart(this.seriesList, {this.animate}); DonutAutoLabelChart(this.seriesList, {this.animate});
/// Creates a [PieChart] with sample data and no transition. /// Creates a [PieChart] with sample data and no transition.
@ -18,6 +15,8 @@ class DonutAutoLabelChart extends StatelessWidget {
); );
} }
final List<charts.Series> seriesList;
final bool animate;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -67,8 +66,8 @@ class DonutAutoLabelChart extends StatelessWidget {
/// Sample linear data type. /// Sample linear data type.
class LinearSales { class LinearSales {
LinearSales(this.key, this.sales);
final String key; final String key;
final int sales; final int sales;
}
LinearSales(this.key, this.sales);
}

View File

@ -2,13 +2,12 @@ import 'package:flutter/material.dart';
import 'package:local_spend/common/widgets/charts/time_series_simple.dart'; import 'package:local_spend/common/widgets/charts/time_series_simple.dart';
class TimeSeries extends StatelessWidget { class TimeSeries extends StatelessWidget {
final String chartDataName;
TimeSeries({ TimeSeries({
this.chartDataName, this.chartDataName,
}); });
final String chartDataName;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return new Container( return new Container(
@ -16,4 +15,4 @@ class TimeSeries extends StatelessWidget {
child: SimpleTimeSeriesChart.withSampleData(), child: SimpleTimeSeriesChart.withSampleData(),
); );
} }
} }

View File

@ -3,9 +3,6 @@ import 'package:charts_flutter/flutter.dart' as charts;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class DonutPieChart extends StatelessWidget { class DonutPieChart extends StatelessWidget {
final List<charts.Series> seriesList;
final bool animate;
DonutPieChart(this.seriesList, {this.animate}); DonutPieChart(this.seriesList, {this.animate});
/// Creates a [PieChart] with sample data and no transition. /// Creates a [PieChart] with sample data and no transition.
@ -16,6 +13,8 @@ class DonutPieChart extends StatelessWidget {
); );
} }
final List<charts.Series> seriesList;
final bool animate;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -46,11 +45,10 @@ class DonutPieChart extends StatelessWidget {
} }
} }
/// Sample linear data type. /// Sample linear data type.
class LinearSales { class LinearSales {
LinearSales(this.year, this.sales);
final int year; final int year;
final int sales; final int sales;
}
LinearSales(this.year, this.sales);
}

View File

@ -3,9 +3,6 @@ import 'package:flutter/material.dart';
import 'package:charts_flutter/flutter.dart' as charts; import 'package:charts_flutter/flutter.dart' as charts;
class GroupedBarChart extends StatelessWidget { class GroupedBarChart extends StatelessWidget {
final List<charts.Series> seriesList;
final bool animate;
GroupedBarChart(this.seriesList, {this.animate}); GroupedBarChart(this.seriesList, {this.animate});
factory GroupedBarChart.withSampleData() { factory GroupedBarChart.withSampleData() {
@ -16,6 +13,8 @@ class GroupedBarChart extends StatelessWidget {
); );
} }
final List<charts.Series> seriesList;
final bool animate;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -74,8 +73,8 @@ class GroupedBarChart extends StatelessWidget {
/// Sample ordinal data type. /// Sample ordinal data type.
class OrdinalSales { class OrdinalSales {
OrdinalSales(this.year, this.sales);
final String year; final String year;
final int sales; final int sales;
}
OrdinalSales(this.year, this.sales);
}

View File

@ -4,8 +4,6 @@ import 'package:charts_flutter/flutter.dart' as charts;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class NumericComboLineBarChart extends StatelessWidget { class NumericComboLineBarChart extends StatelessWidget {
final List<charts.Series> seriesList;
final bool animate;
NumericComboLineBarChart(this.seriesList, {this.animate}); NumericComboLineBarChart(this.seriesList, {this.animate});
@ -18,6 +16,8 @@ class NumericComboLineBarChart extends StatelessWidget {
); );
} }
final List<charts.Series> seriesList;
final bool animate;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -29,7 +29,7 @@ class NumericComboLineBarChart extends StatelessWidget {
// Custom renderer configuration for the bar series. // Custom renderer configuration for the bar series.
customSeriesRenderers: [ customSeriesRenderers: [
new charts.BarRendererConfig( new charts.BarRendererConfig(
// ID used to link series to this renderer. // ID used to link series to this renderer.
customRendererId: 'customBar') customRendererId: 'customBar')
]); ]);
} }
@ -65,7 +65,7 @@ class NumericComboLineBarChart extends StatelessWidget {
measureFn: (LinearSales sales, _) => sales.sales, measureFn: (LinearSales sales, _) => sales.sales,
data: desktopSalesData, data: desktopSalesData,
) )
// Configure our custom bar renderer for this series. // Configure our custom bar renderer for this series.
..setAttribute(charts.rendererIdKey, 'customBar'), ..setAttribute(charts.rendererIdKey, 'customBar'),
new charts.Series<LinearSales, int>( new charts.Series<LinearSales, int>(
id: 'Tablet', id: 'Tablet',
@ -74,7 +74,7 @@ class NumericComboLineBarChart extends StatelessWidget {
measureFn: (LinearSales sales, _) => sales.sales, measureFn: (LinearSales sales, _) => sales.sales,
data: tableSalesData, data: tableSalesData,
) )
// Configure our custom bar renderer for this series. // Configure our custom bar renderer for this series.
..setAttribute(charts.rendererIdKey, 'customBar'), ..setAttribute(charts.rendererIdKey, 'customBar'),
new charts.Series<LinearSales, int>( new charts.Series<LinearSales, int>(
id: 'Mobile', id: 'Mobile',
@ -88,8 +88,8 @@ class NumericComboLineBarChart extends StatelessWidget {
/// Sample linear data type. /// Sample linear data type.
class LinearSales { class LinearSales {
LinearSales(this.year, this.sales);
final int year; final int year;
final int sales; final int sales;
}
LinearSales(this.year, this.sales);
}

View File

@ -3,9 +3,6 @@ import 'package:charts_flutter/flutter.dart' as charts;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class PieOutsideLabelChart extends StatelessWidget { class PieOutsideLabelChart extends StatelessWidget {
final List<charts.Series> seriesList;
final bool animate;
PieOutsideLabelChart(this.seriesList, {this.animate}); PieOutsideLabelChart(this.seriesList, {this.animate});
/// Creates a [PieChart] with sample data and no transition. /// Creates a [PieChart] with sample data and no transition.
@ -17,6 +14,8 @@ class PieOutsideLabelChart extends StatelessWidget {
); );
} }
final List<charts.Series> seriesList;
final bool animate;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -62,8 +61,8 @@ class PieOutsideLabelChart extends StatelessWidget {
/// Sample linear data type. /// Sample linear data type.
class LinearSales { class LinearSales {
LinearSales(this.year, this.sales);
final int year; final int year;
final int sales; final int sales;
}
LinearSales(this.year, this.sales);
}

View File

@ -8,8 +8,6 @@ import 'package:charts_flutter/flutter.dart' as charts;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class BucketingAxisScatterPlotChart extends StatelessWidget { class BucketingAxisScatterPlotChart extends StatelessWidget {
final List<charts.Series> seriesList;
final bool animate;
BucketingAxisScatterPlotChart(this.seriesList, {this.animate}); BucketingAxisScatterPlotChart(this.seriesList, {this.animate});
@ -22,6 +20,8 @@ class BucketingAxisScatterPlotChart extends StatelessWidget {
); );
} }
final List<charts.Series> seriesList;
final bool animate;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -77,7 +77,7 @@ class BucketingAxisScatterPlotChart extends StatelessWidget {
new charts.Series<LinearSales, int>( new charts.Series<LinearSales, int>(
id: 'Cheese', id: 'Cheese',
colorFn: (LinearSales sales, _) => colorFn: (LinearSales sales, _) =>
charts.MaterialPalette.blue.shadeDefault, charts.MaterialPalette.blue.shadeDefault,
domainFn: (LinearSales sales, _) => sales.year, domainFn: (LinearSales sales, _) => sales.year,
measureFn: (LinearSales sales, _) => sales.revenueShare, measureFn: (LinearSales sales, _) => sales.revenueShare,
radiusPxFn: (LinearSales sales, _) => sales.radius, radiusPxFn: (LinearSales sales, _) => sales.radius,
@ -85,7 +85,7 @@ class BucketingAxisScatterPlotChart extends StatelessWidget {
new charts.Series<LinearSales, int>( new charts.Series<LinearSales, int>(
id: 'Carrots', id: 'Carrots',
colorFn: (LinearSales sales, _) => colorFn: (LinearSales sales, _) =>
charts.MaterialPalette.red.shadeDefault, charts.MaterialPalette.red.shadeDefault,
domainFn: (LinearSales sales, _) => sales.year, domainFn: (LinearSales sales, _) => sales.year,
measureFn: (LinearSales sales, _) => sales.revenueShare, measureFn: (LinearSales sales, _) => sales.revenueShare,
radiusPxFn: (LinearSales sales, _) => sales.radius, radiusPxFn: (LinearSales sales, _) => sales.radius,
@ -93,7 +93,7 @@ class BucketingAxisScatterPlotChart extends StatelessWidget {
new charts.Series<LinearSales, int>( new charts.Series<LinearSales, int>(
id: 'Cucumbers', id: 'Cucumbers',
colorFn: (LinearSales sales, _) => colorFn: (LinearSales sales, _) =>
charts.MaterialPalette.green.shadeDefault, charts.MaterialPalette.green.shadeDefault,
domainFn: (LinearSales sales, _) => sales.year, domainFn: (LinearSales sales, _) => sales.year,
measureFn: (LinearSales sales, _) => sales.revenueShare, measureFn: (LinearSales sales, _) => sales.revenueShare,
radiusPxFn: (LinearSales sales, _) => sales.radius, radiusPxFn: (LinearSales sales, _) => sales.radius,
@ -101,7 +101,7 @@ class BucketingAxisScatterPlotChart extends StatelessWidget {
new charts.Series<LinearSales, int>( new charts.Series<LinearSales, int>(
id: 'Crayons', id: 'Crayons',
colorFn: (LinearSales sales, _) => colorFn: (LinearSales sales, _) =>
charts.MaterialPalette.purple.shadeDefault, charts.MaterialPalette.purple.shadeDefault,
domainFn: (LinearSales sales, _) => sales.year, domainFn: (LinearSales sales, _) => sales.year,
measureFn: (LinearSales sales, _) => sales.revenueShare, measureFn: (LinearSales sales, _) => sales.revenueShare,
radiusPxFn: (LinearSales sales, _) => sales.radius, radiusPxFn: (LinearSales sales, _) => sales.radius,
@ -109,7 +109,7 @@ class BucketingAxisScatterPlotChart extends StatelessWidget {
new charts.Series<LinearSales, int>( new charts.Series<LinearSales, int>(
id: 'Celery', id: 'Celery',
colorFn: (LinearSales sales, _) => colorFn: (LinearSales sales, _) =>
charts.MaterialPalette.indigo.shadeDefault, charts.MaterialPalette.indigo.shadeDefault,
domainFn: (LinearSales sales, _) => sales.year, domainFn: (LinearSales sales, _) => sales.year,
measureFn: (LinearSales sales, _) => sales.revenueShare, measureFn: (LinearSales sales, _) => sales.revenueShare,
radiusPxFn: (LinearSales sales, _) => sales.radius, radiusPxFn: (LinearSales sales, _) => sales.radius,
@ -117,7 +117,7 @@ class BucketingAxisScatterPlotChart extends StatelessWidget {
new charts.Series<LinearSales, int>( new charts.Series<LinearSales, int>(
id: 'Cauliflower', id: 'Cauliflower',
colorFn: (LinearSales sales, _) => colorFn: (LinearSales sales, _) =>
charts.MaterialPalette.gray.shadeDefault, charts.MaterialPalette.gray.shadeDefault,
domainFn: (LinearSales sales, _) => sales.year, domainFn: (LinearSales sales, _) => sales.year,
measureFn: (LinearSales sales, _) => sales.revenueShare, measureFn: (LinearSales sales, _) => sales.revenueShare,
radiusPxFn: (LinearSales sales, _) => sales.radius, radiusPxFn: (LinearSales sales, _) => sales.radius,
@ -128,9 +128,9 @@ class BucketingAxisScatterPlotChart extends StatelessWidget {
/// Sample linear data type. /// Sample linear data type.
class LinearSales { class LinearSales {
LinearSales(this.year, this.revenueShare, this.radius);
final int year; final int year;
final double revenueShare; final double revenueShare;
final double radius; final double radius;
}
LinearSales(this.year, this.revenueShare, this.radius);
}

View File

@ -11,9 +11,6 @@ import 'package:charts_flutter/flutter.dart' as charts;
/// ///
/// Also shows the option to provide a custom measure formatter. /// Also shows the option to provide a custom measure formatter.
class LegendWithMeasures extends StatelessWidget { class LegendWithMeasures extends StatelessWidget {
final List<charts.Series> seriesList;
final bool animate;
LegendWithMeasures(this.seriesList, {this.animate}); LegendWithMeasures(this.seriesList, {this.animate});
factory LegendWithMeasures.withSampleData() { factory LegendWithMeasures.withSampleData() {
@ -24,6 +21,8 @@ class LegendWithMeasures extends StatelessWidget {
); );
} }
final List<charts.Series> seriesList;
final bool animate;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -122,8 +121,8 @@ class LegendWithMeasures extends StatelessWidget {
/// Sample ordinal data type. /// Sample ordinal data type.
class OrdinalSales { class OrdinalSales {
OrdinalSales(this.year, this.sales);
final String year; final String year;
final int sales; final int sales;
}
OrdinalSales(this.year, this.sales);
}

View File

@ -3,9 +3,6 @@ import 'package:charts_flutter/flutter.dart' as charts;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class SimpleTimeSeriesChart extends StatelessWidget { class SimpleTimeSeriesChart extends StatelessWidget {
final List<charts.Series> seriesList;
final bool animate;
SimpleTimeSeriesChart(this.seriesList, {this.animate}); SimpleTimeSeriesChart(this.seriesList, {this.animate});
/// Creates a [TimeSeriesChart] with sample data and no transition. /// Creates a [TimeSeriesChart] with sample data and no transition.
@ -17,6 +14,8 @@ class SimpleTimeSeriesChart extends StatelessWidget {
); );
} }
final List<charts.Series> seriesList;
final bool animate;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -53,8 +52,8 @@ class SimpleTimeSeriesChart extends StatelessWidget {
/// Sample time series data type. /// Sample time series data type.
class TimeSeriesSales { class TimeSeriesSales {
TimeSeriesSales(this.time, this.sales);
final DateTime time; final DateTime time;
final int sales; final int sales;
}
TimeSeriesSales(this.time, this.sales);
}

View File

@ -58,12 +58,10 @@ class CustomCheckbox extends StatefulWidget {
this.checkColor, this.checkColor,
this.materialTapTargetSize, this.materialTapTargetSize,
this.useTapTarget = true, this.useTapTarget = true,
}) : assert(tristate != null), }) : assert(tristate != null),
assert(tristate || value != null), assert(tristate || value != null),
super(key: key); super(key: key);
final bool useTapTarget; final bool useTapTarget;
/// Whether this checkbox is checked. /// Whether this checkbox is checked.
@ -138,7 +136,8 @@ class CustomCheckbox extends StatefulWidget {
_CustomCheckboxState createState() => _CustomCheckboxState(); _CustomCheckboxState createState() => _CustomCheckboxState();
} }
class _CustomCheckboxState extends State<CustomCheckbox> with TickerProviderStateMixin { class _CustomCheckboxState extends State<CustomCheckbox>
with TickerProviderStateMixin {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
assert(debugCheckHasMaterial(context)); assert(debugCheckHasMaterial(context));
@ -147,25 +146,26 @@ class _CustomCheckboxState extends State<CustomCheckbox> with TickerProviderStat
Size size; Size size;
switch (widget.materialTapTargetSize ?? themeData.materialTapTargetSize) { switch (widget.materialTapTargetSize ?? themeData.materialTapTargetSize) {
case MaterialTapTargetSize.padded: case MaterialTapTargetSize.padded:
size = const Size(2 * kRadialReactionRadius + 8.0, 2 * kRadialReactionRadius + 8.0); size = const Size(
2 * kRadialReactionRadius + 8.0, 2 * kRadialReactionRadius + 8.0);
break; break;
case MaterialTapTargetSize.shrinkWrap: case MaterialTapTargetSize.shrinkWrap:
size = const Size(2 * kRadialReactionRadius, 2 * kRadialReactionRadius); size = const Size(2 * kRadialReactionRadius, 2 * kRadialReactionRadius);
break; break;
} }
Size noTapTargetSize = Size(CustomCheckbox.width, Size noTapTargetSize = Size(CustomCheckbox.width, CustomCheckbox.width);
CustomCheckbox.width);
final BoxConstraints additionalConstraints = final BoxConstraints additionalConstraints =
BoxConstraints.tight(widget BoxConstraints.tight(widget.useTapTarget ? size : noTapTargetSize);
.useTapTarget? size : noTapTargetSize);
return _CheckboxRenderObjectWidget( return _CheckboxRenderObjectWidget(
value: widget.value, value: widget.value,
tristate: widget.tristate, tristate: widget.tristate,
activeColor: widget.activeColor ?? themeData.toggleableActiveColor, activeColor: widget.activeColor ?? themeData.toggleableActiveColor,
checkColor: widget.checkColor ?? const Color(0xFFFFFFFF), checkColor: widget.checkColor ?? const Color(0xFFFFFFFF),
inactiveColor: widget.onChanged != null ? themeData.unselectedWidgetColor : themeData.disabledColor, inactiveColor: widget.onChanged != null
? themeData.unselectedWidgetColor
: themeData.disabledColor,
onChanged: widget.onChanged, onChanged: widget.onChanged,
additionalConstraints: additionalConstraints, additionalConstraints: additionalConstraints,
vsync: this, vsync: this,
@ -174,19 +174,18 @@ class _CustomCheckboxState extends State<CustomCheckbox> with TickerProviderStat
} }
class _CheckboxRenderObjectWidget extends LeafRenderObjectWidget { class _CheckboxRenderObjectWidget extends LeafRenderObjectWidget {
const _CheckboxRenderObjectWidget({ const _CheckboxRenderObjectWidget(
Key key, {Key key,
@required this.value, @required this.value,
@required this.tristate, @required this.tristate,
@required this.activeColor, @required this.activeColor,
@required this.checkColor, @required this.checkColor,
@required this.inactiveColor, @required this.inactiveColor,
@required this.onChanged, @required this.onChanged,
@required this.vsync, @required this.vsync,
@required this.additionalConstraints, @required this.additionalConstraints,
this.useTapTarget = true this.useTapTarget = true})
: assert(tristate != null),
}) : assert(tristate != null),
assert(tristate || value != null), assert(tristate || value != null),
assert(activeColor != null), assert(activeColor != null),
assert(inactiveColor != null), assert(inactiveColor != null),
@ -205,15 +204,15 @@ class _CheckboxRenderObjectWidget extends LeafRenderObjectWidget {
@override @override
_RenderCheckbox createRenderObject(BuildContext context) => _RenderCheckbox( _RenderCheckbox createRenderObject(BuildContext context) => _RenderCheckbox(
value: value, value: value,
tristate: tristate, tristate: tristate,
activeColor: activeColor, activeColor: activeColor,
checkColor: checkColor, checkColor: checkColor,
inactiveColor: inactiveColor, inactiveColor: inactiveColor,
onChanged: onChanged, onChanged: onChanged,
vsync: vsync, vsync: vsync,
additionalConstraints: additionalConstraints, additionalConstraints: additionalConstraints,
); );
@override @override
void updateRenderObject(BuildContext context, _RenderCheckbox renderObject) { void updateRenderObject(BuildContext context, _RenderCheckbox renderObject) {
@ -243,24 +242,23 @@ class _RenderCheckbox extends RenderToggleable {
BoxConstraints additionalConstraints, BoxConstraints additionalConstraints,
ValueChanged<bool> onChanged, ValueChanged<bool> onChanged,
@required TickerProvider vsync, @required TickerProvider vsync,
}) : _oldValue = value, }) : _oldValue = value,
super( super(
value: value, value: value,
tristate: tristate, tristate: tristate,
activeColor: activeColor, activeColor: activeColor,
inactiveColor: inactiveColor, inactiveColor: inactiveColor,
onChanged: onChanged, onChanged: onChanged,
additionalConstraints: additionalConstraints, additionalConstraints: additionalConstraints,
vsync: vsync, vsync: vsync,
); );
bool _oldValue; bool _oldValue;
Color checkColor; Color checkColor;
@override @override
set value(bool newValue) { set value(bool newValue) {
if (newValue == value) if (newValue == value) return;
return;
_oldValue = value; _oldValue = value;
super.value = newValue; super.value = newValue;
} }
@ -278,7 +276,8 @@ class _RenderCheckbox extends RenderToggleable {
RRect _outerRectAt(Offset origin, double t) { RRect _outerRectAt(Offset origin, double t) {
final double inset = 1.0 - (t - 0.5).abs() * 2.0; final double inset = 1.0 - (t - 0.5).abs() * 2.0;
final double size = _kEdgeSize - inset * _kStrokeWidth; final double size = _kEdgeSize - inset * _kStrokeWidth;
final Rect rect = Rect.fromLTWH(origin.dx + inset, origin.dy + inset, size, size); final Rect rect =
Rect.fromLTWH(origin.dx + inset, origin.dy + inset, size, size);
return RRect.fromRectAndRadius(rect, _kEdgeRadius); return RRect.fromRectAndRadius(rect, _kEdgeRadius);
} }
@ -288,7 +287,9 @@ class _RenderCheckbox extends RenderToggleable {
// As t goes from 0.0 to 0.25, animate from the inactiveColor to activeColor. // As t goes from 0.0 to 0.25, animate from the inactiveColor to activeColor.
return onChanged == null return onChanged == null
? inactiveColor ? inactiveColor
: (t >= 0.25 ? activeColor : Color.lerp(inactiveColor, activeColor, t * 4.0)); : (t >= 0.25
? activeColor
: Color.lerp(inactiveColor, activeColor, t * 4.0));
} }
// White stroke used to paint the check and dash. // White stroke used to paint the check and dash.
@ -303,7 +304,8 @@ class _RenderCheckbox extends RenderToggleable {
assert(t >= 0.0 && t <= 0.5); assert(t >= 0.0 && t <= 0.5);
final double size = outer.width; final double size = outer.width;
// As t goes from 0.0 to 1.0, gradually fill the outer RRect. // As t goes from 0.0 to 1.0, gradually fill the outer RRect.
final RRect inner = outer.deflate(math.min(size / 2.0, _kStrokeWidth + size * t)); final RRect inner =
outer.deflate(math.min(size / 2.0, _kStrokeWidth + size * t));
canvas.drawDRRect(outer, inner, paint); canvas.drawDRRect(outer, inner, paint);
} }
@ -347,11 +349,13 @@ class _RenderCheckbox extends RenderToggleable {
final Canvas canvas = context.canvas; final Canvas canvas = context.canvas;
paintRadialReaction(canvas, offset, size.center(Offset.zero)); paintRadialReaction(canvas, offset, size.center(Offset.zero));
final Offset origin = offset + (size / 2.0 - const Size.square(_kEdgeSize) / 2.0); final Offset origin =
offset + (size / 2.0 - const Size.square(_kEdgeSize) / 2.0);
final AnimationStatus status = position.status; final AnimationStatus status = position.status;
final double tNormalized = status == AnimationStatus.forward || status == AnimationStatus.completed final double tNormalized =
? position.value status == AnimationStatus.forward || status == AnimationStatus.completed
: 1.0 - position.value; ? position.value
: 1.0 - position.value;
// Four cases: false to null, false to true, null to false, true to false // Four cases: false to null, false to true, null to false, true to false
if (_oldValue == false || value == false) { if (_oldValue == false || value == false) {
@ -366,29 +370,36 @@ class _RenderCheckbox extends RenderToggleable {
_initStrokePaint(paint); _initStrokePaint(paint);
final double tShrink = (t - 0.5) * 2.0; final double tShrink = (t - 0.5) * 2.0;
if (_oldValue == null || value == null) if (_oldValue == null || value == null) {
_drawDash(canvas, origin, tShrink, paint); _drawDash(canvas, origin, tShrink, paint);
else }
else {
_drawCheck(canvas, origin, tShrink, paint); _drawCheck(canvas, origin, tShrink, paint);
}
} }
} else { // Two cases: null to true, true to null } else {
// Two cases: null to true, true to null
final RRect outer = _outerRectAt(origin, 1.0); final RRect outer = _outerRectAt(origin, 1.0);
final Paint paint = Paint() ..color = _colorAt(1.0); final Paint paint = Paint()..color = _colorAt(1.0);
canvas.drawRRect(outer, paint); canvas.drawRRect(outer, paint);
_initStrokePaint(paint); _initStrokePaint(paint);
if (tNormalized <= 0.5) { if (tNormalized <= 0.5) {
final double tShrink = 1.0 - tNormalized * 2.0; final double tShrink = 1.0 - tNormalized * 2.0;
if (_oldValue == true) if (_oldValue == true) {
_drawCheck(canvas, origin, tShrink, paint); _drawCheck(canvas, origin, tShrink, paint);
else }
else {
_drawDash(canvas, origin, tShrink, paint); _drawDash(canvas, origin, tShrink, paint);
}
} else { } else {
final double tExpand = (tNormalized - 0.5) * 2.0; final double tExpand = (tNormalized - 0.5) * 2.0;
if (value == true) if (value == true) {
_drawCheck(canvas, origin, tExpand, paint); _drawCheck(canvas, origin, tExpand, paint);
else }
else {
_drawDash(canvas, origin, tExpand, paint); _drawDash(canvas, origin, tExpand, paint);
}
} }
} }
} }

View File

@ -28,11 +28,8 @@ class LabeledCheckboxWithIcon extends StatelessWidget {
onTap: () { onTap: () {
onChanged(!value); onChanged(!value);
}, },
child: Padding( child: Padding(
padding: padding, padding: padding,
child: Row( child: Row(
// crossAxisAlignment: CrossAxisAlignment.center, //doesn't do anything // crossAxisAlignment: CrossAxisAlignment.center, //doesn't do anything
@ -40,16 +37,18 @@ class LabeledCheckboxWithIcon extends StatelessWidget {
Container( Container(
padding: EdgeInsets.all(0), padding: EdgeInsets.all(0),
width: iconSize, width: iconSize,
child: Icon(
child : Icon(
icon, icon,
// size: iconSize, // size: iconSize,
color: iconColor, color: iconColor,
), ),
), ),
Expanded(
Expanded(child: Text(label, style: textStyle, textAlign: TextAlign.center,)), child: Text(
label,
style: textStyle,
textAlign: TextAlign.center,
)),
CustomCheckbox( CustomCheckbox(
//custom checkbox removes padding so the form looks nice //custom checkbox removes padding so the form looks nice
@ -89,11 +88,9 @@ class LabeledCheckbox extends StatelessWidget {
}, },
child: Padding( child: Padding(
padding: padding, padding: padding,
child: Row( child: Row(
children: <Widget>[ children: <Widget>[
Expanded(child: Text(label, style: textStyle)), Expanded(child: Text(label, style: textStyle)),
CustomCheckbox( CustomCheckbox(
//custom checkbox removes padding so the form looks nice //custom checkbox removes padding so the form looks nice
@ -110,7 +107,6 @@ class LabeledCheckbox extends StatelessWidget {
} }
} }
/* /*
//USAGE: //USAGE:
@ -134,4 +130,4 @@ Widget build(BuildContext context) {
), ),
); );
} }
*/ */

View File

@ -4,7 +4,6 @@ import 'package:flutter/services.dart';
import 'package:local_spend/common/apifunctions/find_organisations.dart'; import 'package:local_spend/common/apifunctions/find_organisations.dart';
class FindOrganisations { class FindOrganisations {
TextField getSearchBar(TextEditingController controller, String hintText) { TextField getSearchBar(TextEditingController controller, String hintText) {
return TextField( return TextField(
controller: controller, controller: controller,
@ -20,12 +19,12 @@ class FindOrganisations {
Future<dynamic> _moreInfoDialog(context, Organisation organisation) { Future<dynamic> _moreInfoDialog(context, Organisation organisation) {
TextStyle informationTitleStyle = new TextStyle(fontSize: 16); TextStyle informationTitleStyle = new TextStyle(fontSize: 16);
TextStyle informationStyle = new TextStyle(fontSize: 16, fontWeight: FontWeight.bold); TextStyle informationStyle =
new TextStyle(fontSize: 16, fontWeight: FontWeight.bold);
return showDialog<Organisation>( return showDialog<Organisation>(
context: context, context: context,
barrierDismissible: true, barrierDismissible: true,
builder: (BuildContext context) { builder: (BuildContext context) {
return StatefulBuilder( return StatefulBuilder(
builder: (context, setState) { builder: (context, setState) {
@ -39,12 +38,10 @@ class FindOrganisations {
fontSize: 21, fontWeight: FontWeight.bold), fontSize: 21, fontWeight: FontWeight.bold),
), ),
), ),
Container( Container(
padding: EdgeInsets.symmetric(horizontal: 10), padding: EdgeInsets.symmetric(horizontal: 10),
child: Divider(), child: Divider(),
), ),
Container( Container(
width: MediaQuery.of(context).size.width, width: MediaQuery.of(context).size.width,
padding: EdgeInsets.symmetric(horizontal: 10), padding: EdgeInsets.symmetric(horizontal: 10),
@ -54,13 +51,15 @@ class FindOrganisations {
TableRow( TableRow(
children: [ children: [
Text("Street:", style: informationTitleStyle), Text("Street:", style: informationTitleStyle),
Text(organisation.streetName, style: informationStyle), Text(organisation.streetName,
style: informationStyle),
], ],
), ),
TableRow( TableRow(
children: [ children: [
Text("Postcode:", style: informationTitleStyle), Text("Postcode:", style: informationTitleStyle),
Text(organisation.postcode.toUpperCase(), style: informationStyle), Text(organisation.postcode.toUpperCase(),
style: informationStyle),
], ],
), ),
TableRow( TableRow(
@ -72,7 +71,6 @@ class FindOrganisations {
], ],
), ),
), ),
], ],
); );
}, },
@ -82,7 +80,6 @@ class FindOrganisations {
} }
Future<Organisation> dialog(context) { Future<Organisation> dialog(context) {
bool _searchEnabled = false; bool _searchEnabled = false;
bool _orgsFetched = false; bool _orgsFetched = false;
TextEditingController searchBarText = new TextEditingController(); TextEditingController searchBarText = new TextEditingController();
@ -95,148 +92,150 @@ class FindOrganisations {
listTitle = "Results for \'" + search + "\'"; listTitle = "Results for \'" + search + "\'";
var futureOrgs = await organisations.findOrganisations(search); var futureOrgs = await organisations.findOrganisations(search);
organisationsList = futureOrgs; organisationsList = futureOrgs;
_searchEnabled = true; _searchEnabled = true;
return futureOrgs.length; return futureOrgs.length;
} }
return showDialog<Organisation>( return showDialog<Organisation>(
context: context, context: context,
barrierDismissible: true, barrierDismissible: true,
builder: (BuildContext context) { builder: (BuildContext context) {
return StatefulBuilder( return StatefulBuilder(
builder: (context, setState) { builder: (context, setState) {
return SimpleDialog( return SimpleDialog(
children: <Widget>[ children: <Widget>[
Column( Column(
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
Row( Container(
crossAxisAlignment: CrossAxisAlignment.center, padding: EdgeInsets.fromLTRB(20, 0, 0, 0),
children: [ width: 150,
Container( height: 50,
padding: EdgeInsets.fromLTRB(20, 0, 0, 0), child: TextField(
width: 150, autofocus: true,
height: 50, controller: searchBarText,
child: TextField( decoration: InputDecoration(
autofocus: true, hintText: "Payee Name",
controller: searchBarText,
decoration: InputDecoration(
hintText: "Payee Name",
),
onChanged: (value) {
if (value.length > 0) {
_searchEnabled = true;
} else {
_searchEnabled = false;
}
setState(() => {_searchEnabled});
},
onSubmitted: _searchEnabled ? ((_) {
SystemChannels.textInput.invokeMethod('TextInput.hide');
var result = _submitSearch(searchBarText.text);
result.then((_) {
setState(() {
_orgsFetched = true;
});
});
}) : null,
),
), ),
onChanged: (value) {
Container( if (value.isNotEmpty) {
width: 80, _searchEnabled = true;
padding: EdgeInsets.fromLTRB(20, 0, 0, 0), } else {
_searchEnabled = false;
child: RaisedButton( }
onPressed: _searchEnabled ? (() { setState(() => {_searchEnabled});
SystemChannels.textInput.invokeMethod('TextInput.hide'); },
var result = _submitSearch(searchBarText.text); onSubmitted: _searchEnabled
result.then((_) { ? ((_) {
setState(() { SystemChannels.textInput
_orgsFetched = true; .invokeMethod('TextInput.hide');
var result =
_submitSearch(searchBarText.text);
result.then((_) {
setState(() {
_orgsFetched = true;
});
}); });
}); })
}) : null, : null,
),
child: Icon(Icons.search, color: Colors.white), ),
color : Colors.blue, Container(
), width: 80,
), padding: EdgeInsets.fromLTRB(20, 0, 0, 0),
], child: RaisedButton(
onPressed: _searchEnabled
? (() {
SystemChannels.textInput
.invokeMethod('TextInput.hide');
var result =
_submitSearch(searchBarText.text);
result.then((_) {
setState(() {
_orgsFetched = true;
});
});
})
: null,
child: Icon(Icons.search, color: Colors.white),
color: Colors.blue,
),
), ),
], ],
), ),
],
),
Column( Column(
children: _orgsFetched ? [ children: _orgsFetched
Container( ? [
padding: EdgeInsets.fromLTRB(20, 20, 20, 0), Container(
child: Text( padding: EdgeInsets.fromLTRB(20, 20, 20, 0),
listTitle, child: Text(
style: new TextStyle( listTitle,
fontSize: 23, fontWeight: FontWeight.bold), style: new TextStyle(
), fontSize: 23, fontWeight: FontWeight.bold),
),
Container(
padding: EdgeInsets.fromLTRB(10, 10, 10, 0),
width: MediaQuery
.of(context)
.size
.width,
height: MediaQuery
.of(context)
.size
.height * 0.67,
child: Material(
shadowColor: Colors.transparent,
color: Colors.transparent,
child: ListView.builder(
itemCount: organisationsList.length,
itemBuilder: (context, index) {
return Card(
child: ListTile(
leading: Icon(Icons.person),
title: Text(organisationsList[index].name, style: new TextStyle(fontSize: 18)),
subtitle: Text(organisationsList[index].postcode.toUpperCase()),
// trailing: Icon(Icons.arrow_forward_ios),
// onTap: _chosenOrg(organisationsList[index]),
onTap: (){
Navigator.of(context).pop(organisationsList[index]);
},
onLongPress: (){
// show more details about the organisation in a new dialog
var moreInfo = _moreInfoDialog(context, organisationsList[index]);
moreInfo.whenComplete(null);
},
),
);
},
), ),
), ),
), Container(
padding: EdgeInsets.fromLTRB(10, 10, 10, 0),
Center( width: MediaQuery.of(context).size.width,
child : Container( height: MediaQuery.of(context).size.height * 0.67,
padding: EdgeInsets.fromLTRB(0, 10, 0, 0), child: Material(
child : Text("Long press a payee for more info", style: TextStyle(fontStyle: FontStyle.italic)), shadowColor: Colors.transparent,
color: Colors.transparent,
child: ListView.builder(
itemCount: organisationsList.length,
itemBuilder: (context, index) {
return Card(
child: ListTile(
leading: Icon(Icons.person),
title: Text(organisationsList[index].name,
style: new TextStyle(fontSize: 18)),
subtitle: Text(organisationsList[index]
.postcode
.toUpperCase()),
// trailing: Icon(Icons.arrow_forward_ios),
// onTap: _chosenOrg(organisationsList[index]),
onTap: () {
Navigator.of(context)
.pop(organisationsList[index]);
},
onLongPress: () {
// show more details about the organisation in a new dialog
var moreInfo = _moreInfoDialog(
context, organisationsList[index]);
moreInfo.whenComplete(null);
},
),
);
},
),
),
), ),
), Center(
] : [ Container() ], child: Container(
), padding: EdgeInsets.fromLTRB(0, 10, 0, 0),
child: Text("Long press a payee for more info",
style:
TextStyle(fontStyle: FontStyle.italic)),
),
),
]
: [Container()],
),
// help button for if org not listed // help button for if org not listed
// cancel and ok buttons // cancel and ok buttons
],
],
// ), // ),
); );
}, },
); );
}, },
); );
} }
} }

View File

@ -6,7 +6,6 @@ class PopupListView {
return showDialog<dynamic>( return showDialog<dynamic>(
context: context, context: context,
barrierDismissible: true, barrierDismissible: true,
builder: (BuildContext context) { builder: (BuildContext context) {
return SimpleDialog( return SimpleDialog(
title: Text(title), title: Text(title),
@ -16,7 +15,8 @@ class PopupListView {
); );
} }
List<Widget> getDialogOptions(context, List<String> options /*, Function onPressed*/) { List<Widget> getDialogOptions(
context, List<String> options /*, Function onPressed*/) {
var dialogOptionsList = new List<SimpleDialogOption>(); var dialogOptionsList = new List<SimpleDialogOption>();
for (var i = 0; i < options.length; i++) { for (var i = 0; i < options.length; i++) {
@ -33,4 +33,4 @@ class PopupListView {
return dialogOptionsList; return dialogOptionsList;
} }
} }

View File

@ -5,13 +5,13 @@ part 'config.g.dart';
@JsonSerializable(createToJson: false) @JsonSerializable(createToJson: false)
class Config { class Config {
final String env;
final bool production;
final String apiKey;
Config({this.env, this.production, this.apiKey}); Config({this.env, this.production, this.apiKey});
factory Config.fromJson(Map<String, dynamic> json) => _$ConfigFromJson(json); factory Config.fromJson(Map<String, dynamic> json) => _$ConfigFromJson(json);
final String env;
final bool production;
final String apiKey;
} }
class ConfigWrapper extends StatelessWidget { class ConfigWrapper extends StatelessWidget {
@ -24,7 +24,7 @@ class ConfigWrapper extends StatelessWidget {
static Config of(BuildContext context) { static Config of(BuildContext context) {
final _InheritedConfig inheritedConfig = final _InheritedConfig inheritedConfig =
context.inheritFromWidgetOfExactType(_InheritedConfig); context.inheritFromWidgetOfExactType(_InheritedConfig);
return inheritedConfig.config; return inheritedConfig.config;
} }
@ -43,4 +43,4 @@ class _InheritedConfig extends InheritedWidget {
@override @override
bool updateShouldNotify(_InheritedConfig oldWidget) => bool updateShouldNotify(_InheritedConfig oldWidget) =>
config != oldWidget.config; config != oldWidget.config;
} }

2
lib/env/dev.dart vendored
View File

@ -3,4 +3,4 @@ import 'package:json_annotation/json_annotation.dart';
part 'dev.g.dart'; part 'dev.g.dart';
@JsonLiteral('dev.json', asConst: true) @JsonLiteral('dev.json', asConst: true)
Map<String, dynamic> get config => _$configJsonLiteral; Map<String, dynamic> get config => _$configJsonLiteral;

2
lib/env/prod.dart vendored
View File

@ -3,4 +3,4 @@ import 'package:json_annotation/json_annotation.dart';
part 'prod.g.dart'; part 'prod.g.dart';
@JsonLiteral('prod.json', asConst: true) @JsonLiteral('prod.json', asConst: true)
Map<String, dynamic> get config => _$configJsonLiteral; Map<String, dynamic> get config => _$configJsonLiteral;

View File

@ -1,13 +1,12 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:local_spend/pages/home_page.dart'; import 'package:local_spend/pages/home_page.dart';
import 'package:local_spend/pages/login_page.dart'; import 'package:local_spend/pages/login_page.dart';
import 'package:local_spend/pages/map_page.dart';
import 'package:local_spend/pages/receipt_page_2.dart'; import 'package:local_spend/pages/receipt_page_2.dart';
import 'package:local_spend/pages/spash_screen.dart'; import 'package:local_spend/pages/spash_screen.dart';
import 'package:local_spend/pages/more_page.dart'; import 'package:local_spend/pages/more_page.dart';
import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:local_spend/common/apifunctions/get_graph_data.dart';
void main() { void main() {
runApp(MyApp()); runApp(MyApp());
} }
@ -21,10 +20,7 @@ class MyApp extends StatelessWidget {
GlobalMaterialLocalizations.delegate, GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate, GlobalWidgetsLocalizations.delegate,
], ],
supportedLocales: [ supportedLocales: [Locale("en")],
Locale("en")
],
title: "Local Spend Tracker", title: "Local Spend Tracker",
theme: new ThemeData( theme: new ThemeData(
primarySwatch: Colors.blueGrey, primarySwatch: Colors.blueGrey,
@ -32,6 +28,7 @@ class MyApp extends StatelessWidget {
routes: <String, WidgetBuilder>{ routes: <String, WidgetBuilder>{
"/HomePage": (BuildContext context) => HomePage(), "/HomePage": (BuildContext context) => HomePage(),
"/LoginPage": (BuildContext context) => LoginPage(), "/LoginPage": (BuildContext context) => LoginPage(),
'/MapPage': (BuildContext context) => MapSample(),
"/ReceiptPage": (BuildContext context) => ReceiptPage2(), "/ReceiptPage": (BuildContext context) => ReceiptPage2(),
"/MorePage": (BuildContext context) => MorePage(), "/MorePage": (BuildContext context) => MorePage(),
}, },

View File

@ -1,8 +1,4 @@
class LoginModel { class LoginModel {
final String userName;
final String token;
final String userType;
LoginModel(this.userName, this.token, this.userType); LoginModel(this.userName, this.token, this.userType);
LoginModel.fromJson(Map<String, dynamic> json) LoginModel.fromJson(Map<String, dynamic> json)
@ -10,6 +6,10 @@ class LoginModel {
userType = json['user_type'], userType = json['user_type'],
token = json['session_key']; token = json['session_key'];
final String userName;
final String token;
final String userType;
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
'name': userName, 'name': userName,
'user_type': userType, 'user_type': userType,

View File

@ -1,31 +0,0 @@
import 'package:flutter/material.dart';
import 'package:charts_flutter/flutter.dart' as charts;
import 'package:local_spend/common/apifunctions/get_graph_data.dart';
class PresetChart extends StatefulWidget {
PresetChart({Key key}) : super(key: key);
@override
_PresetChartState createState() {
return _PresetChartState();
}
}
class _PresetChartState extends State<PresetChart> {
@override
void initState() {
super.initState();
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
return new Container(
);
}
}

View File

@ -56,10 +56,9 @@ class _CustomerGraphsState extends State<CustomerGraphs> {
return ListView( return ListView(
children: <Widget>[ children: <Widget>[
Container( Container(
padding: EdgeInsets.fromLTRB(0.0,17,0.0,0.0), padding: EdgeInsets.fromLTRB(0.0, 17, 0.0, 0.0),
child : Text( child: Text(
"Last Week's Total Spend", "Last Week's Total Spend",
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(
@ -69,19 +68,21 @@ class _CustomerGraphsState extends State<CustomerGraphs> {
), ),
), ),
), ),
Tooltip( Tooltip(
message: "Graph of total spend last week", message: "Graph of total spend last week",
child : Container( child: Container(
padding: EdgeInsets.symmetric(horizontal: 10), padding: EdgeInsets.symmetric(horizontal: 10),
height: 200, height: 200,
child: totalLastWeekGraph.graph != null ? new charts.TimeSeriesChart(totalLastWeekGraph.graph) : Center(child: Text("Loading graph...")), //List<Series<dynamic, DateTime>> child: totalLastWeekGraph.graph != null
? new charts.TimeSeriesChart(totalLastWeekGraph.graph)
: Center(
child: Text(
"Loading graph...")), //List<Series<dynamic, DateTime>>
), ),
), ),
Container( Container(
padding: EdgeInsets.fromLTRB(0.0,17,0.0,0.0), padding: EdgeInsets.fromLTRB(0.0, 17, 0.0, 0.0),
child : Text( child: Text(
"Last Week's Average Spend", "Last Week's Average Spend",
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(
@ -91,19 +92,21 @@ class _CustomerGraphsState extends State<CustomerGraphs> {
), ),
), ),
), ),
Tooltip( Tooltip(
message: "Graph of average spend last week", message: "Graph of average spend last week",
child : Container( child: Container(
padding: EdgeInsets.symmetric(horizontal: 10), padding: EdgeInsets.symmetric(horizontal: 10),
height: 200, height: 200,
child: avgSpendLastWeekGraph.graph != null ? new charts.TimeSeriesChart(avgSpendLastWeekGraph.graph) : Center(child: Text("Loading graph...")), //List<Series<dynamic, DateTime>> child: avgSpendLastWeekGraph.graph != null
? new charts.TimeSeriesChart(avgSpendLastWeekGraph.graph)
: Center(
child: Text(
"Loading graph...")), //List<Series<dynamic, DateTime>>
), ),
), ),
Container( Container(
padding: EdgeInsets.fromLTRB(0.0,17,0.0,0.0), padding: EdgeInsets.fromLTRB(0.0, 17, 0.0, 0.0),
child : Text( child: Text(
"Last Month's Total Spend", "Last Month's Total Spend",
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(
@ -113,19 +116,21 @@ class _CustomerGraphsState extends State<CustomerGraphs> {
), ),
), ),
), ),
Tooltip( Tooltip(
message: "Graph of total spend last month", message: "Graph of total spend last month",
child : Container( child: Container(
padding: EdgeInsets.symmetric(horizontal: 10), padding: EdgeInsets.symmetric(horizontal: 10),
height: 200, height: 200,
child: totalLastMonthGraph.graph != null ? new charts.TimeSeriesChart(totalLastMonthGraph.graph) : Center(child: Text("Loading graph...")), //List<Series<dynamic, DateTime>> child: totalLastMonthGraph.graph != null
? new charts.TimeSeriesChart(totalLastMonthGraph.graph)
: Center(
child: Text(
"Loading graph...")), //List<Series<dynamic, DateTime>>
), ),
), ),
Container( Container(
padding: EdgeInsets.fromLTRB(0.0,17,0.0,0.0), padding: EdgeInsets.fromLTRB(0.0, 17, 0.0, 0.0),
child : Text( child: Text(
"Last Month's Average Spend", "Last Month's Average Spend",
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(
@ -135,17 +140,19 @@ class _CustomerGraphsState extends State<CustomerGraphs> {
), ),
), ),
), ),
Tooltip( Tooltip(
message: "Graph of average spend last month", message: "Graph of average spend last month",
child : Container( child: Container(
padding: EdgeInsets.symmetric(horizontal: 10), padding: EdgeInsets.symmetric(horizontal: 10),
height: 200, height: 200,
child: avgSpendLastMonth.graph != null ? new charts.TimeSeriesChart(avgSpendLastMonth.graph) : Center(child: Text("Loading graph...")), //List<Series<dynamic, DateTime>> child: avgSpendLastMonth.graph != null
? new charts.TimeSeriesChart(avgSpendLastMonth.graph)
: Center(
child: Text(
"Loading graph...")), //List<Series<dynamic, DateTime>>
), ),
), ),
], ],
); );
} }
} }

View File

@ -5,7 +5,7 @@ import 'package:local_spend/pages/stats_page.dart';
import 'package:local_spend/pages/map_page.dart'; import 'package:local_spend/pages/map_page.dart';
class HomePage extends StatelessWidget { class HomePage extends StatelessWidget {
static String _title = 'Text here'; static String _title = 'SpendTracker';
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -27,11 +27,11 @@ class _HomePageState extends State<HomePageWidget> {
int _selectedIndex = 0; int _selectedIndex = 0;
static const TextStyle optionStyle = static const TextStyle optionStyle =
TextStyle(fontSize: 30, fontWeight: FontWeight.bold); TextStyle(fontSize: 30, fontWeight: FontWeight.bold);
static List<Widget> _widgetOptions = <Widget>[ static List<Widget> _widgetOptions = <Widget>[
ReceiptPage2(), ReceiptPage2(),
StatsPage(), StatsPage(),
MapPage(), MapSample(),
MorePage() MorePage()
]; ];
@ -43,7 +43,6 @@ class _HomePageState extends State<HomePageWidget> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var _itemText = TextStyle(color: Colors.grey[400]);
return Scaffold( return Scaffold(
body: Center( body: Center(
@ -75,4 +74,4 @@ class _HomePageState extends State<HomePageWidget> {
), ),
); );
} }
} }

View File

@ -9,7 +9,7 @@ import 'package:url_launcher/url_launcher.dart';
import 'package:local_spend/common/widgets/labeled_checkbox.dart'; import 'package:local_spend/common/widgets/labeled_checkbox.dart';
import 'package:local_spend/common/widgets/animatedGradientButton.dart'; import 'package:local_spend/common/widgets/animatedGradientButton.dart';
const URL = "https://flutter.io/"; const url = "https://flutter.io/";
class LoginPage extends StatefulWidget { class LoginPage extends StatefulWidget {
@override @override
@ -20,12 +20,15 @@ class LoginPage extends StatefulWidget {
class LoginPageState extends State<LoginPage> { class LoginPageState extends State<LoginPage> {
bool _isLoggingIn = false; bool _isLoggingIn = false;
final TextEditingController _emailController = TextEditingController(/*text: 'test@example.com'*/); // remove final TextEditingController _emailController =
final TextEditingController _passwordController = TextEditingController(/*text: 'abc123'*/); // remove TextEditingController(/*text: 'test@example.com'*/); // remove
bool _saveLoginDetails = true; // I am extremely sorry for the placement of this variable final TextEditingController _passwordController =
// it will be fixed soon I promise TextEditingController(/*text: 'abc123'*/); // remove
bool _saveLoginDetails =
true; // I am extremely sorry for the placement of this variable
// it will be fixed soon I promise
FocusNode focusNode; // added so focus can move automatically FocusNode focusNode; // added so focus can move automatically
Future launchURL(String url) async { Future launchURL(String url) async {
if (await canLaunch(url)) { if (await canLaunch(url)) {
@ -34,7 +37,7 @@ class LoginPageState extends State<LoginPage> {
showDialogSingleButton( showDialogSingleButton(
context, context,
"Unable to reach your website.", "Unable to reach your website.",
"Currently unable to reach the website $URL. Please try again at a later time.", "Currently unable to reach the website $url. Please try again at a later time.",
"OK"); "OK");
} }
} }
@ -55,7 +58,7 @@ class LoginPageState extends State<LoginPage> {
super.dispose(); super.dispose();
} }
_fillLoginDetails() async { void _fillLoginDetails() async {
SharedPreferences preferences = await SharedPreferences.getInstance(); SharedPreferences preferences = await SharedPreferences.getInstance();
var username = await preferences.get('username'); var username = await preferences.get('username');
@ -65,14 +68,14 @@ class LoginPageState extends State<LoginPage> {
_passwordController.text = await password; _passwordController.text = await password;
} }
_saveCurrentRoute(String lastRoute) async { void _saveCurrentRoute(String lastRoute) async {
SharedPreferences preferences = await SharedPreferences.getInstance(); SharedPreferences preferences = await SharedPreferences.getInstance();
await preferences.setString('LastPageRoute', lastRoute); await preferences.setString('LastPageRoute', lastRoute);
} }
login(String username, String password) async { void login(String username, String password) async {
_isLoggingIn = true; _isLoggingIn = true;
SystemChannels.textInput.invokeMethod('TextInput.hide'); await SystemChannels.textInput.invokeMethod('TextInput.hide');
SharedPreferences preferences = await SharedPreferences.getInstance(); SharedPreferences preferences = await SharedPreferences.getInstance();
if (_saveLoginDetails) { if (_saveLoginDetails) {
@ -85,7 +88,7 @@ class LoginPageState extends State<LoginPage> {
print("details cleared"); print("details cleared");
} }
requestLoginAPI(context, username, password).then((value) { await requestLoginAPI(context, username, password).then((value) {
_isLoggingIn = false; _isLoggingIn = false;
}); });
} }
@ -100,24 +103,25 @@ class LoginPageState extends State<LoginPage> {
} else { } else {
Navigator.of(context).pushReplacementNamed('/HomePage'); Navigator.of(context).pushReplacementNamed('/HomePage');
} }
return null;
}, },
child: PlatformScaffold( child: PlatformScaffold(
body: Stack( body: Stack(
children: [ children: [
AnimatedBackground([Colors.lightBlue[50], Colors.lightBlue[50]], Colors.white, Alignment.topRight, Alignment.bottomLeft, 3), AnimatedBackground([Colors.lightBlue[50], Colors.lightBlue[50]],
Colors.white, Alignment.topRight, Alignment.bottomLeft, 3),
Container( Container(
margin: EdgeInsets.fromLTRB(60,30,60,0), margin: EdgeInsets.fromLTRB(60, 30, 60, 0),
child: Column( child: Column(
children: <Widget>[ children: <Widget>[
Expanded( Expanded(
child: AnimatedContainer( child: AnimatedContainer(
duration: Duration(seconds: 2), duration: Duration(seconds: 2),
margin: EdgeInsets.fromLTRB(15,0,15,0), margin: EdgeInsets.fromLTRB(15, 0, 15, 0),
decoration: BoxDecoration( decoration: BoxDecoration(
image: DecorationImage( image: DecorationImage(
image: AssetImage('assets/images/launch_image.png') image:
), AssetImage('assets/images/launch_image.png')),
), ),
), ),
), ),
@ -159,49 +163,57 @@ class LoginPageState extends State<LoginPage> {
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
onSubmitted: (_) { onSubmitted: (_) {
login( _emailController.text, login(_emailController.text, _passwordController.text);
_passwordController.text);
}, },
), ),
), ),
Container(
Container( margin: EdgeInsets.fromLTRB(0.0, 40.0, 0.0, 30.0),
margin: EdgeInsets.fromLTRB(0.0, 40.0, 0.0, 30.0), width: 100,
width: 100, height: 50,
height: 50, child: Opacity(
child: Opacity( opacity: _isLoggingIn ? 0.5 : 1,
opacity: _isLoggingIn ? 0.5 : 1, child: ClipRRect(
child: ClipRRect( borderRadius: BorderRadius.circular(2),
borderRadius: BorderRadius.circular(2), child: Stack(
child : Stack( children: [
children : [ AnimatedBackground(
AnimatedBackground([Colors.blue, Colors.lightBlue[300]], Colors.lightBlue, Alignment.bottomRight, Alignment.topLeft, 3), [Colors.blue, Colors.lightBlue[300]],
Material( Colors.lightBlue,
type: MaterialType.transparency, Alignment.bottomRight,
child : InkWell( Alignment.topLeft,
onTap: _isLoggingIn ? null : () => login( _emailController.text, _passwordController.text), 3),
Material(
child: new Center( type: MaterialType.transparency,
child: new Text( child: InkWell(
'GO', style: new TextStyle(fontSize: 18, color: Colors.white),), onTap: _isLoggingIn
? null
: () => login(_emailController.text,
_passwordController.text),
child: new Center(
child: new Text(
'GO',
style: new TextStyle(
fontSize: 18, color: Colors.white),
),
),
), ),
), ),
), ],
], ),
), ),
), ),
), ),
),
Padding( Padding(
padding: EdgeInsets.fromLTRB(0, 10, 0, 50), padding: EdgeInsets.fromLTRB(0, 10, 0, 50),
child: LabeledCheckbox( child: LabeledCheckbox(
label : "SAVE LOGIN", label: "SAVE LOGIN",
textStyle: TextStyle(fontSize: 18, color: Colors.black54, fontWeight: FontWeight.bold), textStyle: TextStyle(
padding: const EdgeInsets.fromLTRB(0,0,0,0), fontSize: 18,
value : _saveLoginDetails, color: Colors.black54,
fontWeight: FontWeight.bold),
padding: const EdgeInsets.fromLTRB(0, 0, 0, 0),
value: _saveLoginDetails,
onChanged: (bool newValue) { onChanged: (bool newValue) {
setState(() { setState(() {
_saveLoginDetails = newValue; _saveLoginDetails = newValue;

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_maps/flutter_maps.dart'; import 'dart:async';
import 'package:local_spend/common/felixApiCreds.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:local_spend/common/platform/platform_scaffold.dart';
class MapPage extends StatefulWidget { class MapPage extends StatefulWidget {
MapPage({Key key}) : super(key: key); MapPage({Key key}) : super(key: key);
@ -13,20 +14,48 @@ class MapPage extends StatefulWidget {
class _MapPageState extends State<MapPage> { class _MapPageState extends State<MapPage> {
@override @override
void initState() { Widget build(BuildContext context) {
super.initState(); return PlatformScaffold(
appBar: AppBar(
backgroundColor: Colors.blue[400],
title: Text(
"Submit Receipt",
style: TextStyle(
fontSize: 20,
color: Colors.white,
),
),
centerTitle: true,
iconTheme: IconThemeData(color: Colors.black),
),
body: null,
);
} }
}
class MapSample extends StatefulWidget {
@override @override
void dispose() { State<MapSample> createState() => MapSampleState();
super.dispose(); }
}
class MapSampleState extends State<MapSample> {
Completer<GoogleMapController> _controller = Completer();
static final CameraPosition _kGooglePlex = CameraPosition(
target: LatLng(37.42796133580664, -122.085749655962),
zoom: 14.4746,
);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var fac = new FelixApiCreds(); return new Scaffold(
body: GoogleMap(
// TODO: implement build mapType: MapType.hybrid,
return Text(fac.mapsApiKey); initialCameraPosition: _kGooglePlex,
onMapCreated: (GoogleMapController controller) {
_controller.complete(controller);
},
),
);
} }
} }

View File

@ -1,4 +1,3 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:local_spend/common/platform/platform_scaffold.dart'; import 'package:local_spend/common/platform/platform_scaffold.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
@ -7,7 +6,7 @@ import 'package:url_launcher/url_launcher.dart';
import 'package:local_spend/common/functions/customAbout.dart' as custom; import 'package:local_spend/common/functions/customAbout.dart' as custom;
import 'package:local_spend/common/functions/showDialogTwoButtons.dart'; import 'package:local_spend/common/functions/showDialogTwoButtons.dart';
const URL = "https://flutter.io/"; const url = "https://flutter.io/";
const demonstration = false; const demonstration = false;
class MorePage extends StatefulWidget { class MorePage extends StatefulWidget {
@ -18,7 +17,7 @@ class MorePage extends StatefulWidget {
} }
class MorePageState extends State<MorePage> { class MorePageState extends State<MorePage> {
FocusNode focusNode; // added so focus can move automatically FocusNode focusNode; // added so focus can move automatically
DateTime date; DateTime date;
@ -37,7 +36,7 @@ class MorePageState extends State<MorePage> {
focusNode.dispose(); //disposes focus node when form disposed focusNode.dispose(); //disposes focus node when form disposed
} }
_saveCurrentRoute(String lastRoute) async { void _saveCurrentRoute(String lastRoute) async {
SharedPreferences preferences = await SharedPreferences.getInstance(); SharedPreferences preferences = await SharedPreferences.getInstance();
await preferences.setString('LastPageRoute', lastRoute); await preferences.setString('LastPageRoute', lastRoute);
} }
@ -52,9 +51,9 @@ class MorePageState extends State<MorePage> {
} else { } else {
Navigator.of(context).pushReplacementNamed('/LoginPage'); Navigator.of(context).pushReplacementNamed('/LoginPage');
} }
return null;
}, },
child: PlatformScaffold( child: PlatformScaffold(
appBar: AppBar( appBar: AppBar(
backgroundColor: Colors.blue[400], backgroundColor: Colors.blue[400],
title: Text( title: Text(
@ -68,14 +67,12 @@ class MorePageState extends State<MorePage> {
centerTitle: true, centerTitle: true,
iconTheme: IconThemeData(color: Colors.black), iconTheme: IconThemeData(color: Colors.black),
), ),
body: Container( body: Container(
child: ListView( child: ListView(
children: <Widget>[ children: <Widget>[
Container( Container(
padding: EdgeInsets.fromLTRB(30.0,25,30.0,0.0), padding: EdgeInsets.fromLTRB(30.0, 25, 30.0, 0.0),
child : Text( child: Text(
"Local Spend Tracker", "Local Spend Tracker",
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(
@ -92,53 +89,49 @@ class MorePageState extends State<MorePage> {
height: 65.0, height: 65.0,
child: RaisedButton( child: RaisedButton(
onPressed: () { onPressed: () {
custom.showAboutDialog( custom.showAboutDialog(
context: context, context: context,
applicationIcon: new Icon(Icons.receipt), applicationIcon: new Icon(Icons.receipt),
applicationName: "Local Spend Tracker", applicationName: "Local Spend Tracker",
children: <Widget> children: <Widget>[
[ Text(
Text("Pear Trading is a commerce company designed to register and monitor money circulating in the local economy.\n"), "Pear Trading is a commerce company designed to register and monitor money circulating in the local economy.\n"),
Container( Container(
padding: EdgeInsets.symmetric(horizontal: 10), padding: EdgeInsets.symmetric(horizontal: 10),
height: 35, height: 35,
child: RaisedButton( child: RaisedButton(
onPressed: () => {}, onPressed: () => {},
child: Text("Contact us", child: Text("Contact us",
style: style: TextStyle(
TextStyle(color: Colors.white, fontSize: 18.0)), color: Colors.white, fontSize: 18.0)),
color: Colors.green, color: Colors.green,
), ),
), ),
Container( Container(
height: 35, height: 35,
margin: EdgeInsets.fromLTRB(10, 20, 10, 0), margin: EdgeInsets.fromLTRB(10, 20, 10, 0),
child: RaisedButton( child: RaisedButton(
child: Text child: Text(
('Pear Trading', 'Pear Trading',
style: TextStyle( style: TextStyle(
color: Colors.white, color: Colors.white, fontSize: 18.0),
fontSize: 18.0
), ),
), color: Colors.lightGreen,
color: Colors.lightGreen, onPressed: () =>
onPressed: () => launch('http://www.peartrade.org') launch('http://www.peartrade.org')),
),
), ),
Container( Container(
height: 35, height: 35,
margin: EdgeInsets.fromLTRB(10, 20, 10, 0), margin: EdgeInsets.fromLTRB(10, 20, 10, 0),
child: Material( child: Material(
child: OutlineButton( child: OutlineButton(
child: Text child: Text(
('Shadowcat Systems', 'Shadowcat Systems',
style: TextStyle( style: TextStyle(
color: Colors.black, color: Colors.black, fontSize: 18.0
fontSize: 18.0 /// I don't know what to do with this button
), /// I don't know what to do with this button
),
), ),
onPressed: () => launch('https://shadow.cat/'), onPressed: () => launch('https://shadow.cat/'),
), ),
@ -146,14 +139,11 @@ class MorePageState extends State<MorePage> {
shadowColor: Colors.transparent, shadowColor: Colors.transparent,
), ),
), ),
], ],
); );
}, },
child: Text("ABOUT", child: Text("ABOUT",
style: style: TextStyle(color: Colors.white, fontSize: 22.0)),
TextStyle(color: Colors.white, fontSize: 22.0)),
color: Colors.blue, color: Colors.blue,
), ),
), ),
@ -166,17 +156,15 @@ class MorePageState extends State<MorePage> {
child: RaisedButton( child: RaisedButton(
onPressed: () { onPressed: () {
showDialogTwoButtons( showDialogTwoButtons(
context, context,
"Logout", "Logout",
"Are you sure you want to log out?", "Are you sure you want to log out?",
"Cancel", "Cancel",
"Logout", "Logout",
logout logout);
);
}, },
child: Text("LOGOUT", child: Text("LOGOUT",
style: style: TextStyle(color: Colors.white, fontSize: 22.0)),
TextStyle(color: Colors.white, fontSize: 22.0)),
color: Colors.red, color: Colors.red,
), ),
), ),
@ -197,7 +185,6 @@ class MorePageState extends State<MorePage> {
// ), // ),
// ), // ),
// ), // ),
], ],
), ),
), ),

View File

@ -1,10 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:local_spend/common/platform/platform_scaffold.dart'; import 'package:local_spend/common/platform/platform_scaffold.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:local_spend/common/apifunctions/get_graph_data.dart';
import 'package:charts_flutter/flutter.dart' as charts;
const URL = "https://flutter.io/"; const url = "https://flutter.io/";
const demonstration = false; const demonstration = false;
class NewStatsPage extends StatefulWidget { class NewStatsPage extends StatefulWidget {
@ -15,7 +13,6 @@ class NewStatsPage extends StatefulWidget {
} }
class NewStatsPageState extends State<NewStatsPage> { class NewStatsPageState extends State<NewStatsPage> {
/// Graph types: /// Graph types:
/// - total_last_week /// - total_last_week
/// - avg_spend_last_week /// - avg_spend_last_week
@ -33,14 +30,13 @@ class NewStatsPageState extends State<NewStatsPage> {
super.dispose(); super.dispose();
} }
_saveCurrentRoute(String lastRoute) async { void _saveCurrentRoute(String lastRoute) async {
SharedPreferences preferences = await SharedPreferences.getInstance(); SharedPreferences preferences = await SharedPreferences.getInstance();
await preferences.setString('LastPageRoute', lastRoute); await preferences.setString('LastPageRoute', lastRoute);
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return PlatformScaffold( return PlatformScaffold(
appBar: AppBar( appBar: AppBar(
backgroundColor: Colors.blue[400], backgroundColor: Colors.blue[400],
@ -55,11 +51,7 @@ class NewStatsPageState extends State<NewStatsPage> {
centerTitle: true, centerTitle: true,
iconTheme: IconThemeData(color: Colors.black), iconTheme: IconThemeData(color: Colors.black),
), ),
body: Container(),
body : Container(
),
); );
} }
} }

View File

@ -1,6 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:local_spend/common/apifunctions/get_graph_data.dart'; import 'package:local_spend/common/apifunctions/get_graph_data.dart';
import 'package:charts_flutter/flutter.dart' as charts; //import 'package:charts_flutter/flutter.dart' as charts;
class OrgGraphs extends StatefulWidget { class OrgGraphs extends StatefulWidget {
OrgGraphs({Key key}) : super(key: key); OrgGraphs({Key key}) : super(key: key);
@ -27,9 +27,7 @@ class _OrgGraphsState extends State<OrgGraphs> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ListView( return ListView(
children: <Widget>[ children: <Widget>[],
],
); );
} }
} }

View File

@ -1,7 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:local_spend/common/platform/platform_scaffold.dart'; import 'package:local_spend/common/platform/platform_scaffold.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'dart:core'; import 'dart:async';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:local_spend/common/widgets/animatedGradientButton.dart'; import 'package:local_spend/common/widgets/animatedGradientButton.dart';
import 'package:local_spend/common/apifunctions/find_organisations.dart'; import 'package:local_spend/common/apifunctions/find_organisations.dart';
@ -10,13 +10,6 @@ import 'package:local_spend/common/apifunctions/submit_receipt_api.dart';
import 'package:local_spend/common/apifunctions/categories.dart'; import 'package:local_spend/common/apifunctions/categories.dart';
class Transaction { class Transaction {
DateTime date;
TextEditingController amount;
Organisation organisation;
String recurring;
bool isEssential;
String category;
Transaction( Transaction(
this.date, this.date,
this.amount, this.amount,
@ -25,6 +18,13 @@ class Transaction {
this.isEssential, this.isEssential,
this.category, this.category,
); );
DateTime date;
TextEditingController amount;
Organisation organisation;
String recurring;
bool isEssential;
String category;
} }
class ReceiptPage2 extends StatefulWidget { class ReceiptPage2 extends StatefulWidget {
@ -44,7 +44,7 @@ class ReceiptPage2State extends State<ReceiptPage2> {
"Uncategorised", "Uncategorised",
); );
_invalidDialog(context) { AlertDialog _invalidDialog(context) {
return AlertDialog( return AlertDialog(
title: new Text("Invalid data"), title: new Text("Invalid data"),
content: new Text( content: new Text(
@ -64,9 +64,7 @@ class ReceiptPage2State extends State<ReceiptPage2> {
return await getCategories(); return await getCategories();
} }
_submitReceipt(Transaction transaction) { void _submitReceipt(Transaction transaction) {
DateTime dt = new DateTime.now();
Receipt receipt = new Receipt(); Receipt receipt = new Receipt();
receipt.organisationName = transaction.organisation.name; receipt.organisationName = transaction.organisation.name;
receipt.street = transaction.organisation.streetName; receipt.street = transaction.organisation.streetName;
@ -86,7 +84,9 @@ class ReceiptPage2State extends State<ReceiptPage2> {
} }
receipt.amount = transaction.amount.text.toString(); receipt.amount = transaction.amount.text.toString();
receipt.time = DateFormat("yyyy-MM-dd'T'hh:mm':00.000+01:00'").format(transaction.date).toString(); receipt.time = DateFormat("yyyy-MM-dd'T'hh:mm':00.000+01:00'")
.format(transaction.date)
.toString();
receipt.essential = transaction.isEssential.toString(); receipt.essential = transaction.isEssential.toString();
submitReceiptAPI(context, receipt); submitReceiptAPI(context, receipt);
@ -97,10 +97,11 @@ class ReceiptPage2State extends State<ReceiptPage2> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var _widgetHeight = MediaQuery.of(context).size.height * 0.06 < 40.0
? 40.0
: MediaQuery.of(context).size.height * 0.06;
var _widgetHeight = MediaQuery.of(context).size.height * 0.06 < 40.0 ? 40.0 : MediaQuery.of(context).size.height * 0.06; if (_categories.isNotEmpty) {
if (_categories.length == 0) {
Future<List<String>> _futureCats = getCats(); Future<List<String>> _futureCats = getCats();
_categories.add("Fetching categories..."); _categories.add("Fetching categories...");
_futureCats.then((value) { _futureCats.then((value) {
@ -108,15 +109,15 @@ class ReceiptPage2State extends State<ReceiptPage2> {
_categories = value; _categories = value;
}); });
} }
_sampleRecurringOptions[0] = "None"; _sampleRecurringOptions[0] = "None";
_sampleRecurringOptions[1] = "Daily"; _sampleRecurringOptions[1] = "Daily";
_sampleRecurringOptions[2] = "Weekly"; _sampleRecurringOptions[2] = "Weekly";
_sampleRecurringOptions[3] = "Fortnightly"; _sampleRecurringOptions[3] = "Fortnightly";
_sampleRecurringOptions[4] = "Monthly"; _sampleRecurringOptions[4] = "Monthly";
_sampleRecurringOptions[5] = "Quarterly"; _sampleRecurringOptions[5] = "Quarterly";
_sampleRecurringOptions[6] = "Yearly"; // these will be difficult to fetch from server as they are coded into the site's rather than fetched _sampleRecurringOptions[6] = "Yearly";
// these will be difficult to fetch from server as they are coded into the site's HTML rather than fetched
return PlatformScaffold( return PlatformScaffold(
appBar: AppBar( appBar: AppBar(
@ -131,15 +132,19 @@ class ReceiptPage2State extends State<ReceiptPage2> {
centerTitle: true, centerTitle: true,
iconTheme: IconThemeData(color: Colors.black), iconTheme: IconThemeData(color: Colors.black),
), ),
body: ListView( body: ListView(
children: <Widget>[ children: <Widget>[
// each CHILD has its own horizontal padding because if the listView has padding, Android's end-of-scroll animation // each CHILD has its own horizontal padding because if the listView
// has padding, Android's end-of-scroll animation
// doesn't fit the screen properly and looks weird // doesn't fit the screen properly and looks weird
Container( Container(
padding: EdgeInsets.fromLTRB(MediaQuery.of(context).size.width * 0.025,MediaQuery.of(context).size.height * 0.025,0,0.0), padding: EdgeInsets.fromLTRB(
child : Text( MediaQuery.of(context).size.width * 0.025,
MediaQuery.of(context).size.height * 0.025,
0,
0.0),
child: Text(
"Receipt Details", "Receipt Details",
style: TextStyle( style: TextStyle(
fontSize: 26, fontSize: 26,
@ -150,13 +155,17 @@ class ReceiptPage2State extends State<ReceiptPage2> {
), // "Receipt Details" title ), // "Receipt Details" title
Container( Container(
padding: EdgeInsets.fromLTRB(MediaQuery.of(context).size.width * 0.05,15,MediaQuery.of(context).size.width * 0.05,0.0), padding: EdgeInsets.fromLTRB(
MediaQuery.of(context).size.width * 0.05,
15,
MediaQuery.of(context).size.width * 0.05,
0.0),
child: Tooltip( child: Tooltip(
message: "Date and time of transaction", message: "Date and time of transaction",
child: Row( child: Row(
children: <Widget> [ children: <Widget>[
Container( Container(
child : Text( child: Text(
"Date/Time", "Date/Time",
style: TextStyle( style: TextStyle(
fontSize: 22, fontSize: 22,
@ -166,7 +175,6 @@ class ReceiptPage2State extends State<ReceiptPage2> {
), ),
width: MediaQuery.of(context).size.width * 0.3, width: MediaQuery.of(context).size.width * 0.3,
), ),
Container( Container(
padding: const EdgeInsets.fromLTRB(0, 0, 0, 0), padding: const EdgeInsets.fromLTRB(0, 0, 0, 0),
height: _widgetHeight, height: _widgetHeight,
@ -177,17 +185,23 @@ class ReceiptPage2State extends State<ReceiptPage2> {
context: context, context: context,
builder: (BuildContext builder) { builder: (BuildContext builder) {
return Container( return Container(
height: MediaQuery.of(context).copyWith().size.height / 3, height: MediaQuery.of(context)
.copyWith()
.size
.height /
3,
child: CupertinoDatePicker( child: CupertinoDatePicker(
initialDateTime: transaction.date.isAfter(DateTime.now()) initialDateTime:
? DateTime.now() transaction.date.isAfter(DateTime.now())
: transaction.date, ? DateTime.now()
: transaction.date,
onDateTimeChanged: (DateTime newDate) { onDateTimeChanged: (DateTime newDate) {
setState(() => { setState(() => {
newDate.isAfter(DateTime.now()) newDate.isAfter(DateTime.now())
? transaction.date = DateTime.now() ? transaction.date =
: transaction.date = newDate, DateTime.now()
}); : transaction.date = newDate,
});
}, },
use24hFormat: true, use24hFormat: true,
maximumDate: DateTime.now(), maximumDate: DateTime.now(),
@ -199,12 +213,20 @@ class ReceiptPage2State extends State<ReceiptPage2> {
transaction.date == null transaction.date == null
? 'None set.' ? 'None set.'
: transaction.date.year != DateTime.now().year : transaction.date.year != DateTime.now().year
? '${new DateFormat.MMMd().format(transaction.date)}' + " " + transaction.date.year.toString() + " at " + '${new DateFormat.Hm().format(transaction.date)}' ? '${new DateFormat.MMMd().format(transaction.date)}' +
: transaction.date.day == DateTime.now().day && transaction.date.month == DateTime.now().month " " +
? "Today at " + '${new DateFormat.Hm().format(transaction.date)}' transaction.date.year.toString() +
: '${new DateFormat.MMMd().format(transaction.date)}' + " at " + '${new DateFormat.Hm().format(transaction.date)}', " at " +
style: '${new DateFormat.Hm().format(transaction.date)}'
TextStyle(color: Colors.white, fontSize: 22.0), : transaction.date.day == DateTime.now().day &&
transaction.date.month ==
DateTime.now().month
? "Today at " +
'${new DateFormat.Hm().format(transaction.date)}'
: '${new DateFormat.MMMd().format(transaction.date)}' +
" at " +
'${new DateFormat.Hm().format(transaction.date)}',
style: TextStyle(color: Colors.white, fontSize: 22.0),
), ),
color: Colors.blue, color: Colors.blue,
), ),
@ -215,13 +237,17 @@ class ReceiptPage2State extends State<ReceiptPage2> {
), // Date/Time picker ), // Date/Time picker
Container( Container(
padding: EdgeInsets.fromLTRB(MediaQuery.of(context).size.width * 0.05,15,MediaQuery.of(context).size.width * 0.05,0.0), padding: EdgeInsets.fromLTRB(
MediaQuery.of(context).size.width * 0.05,
15,
MediaQuery.of(context).size.width * 0.05,
0.0),
child: Tooltip( child: Tooltip(
message: "Transaction payee", message: "Transaction payee",
child: Row( child: Row(
children: <Widget> [ children: <Widget>[
Container( Container(
child : Text( child: Text(
"Payee", "Payee",
style: TextStyle( style: TextStyle(
fontSize: 22, fontSize: 22,
@ -231,7 +257,6 @@ class ReceiptPage2State extends State<ReceiptPage2> {
), ),
width: MediaQuery.of(context).size.width * 0.3, width: MediaQuery.of(context).size.width * 0.3,
), ),
Container( Container(
padding: const EdgeInsets.fromLTRB(0, 0, 0, 0), padding: const EdgeInsets.fromLTRB(0, 0, 0, 0),
height: _widgetHeight, height: _widgetHeight,
@ -244,9 +269,9 @@ class ReceiptPage2State extends State<ReceiptPage2> {
try { try {
organisation.name.length; organisation.name.length;
transaction.organisation = organisation; transaction.organisation = organisation;
// debugPrint(organisation.name); // debugPrint(organisation.name);
setState(() {}); setState(() {});
} catch(_) { } catch (_) {
debugPrint("No organisation chosen."); debugPrint("No organisation chosen.");
} }
}); });
@ -255,10 +280,11 @@ class ReceiptPage2State extends State<ReceiptPage2> {
transaction.organisation.name == null transaction.organisation.name == null
? 'Find' ? 'Find'
: transaction.organisation.name.length > 14 : transaction.organisation.name.length > 14
? transaction.organisation.name.substring(0,12) + "..." ? transaction.organisation.name
: transaction.organisation.name, .substring(0, 12) +
style: "..."
TextStyle(color: Colors.white, fontSize: 22.0), : transaction.organisation.name,
style: TextStyle(color: Colors.white, fontSize: 22.0),
), ),
color: Colors.blue, color: Colors.blue,
), ),
@ -269,13 +295,17 @@ class ReceiptPage2State extends State<ReceiptPage2> {
), // Organisation picker ), // Organisation picker
Container( Container(
padding: EdgeInsets.fromLTRB(MediaQuery.of(context).size.width * 0.05,15,MediaQuery.of(context).size.width * 0.05,0.0), padding: EdgeInsets.fromLTRB(
MediaQuery.of(context).size.width * 0.05,
15,
MediaQuery.of(context).size.width * 0.05,
0.0),
child: Tooltip( child: Tooltip(
message: "Repeating?", message: "Repeating?",
child: Row( child: Row(
children: <Widget> [ children: <Widget>[
Container( Container(
child : Text( child: Text(
"Recurring", "Recurring",
style: TextStyle( style: TextStyle(
fontSize: 22, fontSize: 22,
@ -285,7 +315,6 @@ class ReceiptPage2State extends State<ReceiptPage2> {
), ),
width: MediaQuery.of(context).size.width * 0.3, width: MediaQuery.of(context).size.width * 0.3,
), ),
Container( Container(
padding: const EdgeInsets.fromLTRB(0, 0, 0, 0), padding: const EdgeInsets.fromLTRB(0, 0, 0, 0),
height: _widgetHeight, height: _widgetHeight,
@ -293,31 +322,37 @@ class ReceiptPage2State extends State<ReceiptPage2> {
child: RaisedButton( child: RaisedButton(
onPressed: () { onPressed: () {
showModalBottomSheet( showModalBottomSheet(
context: context, context: context,
builder: (BuildContext builder) { builder: (BuildContext builder) {
return Container( return Container(
height: MediaQuery.of(context).copyWith().size.height / 3, height: MediaQuery.of(context)
child: CupertinoPicker( .copyWith()
backgroundColor: Colors.white, .size
children: _sampleRecurringOptions.map((thisOption) => Text(thisOption, style: TextStyle(fontSize: 30))).toList(), .height /
onSelectedItemChanged: ((newValue) { 3,
transaction.recurring = _sampleRecurringOptions[newValue]; child: CupertinoPicker(
setState(() {}); backgroundColor: Colors.white,
}), children: _sampleRecurringOptions
magnification: 1.1, .map((thisOption) => Text(thisOption,
useMagnifier: true, style: TextStyle(fontSize: 30)))
itemExtent: 36, .toList(),
), onSelectedItemChanged: ((newValue) {
); transaction.recurring =
} _sampleRecurringOptions[newValue];
); setState(() {});
}),
magnification: 1.1,
useMagnifier: true,
itemExtent: 36,
),
);
});
}, },
child: Text( child: Text(
transaction.recurring == null transaction.recurring == null
? 'None' ? 'None'
: transaction.recurring, : transaction.recurring,
style: style: TextStyle(color: Colors.white, fontSize: 22.0),
TextStyle(color: Colors.white, fontSize: 22.0),
), ),
color: Colors.blue, color: Colors.blue,
), ),
@ -328,11 +363,15 @@ class ReceiptPage2State extends State<ReceiptPage2> {
), // Recurring picker ), // Recurring picker
Container( Container(
padding: EdgeInsets.fromLTRB(MediaQuery.of(context).size.width * 0.05,15,MediaQuery.of(context).size.width * 0.05,0.0), padding: EdgeInsets.fromLTRB(
MediaQuery.of(context).size.width * 0.05,
15,
MediaQuery.of(context).size.width * 0.05,
0.0),
child: Row( child: Row(
children: <Widget> [ children: <Widget>[
Container( Container(
child : Text( child: Text(
"Category", "Category",
style: TextStyle( style: TextStyle(
fontSize: 22, fontSize: 22,
@ -342,7 +381,6 @@ class ReceiptPage2State extends State<ReceiptPage2> {
), ),
width: MediaQuery.of(context).size.width * 0.3, width: MediaQuery.of(context).size.width * 0.3,
), ),
Container( Container(
padding: const EdgeInsets.fromLTRB(0, 0, 0, 0), padding: const EdgeInsets.fromLTRB(0, 0, 0, 0),
height: _widgetHeight, height: _widgetHeight,
@ -355,12 +393,22 @@ class ReceiptPage2State extends State<ReceiptPage2> {
context: context, context: context,
builder: (BuildContext builder) { builder: (BuildContext builder) {
return Container( return Container(
height: MediaQuery.of(context).copyWith().size.height / 3, height: MediaQuery.of(context)
.copyWith()
.size
.height /
3,
child: CupertinoPicker( child: CupertinoPicker(
backgroundColor: Colors.white, backgroundColor: Colors.white,
children: _categories.map((thisOption) => Text(thisOption, style: TextStyle(fontSize: 30),)).toList(), children: _categories
.map((thisOption) => Text(
thisOption,
style: TextStyle(fontSize: 30),
))
.toList(),
onSelectedItemChanged: ((newValue) { onSelectedItemChanged: ((newValue) {
transaction.category = _categories[newValue]; transaction.category =
_categories[newValue];
setState(() {}); setState(() {});
}), }),
magnification: 1.1, magnification: 1.1,
@ -374,8 +422,7 @@ class ReceiptPage2State extends State<ReceiptPage2> {
transaction.category == null transaction.category == null
? 'None' ? 'None'
: transaction.category, : transaction.category,
style: style: TextStyle(color: Colors.white, fontSize: 22.0),
TextStyle(color: Colors.white, fontSize: 22.0),
), ),
color: Colors.blue, color: Colors.blue,
), ),
@ -386,13 +433,17 @@ class ReceiptPage2State extends State<ReceiptPage2> {
), // Category picker ), // Category picker
Container( Container(
padding: EdgeInsets.fromLTRB(MediaQuery.of(context).size.width * 0.05,15,MediaQuery.of(context).size.width * 0.05,0.0), padding: EdgeInsets.fromLTRB(
MediaQuery.of(context).size.width * 0.05,
15,
MediaQuery.of(context).size.width * 0.05,
0.0),
child: Tooltip( child: Tooltip(
message: "Essential or not", message: "Essential or not",
child: Row( child: Row(
children: <Widget> [ children: <Widget>[
Container( Container(
child : Text( child: Text(
"Essential", "Essential",
style: TextStyle( style: TextStyle(
fontSize: 22, fontSize: 22,
@ -402,7 +453,6 @@ class ReceiptPage2State extends State<ReceiptPage2> {
), ),
width: MediaQuery.of(context).size.width * 0.3, width: MediaQuery.of(context).size.width * 0.3,
), ),
Container( Container(
height: _widgetHeight, height: _widgetHeight,
width: MediaQuery.of(context).size.width * 0.6, width: MediaQuery.of(context).size.width * 0.6,
@ -419,13 +469,17 @@ class ReceiptPage2State extends State<ReceiptPage2> {
), // Essential ), // Essential
Container( Container(
padding: EdgeInsets.fromLTRB(MediaQuery.of(context).size.width * 0.05,15,MediaQuery.of(context).size.width * 0.05,0.0), padding: EdgeInsets.fromLTRB(
MediaQuery.of(context).size.width * 0.05,
15,
MediaQuery.of(context).size.width * 0.05,
0.0),
child: Tooltip( child: Tooltip(
message: "Transaction amount", message: "Transaction amount",
child: Row( child: Row(
children: <Widget> [ children: <Widget>[
Container( Container(
child : Text( child: Text(
"Amount", "Amount",
style: TextStyle( style: TextStyle(
fontSize: 22, fontSize: 22,
@ -435,8 +489,6 @@ class ReceiptPage2State extends State<ReceiptPage2> {
), ),
width: MediaQuery.of(context).size.width * 0.3, width: MediaQuery.of(context).size.width * 0.3,
), ),
Container( Container(
padding: const EdgeInsets.fromLTRB(0, 0, 0, 0), padding: const EdgeInsets.fromLTRB(0, 0, 0, 0),
height: _widgetHeight, height: _widgetHeight,
@ -447,10 +499,9 @@ class ReceiptPage2State extends State<ReceiptPage2> {
), ),
textAlign: TextAlign.center, textAlign: TextAlign.center,
controller: transaction.amount, controller: transaction.amount,
decoration: InputDecoration( decoration: InputDecoration(hintText: "0.00"),
hintText: "0.00" keyboardType: TextInputType.numberWithOptions(
), decimal: true, signed: true),
keyboardType: TextInputType.numberWithOptions(decimal: true, signed: true),
), ),
), ),
], ],
@ -459,7 +510,11 @@ class ReceiptPage2State extends State<ReceiptPage2> {
), // Amount picker ), // Amount picker
Padding( Padding(
padding: EdgeInsets.fromLTRB(MediaQuery.of(context).size.width * 0.05,MediaQuery.of(context).size.height * 0.03,MediaQuery.of(context).size.width * 0.05,15.0), padding: EdgeInsets.fromLTRB(
MediaQuery.of(context).size.width * 0.05,
MediaQuery.of(context).size.height * 0.03,
MediaQuery.of(context).size.width * 0.05,
15.0),
child: Tooltip( child: Tooltip(
message: "Submit receipt", message: "Submit receipt",
child: Container( child: Container(
@ -470,45 +525,52 @@ class ReceiptPage2State extends State<ReceiptPage2> {
opacity: 1, opacity: 1,
child: Stack( child: Stack(
children: [ children: [
AnimatedBackground([Colors.blue, Colors.lightBlue[300]], Colors.lightBlue, Alignment.topLeft, Alignment.bottomRight, 4), AnimatedBackground(
[Colors.blue, Colors.lightBlue[300]],
Colors.lightBlue,
Alignment.topLeft,
Alignment.bottomRight,
4),
Material( Material(
type: MaterialType.transparency, type: MaterialType.transparency,
child: InkWell( child: InkWell(
child: Center( child: Center(
child : Text("GO", child: Text(
style: "GO",
TextStyle(color: Colors.white, fontSize: 30.0), style: TextStyle(
color: Colors.white, fontSize: 30.0),
), ),
), ),
onTap: () { onTap: () {
try { try {
if (transaction.amount.text == "" || transaction.organisation.name == null) { if (transaction.amount.text == "" ||
transaction.organisation.name == null) {
showDialog( showDialog(
context: context, context: context,
builder: (BuildContext context) { builder: (BuildContext context) {
return _invalidDialog(context); return _invalidDialog(context);
} });
);
} else { } else {
if (double.tryParse(transaction.amount.text) != null && double.tryParse(transaction.amount.text) > 0) { if (double.tryParse(
transaction.amount.text) !=
null &&
double.tryParse(transaction.amount.text) >
0) {
_submitReceipt(transaction); _submitReceipt(transaction);
} else { } else {
showDialog( showDialog(
context: context, context: context,
builder: (BuildContext context) { builder: (BuildContext context) {
return _invalidDialog(context); return _invalidDialog(context);
} });
);
} }
} }
} } catch (_) {
catch (_) {
showDialog( showDialog(
context: context, context: context,
builder: (BuildContext context) { builder: (BuildContext context) {
return _invalidDialog(context); return _invalidDialog(context);
} });
);
} }
}, },
), ),
@ -524,4 +586,4 @@ class ReceiptPage2State extends State<ReceiptPage2> {
), ),
); );
} }
} }

View File

@ -12,7 +12,7 @@ class SplashScreen extends StatefulWidget {
class _SplashScreenState extends State<SplashScreen> { class _SplashScreenState extends State<SplashScreen> {
final int splashDuration = 1; final int splashDuration = 1;
startTime() async { Future<Timer> startTime() async {
return Timer(Duration(seconds: splashDuration), () { return Timer(Duration(seconds: splashDuration), () {
SystemChannels.textInput.invokeMethod('TextInput.hide'); SystemChannels.textInput.invokeMethod('TextInput.hide');
Navigator.of(context).pushReplacementNamed('/LoginPage'); Navigator.of(context).pushReplacementNamed('/LoginPage');
@ -41,8 +41,7 @@ class _SplashScreenState extends State<SplashScreen> {
alignment: FractionalOffset(0.5, 0.3), alignment: FractionalOffset(0.5, 0.3),
decoration: BoxDecoration( decoration: BoxDecoration(
image: DecorationImage( image: DecorationImage(
image: AssetImage('assets/images/launch_image.png') image: AssetImage('assets/images/launch_image.png')),
),
), ),
), ),
), ),

View File

@ -4,7 +4,7 @@ import 'package:shared_preferences/shared_preferences.dart';
import 'package:local_spend/pages/customerGraphs.dart'; import 'package:local_spend/pages/customerGraphs.dart';
import 'package:local_spend/pages/orgGraphs.dart'; import 'package:local_spend/pages/orgGraphs.dart';
const URL = "https://flutter.io/"; const url = "https://flutter.io/";
const demonstration = false; const demonstration = false;
class StatsPage extends StatefulWidget { class StatsPage extends StatefulWidget {
@ -28,7 +28,7 @@ class StatsPageState extends State<StatsPage> {
super.dispose(); super.dispose();
} }
_saveCurrentRoute(String lastRoute) async { void _saveCurrentRoute(String lastRoute) async {
SharedPreferences preferences = await SharedPreferences.getInstance(); SharedPreferences preferences = await SharedPreferences.getInstance();
await preferences.setString('LastPageRoute', lastRoute); await preferences.setString('LastPageRoute', lastRoute);
} }
@ -43,7 +43,8 @@ class StatsPageState extends State<StatsPage> {
if (userType == "-") { if (userType == "-") {
_getUserType().then((value) { _getUserType().then((value) {
print(value); print(value);
userType = '${value[0].toUpperCase()}${value.substring(1)}'; // capitalises first letter userType =
'${value[0].toUpperCase()}${value.substring(1)}'; // capitalises first letter
setState(() {}); setState(() {});
}); });
} }
@ -62,10 +63,7 @@ class StatsPageState extends State<StatsPage> {
color: Colors.white, color: Colors.white,
), ),
), ),
Padding( Padding(padding: EdgeInsets.symmetric(horizontal: 4)),
padding: EdgeInsets.symmetric(horizontal: 4)
),
Text( Text(
userType, userType,
style: TextStyle( style: TextStyle(
@ -75,14 +73,16 @@ class StatsPageState extends State<StatsPage> {
), ),
], ],
), ),
centerTitle: true, centerTitle: true,
iconTheme: IconThemeData(color: Colors.black), iconTheme: IconThemeData(color: Colors.black),
), ),
body: Container(
body : Container(
padding: EdgeInsets.fromLTRB(0, 0, 0, 0), padding: EdgeInsets.fromLTRB(0, 0, 0, 0),
child: (userType == "-" ? null : (userType.toLowerCase() == "customer" ? CustomerGraphs() : OrgGraphs())), child: (userType == "-"
? null
: (userType.toLowerCase() == "customer"
? CustomerGraphs()
: OrgGraphs())),
), ),
); );
} }

View File

@ -35,42 +35,42 @@ packages:
name: build name: build
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.4" version: "1.1.6"
build_config: build_config:
dependency: transitive dependency: transitive
description: description:
name: build_config name: build_config
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.4.0" version: "0.4.1+1"
build_daemon: build_daemon:
dependency: transitive dependency: transitive
description: description:
name: build_daemon name: build_daemon
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.0" version: "2.0.0"
build_resolvers: build_resolvers:
dependency: transitive dependency: transitive
description: description:
name: build_resolvers name: build_resolvers
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.5" version: "1.0.7"
build_runner: build_runner:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: build_runner name: build_runner
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.6.1" version: "1.6.6"
build_runner_core: build_runner_core:
dependency: transitive dependency: transitive
description: description:
name: build_runner_core name: build_runner_core
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.0.6" version: "3.0.9"
built_collection: built_collection:
dependency: transitive dependency: transitive
description: description:
@ -84,7 +84,7 @@ packages:
name: built_value name: built_value
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "6.6.0" version: "6.7.0"
charcode: charcode:
dependency: transitive dependency: transitive
description: description:
@ -106,6 +106,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.6.0" version: "0.6.0"
checked_yaml:
dependency: transitive
description:
name: checked_yaml
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2"
code_builder: code_builder:
dependency: transitive dependency: transitive
description: description:
@ -133,14 +140,14 @@ packages:
name: crypto name: crypto
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.6" version: "2.1.2"
csslib: csslib:
dependency: transitive dependency: transitive
description: description:
name: csslib name: csslib
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.16.0" version: "0.16.1"
cupertino_icons: cupertino_icons:
dependency: "direct main" dependency: "direct main"
description: description:
@ -154,7 +161,7 @@ packages:
name: dart_style name: dart_style
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.2.7" version: "1.2.9"
datetime_picker_formfield: datetime_picker_formfield:
dependency: "direct main" dependency: "direct main"
description: description:
@ -193,13 +200,6 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
flutter_maps:
dependency: "direct main"
description:
name: flutter_maps
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.0"
flutter_test: flutter_test:
dependency: "direct dev" dependency: "direct dev"
description: flutter description: flutter
@ -219,6 +219,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.7" version: "1.1.7"
google_maps_flutter:
dependency: "direct main"
description:
name: google_maps_flutter
url: "https://pub.dartlang.org"
source: hosted
version: "0.5.20+5"
graphs: graphs:
dependency: transitive dependency: transitive
description: description:
@ -283,7 +290,7 @@ packages:
source: hosted source: hosted
version: "2.3.0" version: "2.3.0"
json_serializable: json_serializable:
dependency: "direct dev" dependency: "direct main"
description: description:
name: json_serializable name: json_serializable
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
@ -330,7 +337,7 @@ packages:
name: package_config name: package_config
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.5" version: "1.1.0"
package_resolver: package_resolver:
dependency: transitive dependency: transitive
description: description:
@ -346,7 +353,7 @@ packages:
source: hosted source: hosted
version: "1.6.2" version: "1.6.2"
pedantic: pedantic:
dependency: transitive dependency: "direct dev"
description: description:
name: pedantic name: pedantic
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
@ -372,7 +379,7 @@ packages:
name: pubspec_parse name: pubspec_parse
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.1.4" version: "0.1.5"
quiver: quiver:
dependency: transitive dependency: transitive
description: description:
@ -419,7 +426,7 @@ packages:
name: source_gen name: source_gen
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.9.4+2" version: "0.9.4+3"
source_span: source_span:
dependency: transitive dependency: transitive
description: description:
@ -475,7 +482,7 @@ packages:
name: timing name: timing
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.1.1+1" version: "0.1.1+2"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:
@ -503,14 +510,14 @@ packages:
name: watcher name: watcher
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.9.7+10" version: "0.9.7+12"
web_socket_channel: web_socket_channel:
dependency: transitive dependency: transitive
description: description:
name: web_socket_channel name: web_socket_channel
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.13" version: "1.0.15"
yaml: yaml:
dependency: transitive dependency: transitive
description: description:
@ -519,5 +526,5 @@ packages:
source: hosted source: hosted
version: "2.1.16" version: "2.1.16"
sdks: sdks:
dart: ">=2.3.0-dev.0.1 <3.0.0" dart: ">=2.3.0 <3.0.0"
flutter: ">=0.1.4 <2.0.0" flutter: ">=1.5.0 <2.0.0"

View File

@ -10,7 +10,7 @@ description: Local Spend Tracker
version: 1.0.0+1 version: 1.0.0+1
environment: environment:
sdk: ">=2.0.0-dev.68.0 <3.0.0" sdk: ">=2.2.2 <3.0.0"
dependencies: dependencies:
flutter: flutter:
@ -26,7 +26,8 @@ dependencies:
flutter_fadein: ^1.1.1 flutter_fadein: ^1.1.1
charts_flutter: ^0.6.0 charts_flutter: ^0.6.0
simple_animations: ^1.3.3 simple_animations: ^1.3.3
flutter_maps: ^0.1.0 google_maps_flutter: ^0.5.20+5
json_serializable: ^2.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.
cupertino_icons: ^0.1.2 cupertino_icons: ^0.1.2
@ -34,9 +35,8 @@ dependencies:
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter
build_runner: ^1.1.3 pedantic: ^1.4.0
json_serializable: ^2.1.2 build_runner: ^1.2.7
# For information on the generic Dart part of this file, see the # For information on the generic Dart part of this file, see the
# following page: https://www.dartlang.org/tools/pub/pubspec # following page: https://www.dartlang.org/tools/pub/pubspec

View File

@ -11,7 +11,6 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:local_spend/main.dart'; import 'package:local_spend/main.dart';
void main() { void main() {
testWidgets('GO button repetition test', (WidgetTester tester) async { testWidgets('GO button repetition test', (WidgetTester tester) async {
// Build our app and trigger a frame. // Build our app and trigger a frame.
await tester.pumpWidget(MyApp()); await tester.pumpWidget(MyApp());