diff --git a/android/app/build.gradle b/android/app/build.gradle
index 743b022..1032764 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -211,5 +211,6 @@ dependencies {
}
repositories {
+ google()
mavenCentral()
}
diff --git a/android/app/src/main/java/com/dinect/checker/MainActivity.java b/android/app/src/main/java/com/dinect/checker/MainActivity.java
index 8566293..be9a587 100644
--- a/android/app/src/main/java/com/dinect/checker/MainActivity.java
+++ b/android/app/src/main/java/com/dinect/checker/MainActivity.java
@@ -38,6 +38,7 @@ public class MainActivity extends FlutterActivity {
private MethodChannel mChannel;
private Map mScannerArgs;
+ private Result scannerResult;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -59,6 +60,7 @@ public class MainActivity extends FlutterActivity {
result.success(BuildConfig.currency);
break;
case "startScanner":
+ scannerResult = result;
startScannerActivity(call);
break;
case "isOnline":
@@ -169,7 +171,7 @@ public class MainActivity extends FlutterActivity {
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == START_SCANNER_REQUEST_CODE) {
if (resultCode == RESULT_CANCELED) {
- finish();
+ scannerResult.error("Scanning is cancelled", null, null);
} else if (resultCode == RESULT_OK) {
if (data != null && data.getExtras() != null) {
String user = data.getExtras().getString("user", null);
@@ -178,7 +180,9 @@ public class MainActivity extends FlutterActivity {
ArrayList args = new ArrayList<>(2);
args.add(user);
args.add(card);
- mChannel.invokeMethod("purchase", args);
+ if(scannerResult != null) {
+ scannerResult.success(args);
+ }
} else {
String menuItem = data.getExtras().getString("item", null);
if (menuItem != null) {
diff --git a/android/build.gradle b/android/build.gradle
index a7244c4..a2b6e7a 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -13,8 +13,8 @@ buildscript {
allprojects {
repositories {
- jcenter()
google()
+ jcenter()
}
}
diff --git a/assets/values-en/strings.xml b/assets/values-en/strings.xml
index b2b3ee7..88d911c 100644
--- a/assets/values-en/strings.xml
+++ b/assets/values-en/strings.xml
@@ -162,4 +162,7 @@ You bonus balance will be changed and you will have %s bonus points.
Return confirmed
Purchase, which cost %s on %s is returned.
Points
+ Cancel
+ Are you sure you want to cancel this purchase?
+ Total amount: %s %s, with discount of %s %s (%s%%)
diff --git a/assets/values-es/strings.xml b/assets/values-es/strings.xml
index 4ed0d1d..95459b9 100644
--- a/assets/values-es/strings.xml
+++ b/assets/values-es/strings.xml
@@ -158,4 +158,7 @@ Se cambiará su saldo de bonificación y tendrá %s puntos de bonificación.Regreso confirmado
Compra, cuyo costo %s en %s se devuelve.
Puntos
+ Cancelar
+ ¿Seguro que quieres cancelar esta compra?
+ Cantidad total: %s %s, con descuento de %s %s (%s%%)
diff --git a/assets/values-ru/strings.xml b/assets/values-ru/strings.xml
index 0397885..5b2d2fe 100644
--- a/assets/values-ru/strings.xml
+++ b/assets/values-ru/strings.xml
@@ -161,4 +161,7 @@
Возврат подтвержден
Покупка на сумму %s от %s возвращена.
Баллы
+ Отмена
+ Вы уверены что хотите отменить покупку?
+ Итого покупка: %s %s, Со скидкой %s %s (%s%%)
diff --git a/assets/values-ua/strings.xml b/assets/values-ua/strings.xml
index b733dd9..d712144 100644
--- a/assets/values-ua/strings.xml
+++ b/assets/values-ua/strings.xml
@@ -163,4 +163,7 @@
Повернення підтверджено
Повертається придбання, вартість якого %s на %s.
Бонусні бали
+ Скасувати
+ Дійсно скасувати цю покупку?
+ Загальна кількість: %s %s, зі знижкою %s %s (%s%%)
diff --git a/ios/Runner/AppDelegate.m b/ios/Runner/AppDelegate.m
index a583bf2..bd3e706 100644
--- a/ios/Runner/AppDelegate.m
+++ b/ios/Runner/AppDelegate.m
@@ -12,9 +12,7 @@
FlutterMethodChannel* platformChannel = [FlutterMethodChannel
methodChannelWithName:@"com.dinect.checker/instance_id"
- binaryMessenger:controller];
-
- __weak FlutterMethodChannel* weekPlatformChannel = platformChannel;
+ binaryMessenger:controller.binaryMessenger];
NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier];
@@ -116,7 +114,7 @@
result(buildSettings[@"currency"]);
} else if ([@"startScanner" isEqualToString:call.method]) {
ScannerViewController *modalViewController = [[ScannerViewController alloc] initWithStrings:call.arguments];
- modalViewController.platformChannel = weekPlatformChannel;
+ modalViewController.platformChannel = platformChannel;
[controller presentViewController:modalViewController animated:YES completion:nil];
} else if ([@"isOnline" isEqualToString:call.method]) {
result(@YES);
diff --git a/ios/Runner/ScannerViewController.swift b/ios/Runner/ScannerViewController.swift
index 53448b9..0782408 100644
--- a/ios/Runner/ScannerViewController.swift
+++ b/ios/Runner/ScannerViewController.swift
@@ -272,7 +272,7 @@ import ZXingObjC
} else {
print("Result is not nil (ios code)");
self.dismiss(animated: true) {
- self.platformChannel?.invokeMethod("purchase", arguments: [result, str])
+ self.platformChannel?.invokeMethod("scanSuccess", arguments: [result!, str])
}
}
})
diff --git a/lib/screens/finish_registration.dart b/lib/screens/finish_registration.dart
index e9435e5..6cc42ef 100644
--- a/lib/screens/finish_registration.dart
+++ b/lib/screens/finish_registration.dart
@@ -1,5 +1,4 @@
import 'dart:convert';
-import 'dart:async';
import 'package:checker/base/base_screen.dart';
import 'package:checker/base/base_state.dart';
diff --git a/lib/screens/purchase.dart b/lib/screens/purchase.dart
index ee7afc8..4a8016f 100644
--- a/lib/screens/purchase.dart
+++ b/lib/screens/purchase.dart
@@ -1,52 +1,59 @@
-import 'package:checker/base/base_screen.dart';
-import 'package:checker/db.dart';
-import 'package:checker/screens/return.dart';
-import 'package:flutter/material.dart';
-import 'package:flutter/services.dart';
+import 'dart:async';
import 'dart:convert';
import 'dart:core';
-import 'dart:async';
-import 'package:checker/resources.dart';
-import 'package:checker/strings.dart';
+import 'package:checker/base/base_screen.dart';
+import 'package:checker/base/base_state.dart';
import 'package:checker/common.dart';
import 'package:checker/consts.dart';
+import 'package:checker/db.dart';
import 'package:checker/network.dart';
-import 'package:checker/base/base_state.dart';
+import 'package:checker/resources.dart';
import 'package:checker/screens/purchase_success.dart';
+import 'package:checker/screens/purchase_sum.dart';
+import 'package:checker/screens/return.dart';
+import 'package:checker/strings.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+
+typedef PurchaseResponseCallback = void Function(Map, String, String);
/// Экран проведения покупки.
class PurchaseScreen extends BaseScreen {
-
- PurchaseScreen(helper, app, this.user, this.card) : super(helper, app);
+ PurchaseScreen(helper, app, this.user, this.card, this.sum)
+ : super(helper, app);
final String user;
final String card;
+ final String sum;
@override
- State createState() => new PurchaseScreenState(helper, app, user, card);
+ State createState() =>
+ new PurchaseScreenState(helper, app, user, card);
}
class PurchaseScreenState extends BaseState {
/// Объект, помогающий вручную изменять введенный пользователем текст.
/// Используется для форматирования введенных пользователем данных
/// (удаляет запрещенные символы до их отображаения).
- TextEditingController controller = new TextEditingController();
+ TextEditingController controller;
TextEditingController bonusController = new TextEditingController();
bool isAutomaticallyImplyLeading() => false;
- PurchaseScreenState(SqliteHelper helper, String app, String userString, String card) : super(helper, app) {
+ PurchaseScreenState(
+ SqliteHelper helper, String app, String userString, String card)
+ : super(helper, app) {
this.user = json.decode(userString);
this.card = card;
}
@override
void initState() {
+ controller = new TextEditingController(text: widget.sum ?? "");
loading = true;
requestAsyncData(user);
- loading = false;
buildFocusNode();
scrollController = new ScrollController();
super.initState();
@@ -70,21 +77,22 @@ class PurchaseScreenState extends BaseState {
@override
Widget getScreenContent() {
List widgetList = [];
- widgetList.add(getValueWithDescription(
- StringsLocalization.buyer(),
- user['first_name'] == null ? '' : user['first_name']
- ));
+ widgetList.add(getValueWithDescription(StringsLocalization.buyer(),
+ user['first_name'] == null ? '' : user['first_name']));
widgetList.add(getValueWithDescription(StringsLocalization.card(), card));
- if ((app != 'crypto')) {
- widgetList.add(getValueWithDescription(StringsLocalization.reward(), loyalty));
+ if (app != 'crypto') {
+ widgetList
+ .add(getValueWithDescription(StringsLocalization.reward(), loyalty));
if (bonus.length > 0) {
- widgetList.add(getValueWithDescription(StringsLocalization.bonus(), bonus));
+ widgetList
+ .add(getValueWithDescription(StringsLocalization.bonus(), bonus));
}
}
widgetList.add(getHintLabel());
- widgetList.add(getInputField()); // Нельзя добавить еще одно поле таким же способом
+ widgetList.add(
+ getInputField()); // Нельзя добавить еще одно поле таким же способом
if ((app != 'autobonus') && (app != 'crypto')) {
if (this.loyalityType == 'bonus') {
@@ -94,16 +102,12 @@ class PurchaseScreenState extends BaseState {
if (this.coupons.length > 0) {
widgetList.add(getItemTitle(StringsLocalization.selectCoupons()));
this.coupons.forEach((couponItem) {
- widgetList.add(getItemToggleSwitch(
- couponItem['offer_name'],
- couponItem['coupon_condition'],
- couponItem['isSet'],
- (val) {
- setState(() {
- couponItem['isSet'] = val;
- });
- }
- ));
+ widgetList.add(getItemToggleSwitch(couponItem['offer_name'],
+ couponItem['coupon_condition'], couponItem['isSet'], (val) {
+ setState(() {
+ couponItem['isSet'] = val;
+ });
+ }));
});
}
}
@@ -111,16 +115,14 @@ class PurchaseScreenState extends BaseState {
widgetList.add(wrapButton(getScreenMargins(36.0), getCompleteButton()));
widgetList.add(wrapButton(
- getScreenMargins(24.0),
- getScanButton(
- context,
- StringsLocalization.scan(),
- Resources.getPrimaryColor(app)
- )
- ));
+ getScreenMargins(24.0),
+ getCancelScanButton(context, StringsLocalization.cancel(),
+ Resources.getPrimaryColor(app))));
if (this.coupons.length == 0) {
- widgetList.add(new Container(height: 50.0,));
+ widgetList.add(new Container(
+ height: 50.0,
+ ));
}
listView = new ListView(children: widgetList, controller: scrollController);
@@ -131,8 +133,10 @@ class PurchaseScreenState extends BaseState {
void openReturnScreen() {
Future.delayed(const Duration(milliseconds: 200), () {
- Route route = MaterialPageRoute(builder: (BuildContext context) =>
- ReturnScreen(helper, app, user['id'], user['bonus']), fullscreenDialog: true);
+ Route route = MaterialPageRoute(
+ builder: (BuildContext context) =>
+ ReturnScreen(helper, app, user['id'], user['bonus']),
+ fullscreenDialog: true);
Navigator.push(context, route);
});
}
@@ -141,9 +145,8 @@ class PurchaseScreenState extends BaseState {
var bonusTextField = new TextField(
keyboardType: TextInputType.number,
decoration: new InputDecoration.collapsed(
- hintText: StringsLocalization.bonusHint(),
- hintStyle: new TextStyle(color: greyTextColor, fontSize: 16.0)
- ),
+ hintText: StringsLocalization.bonusHint(),
+ hintStyle: new TextStyle(color: greyTextColor, fontSize: 16.0)),
focusNode: bonusFocusNode,
controller: bonusController,
onSubmitted: (String text) {
@@ -157,26 +160,21 @@ class PurchaseScreenState extends BaseState {
return new Column(
children: [
new Container(
- margin: new EdgeInsets.only(
- left: verticalMargin,
- right: verticalMargin,
- top: verticalMargin
- ),
- padding: getInputFieldContainerPadding(),
- decoration: getInputFieldContainerDecoration(),
- child: bonusTextField
- ),
+ margin: new EdgeInsets.only(
+ left: verticalMargin,
+ right: verticalMargin,
+ top: verticalMargin),
+ padding: getInputFieldContainerPadding(),
+ decoration: getInputFieldContainerDecoration(),
+ child: bonusTextField),
new Container(
- margin: new EdgeInsets.only(
- top: 5.0
- ),
- child: new Text(
- StringsLocalization.bonusExplanation(),
- textAlign: TextAlign.center,
- overflow: TextOverflow.ellipsis,
- style: new TextStyle(color: greyTextColor, fontSize: 11.0),
- )
- )
+ margin: new EdgeInsets.only(top: 5.0),
+ child: new Text(
+ StringsLocalization.bonusExplanation(),
+ textAlign: TextAlign.center,
+ overflow: TextOverflow.ellipsis,
+ style: new TextStyle(color: greyTextColor, fontSize: 11.0),
+ ))
],
);
}
@@ -188,19 +186,20 @@ class PurchaseScreenState extends BaseState {
getCompleteButton() {
return buildRaisedButton(
- StringsLocalization.completePurchase(), () => onPurchaseClick());
+ StringsLocalization.completePurchase(), () => onPurchaseClick());
}
- Widget getScanButton(BuildContext context, String title, Color textColor) {
+ Widget getCancelScanButton(
+ BuildContext context, String title, Color textColor) {
return new Container(
- height: buttonHeight,
- child: new FlatButton(
- child: new Text(title, style: new TextStyle(color: textColor)),
- onPressed: () => restartScanner()),
- decoration: new BoxDecoration(
- border: new Border.all(
- color: Resources.getButtonColor(app), width: 1.0),
- borderRadius: new BorderRadius.all(new Radius.circular(4.0))));
+ height: buttonHeight,
+ child: new FlatButton(
+ child: new Text(title, style: new TextStyle(color: textColor)),
+ onPressed: () => restartFlow()),
+ decoration: new BoxDecoration(
+ border: new Border.all(
+ color: Resources.getButtonColor(app), width: 1.0),
+ borderRadius: new BorderRadius.all(new Radius.circular(4.0))));
}
@override
@@ -216,18 +215,18 @@ class PurchaseScreenState extends BaseState {
@override
getTextWidget() {
return new TextField(
- keyboardType: TextInputType.number,
- decoration: new InputDecoration.collapsed(
- hintText: getHintString(),
- hintStyle: new TextStyle(color: greyTextColor, fontSize: 16.0)),
- controller: controller,
- focusNode: sumFocusNode,
- onSubmitted: (String text) {
- setState(() {
- controller.text = _parseSum(text);
- });
- },
- textAlign: TextAlign.center);
+ keyboardType: TextInputType.number,
+ decoration: new InputDecoration.collapsed(
+ hintText: getHintString(),
+ hintStyle: new TextStyle(color: greyTextColor, fontSize: 16.0)),
+ controller: controller,
+ focusNode: sumFocusNode,
+ onSubmitted: (String text) {
+ setState(() {
+ controller.text = _parseSum(text);
+ });
+ },
+ textAlign: TextAlign.center);
}
requestAsyncData(Map user) async {
@@ -239,10 +238,8 @@ class PurchaseScreenState extends BaseState {
var token = await helper.getToken();
response = await getLoyaltyRequest(user['loyalty_url'], token);
couponResponse = await getCouponsRequest(
- user['coupons_url'] + '?status=ACTIVE',
- token
- );
- } catch(error) {
+ user['coupons_url'] + '?status=ACTIVE', token);
+ } catch (error) {
print(error.toString());
}
Map loyality = json.decode(response.body);
@@ -263,10 +260,10 @@ class PurchaseScreenState extends BaseState {
// TODO: Переделать, если потребуется
String _cleanupNumber(String text) {
String tmp = text
- .replaceAll(' ', '')
- .replaceAll('-', '')
- .replaceAll(',', '.')
- .replaceAll('..', '.');
+ .replaceAll(' ', '')
+ .replaceAll('-', '')
+ .replaceAll(',', '.')
+ .replaceAll('..', '.');
while (tmp.indexOf('..') != -1) {
tmp = tmp.replaceAll('..', '.');
@@ -299,59 +296,94 @@ class PurchaseScreenState extends BaseState {
}
onPurchaseClick() {
+ String val = _parseSum(controller.text);
+ purchase(val, false, _showPrecalculatedValues);
+ }
+
+ void _showPrecalculatedValues(Map response, String sumTotal, String token) {
String val = _parseSum(controller.text);
helper.getCurrency().then((currency) {
print(currency.toString());
+ final String totalAmount = response['sum_total'];
+ final String totalDiscount = response['sum_discount'];
+ final String discount = (response['discount'] as int).toString();
+ print(response);
showDialog(
- context: context,
- builder: (_) => new AlertDialog(
- title: new Text(StringsLocalization.confirmation()),
- content:
- new Text(
- StringsLocalization.confirmPurchase(val, currency)
- ),
- actions: [
- new FlatButton(
- child: new Text(StringsLocalization.no()),
- onPressed: () {
- Navigator.of(context).pop();
- },
- ),
- new FlatButton(
- child: new Text(StringsLocalization.yes()),
- onPressed: () {
- Navigator.of(context).pop();
- purchase(val);
- },
- )
- ]));
+ context: context,
+ builder: (_) => new AlertDialog(
+ title: new Text(StringsLocalization.confirmation()),
+ content: Text(StringsLocalization.purchaseDetails(
+ totalAmount, totalDiscount, discount, currency)),
+ actions: [
+ new FlatButton(
+ child: new Text(StringsLocalization.no()),
+ onPressed: () {
+ Navigator.of(context).pop();
+ },
+ ),
+ new FlatButton(
+ child: new Text(StringsLocalization.yes()),
+ onPressed: () {
+ Navigator.of(context).pop();
+ purchase(val, true, _paymentConfirmed);
+ },
+ )
+ ]));
+ });
+ }
+
+ void _paymentConfirmed(Map purchase, String sumTotal, String token) async {
+ var couponsResponse;
+
+ try {
+ couponsResponse = await getCouponsRequest(purchase['coupons_url'], token);
+ print(couponsResponse.body);
+ } catch (error) {
+ purchaseInProgress = false;
+ print(error.toString());
+ }
+
+ Map coupons = json.decode(couponsResponse.body);
+
+ new Future.delayed(const Duration(milliseconds: 200), () {
+ print('show purchase success!');
+ var route = new MaterialPageRoute(
+ builder: (BuildContext context) => new PurchaseSuccessScreen(
+ sumTotal,
+ user['first_name'] == null ? '' : user['first_name'],
+ helper,
+ app,
+ purchase,
+ coupons['results']),
+ fullscreenDialog: true);
+ Navigator.of(context).push(route).then((token) {
+ Navigator.of(context).pop(token);
+ });
});
}
apiErrorAlert(String errorText) {
showDialog(
- context: context,
- builder: (_) => new AlertDialog(
- content: new Text(errorText),
- actions: [
- new FlatButton(
- child: new Text('Ok'),
- onPressed: () {
- Navigator.of(context).pop();
- },
- )
- ]
- )
- );
+ context: context,
+ builder: (_) =>
+ new AlertDialog(content: new Text(errorText), actions: [
+ new FlatButton(
+ child: new Text('Ok'),
+ onPressed: () {
+ Navigator.of(context).pop();
+ },
+ )
+ ]));
}
- purchase(String sumTotal) async {
+ purchase(
+ String sumTotal, bool commit, PurchaseResponseCallback callback) async {
setState(() {
loading = true;
});
if (await platform.invokeMethod('isOnline')) {
if (!purchaseInProgress) {
- purchaseInProgress = true;
+ purchaseInProgress = commit;
String token = await helper.getToken();
var result = await helper.getMerchantID();
@@ -367,10 +399,13 @@ class PurchaseScreenState extends BaseState {
var body = {
'doc_id': result,
'curr_iso_code': currency.toString(),
- 'commit': 'true',
'sum_total': sumTotal,
};
+ if (commit) {
+ body['commit'] = 'true';
+ }
+
if (bonusController.text.length > 0) {
body['bonus_payment'] = bonusController.text;
}
@@ -383,9 +418,10 @@ class PurchaseScreenState extends BaseState {
Map purchase;
try {
- purchaseResponse = await getPurchaseRequest(user['purchases_url'], body, token);
+ purchaseResponse =
+ await getPurchaseRequest(user['purchases_url'], body, token);
purchase = json.decode(purchaseResponse.body);
- } catch(error) {
+ } catch (error) {
purchaseInProgress = false;
print(error.toString());
}
@@ -398,32 +434,7 @@ class PurchaseScreenState extends BaseState {
purchaseInProgress = false;
apiErrorAlert(errors[0]);
} else {
- var couponsResponse;
-
- try {
- couponsResponse = await getCouponsRequest(purchase['coupons_url'], token);
- print(couponsResponse.body);
- } catch(error) {
- purchaseInProgress = false;
- print(error.toString());
- }
-
- Map coupons = json.decode(couponsResponse.body);
-
- new Future.delayed(const Duration(milliseconds: 200), () {
- print('show purchase success!');
- var route = new MaterialPageRoute(builder: (BuildContext context) => new PurchaseSuccessScreen(
- sumTotal,
- user['first_name'] == null ? '' : user['first_name'],
- helper,
- app,
- purchase,
- coupons['results']
- ), fullscreenDialog: true);
- Navigator.of(context).push(route).then((token) {
- Navigator.of(context).pop(token);
- });
- });
+ callback(purchase, sumTotal, token);
}
}
}
@@ -432,24 +443,49 @@ class PurchaseScreenState extends BaseState {
void setBonuses(Map bonuses, bool showBonus) {
print('loyalityType ' + this.loyalityType);
if (bonuses['type'] == 'amount') {
- this.loyalty = '${user['discount']}%';
+ setState(() => this.loyalty = '${user['discount']}%');
} else {
double loyaltyVal = (double.parse(bonuses['amount_to_bonus'][1]) /
- bonuses['amount_to_bonus'][0]) * 100;
- this.loyalty = '${loyaltyVal.toStringAsFixed(0)}%';
+ bonuses['amount_to_bonus'][0]) *
+ 100;
+ setState(() => this.loyalty = '${loyaltyVal.toStringAsFixed(0)}%');
}
if (showBonus && (this.loyalityType == 'bonus')) {
- this.bonus = '${user['bonus']}';
+ setState(() => this.bonus = '${user['bonus']}');
}
print('loyalty ' + this.loyalty);
print('bonus ' + this.bonus);
}
- restartScanner() {
- helper.getToken().then((token) {
- Navigator.of(context).pop(token);
- });
+ restartFlow() {
+ showDialog(
+ context: context,
+ builder: (context) => AlertDialog(
+ content: Text(StringsLocalization.cancelDialog()),
+ actions: [
+ new FlatButton(
+ child: new Text(StringsLocalization.no()),
+ onPressed: () {
+ Navigator.of(context).pop();
+ },
+ ),
+ new FlatButton(
+ child: new Text(StringsLocalization.yes()),
+ onPressed: () {
+ Navigator.of(context).pop();
+ helper.getToken().then((token) {
+ Navigator.pushAndRemoveUntil(
+ context,
+ MaterialPageRoute(
+ builder: (context) => PurchaseSumScreen(
+ widget.helper, widget.app, token)),
+ (route) => false);
+ });
+ },
+ )
+ ],
+ ));
}
FocusNode bonusFocusNode = new FocusNode();
@@ -457,34 +493,22 @@ class PurchaseScreenState extends BaseState {
// TODO: Удалить дублирующийся код.
void buildFocusNode() {
-
var pos = this.coupons.length > 0 ? 150.0 : 100.0;
sumFocusNode.addListener(() {
setState(() {
-
- if (sumFocusNode.hasFocus && bonusFocusNode.hasFocus) {
- bonusFocusNode.unfocus();
- }
-
if (sumFocusNode.hasFocus) {
- scrollController.animateTo(pos, duration: new Duration(seconds: 1), curve: Curves.ease);
+ sumFocusNode.unfocus();
}
-
});
});
bonusFocusNode.addListener(() {
setState(() {
-
- if (bonusFocusNode.hasFocus && sumFocusNode.hasFocus) {
- sumFocusNode.unfocus();
- }
-
if (bonusFocusNode.hasFocus) {
- scrollController.animateTo(pos, duration: new Duration(seconds: 1), curve: Curves.ease);
+ scrollController.animateTo(pos,
+ duration: new Duration(seconds: 1), curve: Curves.ease);
}
-
});
});
}
diff --git a/lib/screens/purchase_success.dart b/lib/screens/purchase_success.dart
index ea99793..5f92556 100644
--- a/lib/screens/purchase_success.dart
+++ b/lib/screens/purchase_success.dart
@@ -2,6 +2,7 @@ import 'package:checker/base/base_state.dart';
import 'package:checker/common.dart';
import 'package:checker/consts.dart';
import 'package:checker/db.dart';
+import 'package:checker/screens/purchase_sum.dart';
import 'package:checker/strings.dart';
import 'package:flutter/material.dart';
@@ -133,7 +134,11 @@ class PurchaseSuccessScreenState extends BaseState {
getScanButton() {
String title = StringsLocalization.scan();
- return buildRaisedButton(title, () => Navigator.of(context).pop(token));
+ return buildRaisedButton(title,
+ () => Navigator.pushAndRemoveUntil(context,
+ MaterialPageRoute(builder: (context) =>
+ PurchaseSumScreen(widget.helper, widget.app, token)),
+ (route) => false));
}
diff --git a/lib/screens/purchase_sum.dart b/lib/screens/purchase_sum.dart
new file mode 100644
index 0000000..fb27dc9
--- /dev/null
+++ b/lib/screens/purchase_sum.dart
@@ -0,0 +1,204 @@
+import 'dart:convert';
+import 'dart:core';
+
+import 'package:checker/base/base_screen.dart';
+import 'package:checker/base/base_state.dart';
+import 'package:checker/common.dart';
+import 'package:checker/consts.dart';
+import 'package:checker/db.dart';
+import 'package:checker/network.dart';
+import 'package:checker/resources.dart';
+import 'package:checker/screens/purchase.dart';
+import 'package:checker/strings.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:http/http.dart';
+
+/// Экран ввода суммы покупки
+class PurchaseSumScreen extends BaseScreen {
+ PurchaseSumScreen(helper, app, this.token) : super(helper, app);
+
+ final String token;
+
+ @override
+ State createState() =>
+ new PurchaseSumScreenState(helper, app);
+}
+
+class PurchaseSumScreenState extends BaseState {
+ TextEditingController _sumController = new TextEditingController();
+
+ bool isAutomaticallyImplyLeading() => false;
+
+ PurchaseSumScreenState(SqliteHelper helper, String app) : super(helper, app);
+
+ @override
+ void initState() {
+ super.initState();
+ _subscribe();
+ }
+
+ @override
+ Widget build(BuildContext ctx) {
+ return getMainWidget();
+ }
+
+ @override
+ Widget getScreenContent() => Column(
+ children: [
+ getHintLabel(),
+ getInputField(),
+ wrapButton(
+ _getScreenMargins(24.0),
+ getScanButton(context, StringsLocalization.scan(),
+ Resources.getPrimaryColor(app)))
+ ],
+ );
+
+ EdgeInsets _getScreenMargins(double top) {
+ double side = 42.0;
+ return new EdgeInsets.only(top: top, left: side, right: side);
+ }
+
+ Widget getScanButton(BuildContext context, String title, Color textColor) {
+ return new Container(
+ height: buttonHeight,
+ child: new FlatButton(
+ child: new Text(title, style: new TextStyle(color: textColor)),
+ onPressed: () => _startScanner()),
+ decoration: new BoxDecoration(
+ border: new Border.all(
+ color: Resources.getButtonColor(app), width: 1.0),
+ borderRadius: new BorderRadius.all(new Radius.circular(4.0))));
+ }
+
+ void _startScanner() {
+ platform.invokeMethod('getEndpoint').then((url) {
+ platform.invokeMethod('getAppToken').then((appToken) {
+ Map args = StringsLocalization.strings;
+ args['token'] = widget.token;
+ args['url'] = url;
+ args['appToken'] = appToken;
+ args['localeCode'] = StringsLocalization.localeCode;
+ args['color'] = Resources.getPrimaryColor(app).value.toString();
+ platform.invokeMethod('startScanner', args).then((result) {
+ _processResult(result);
+ });
+ });
+ });
+ }
+
+ @override
+ String getTitle() {
+ return StringsLocalization.sum();
+ }
+
+ @override
+ getHintString() {
+ return StringsLocalization.sum();
+ }
+
+ @override
+ getTextWidget() {
+ return new TextField(
+ keyboardType: TextInputType.number,
+ decoration: new InputDecoration.collapsed(
+ hintText: getHintString(),
+ hintStyle: new TextStyle(color: greyTextColor, fontSize: 16.0)),
+ controller: _sumController,
+ onSubmitted: (String text) {
+ setState(() {
+ _sumController.text = _parseSum(text);
+ });
+ },
+ textAlign: TextAlign.center);
+ }
+
+ String _cleanupNumber(String text) {
+ String tmp = text
+ .replaceAll(' ', '')
+ .replaceAll('-', '')
+ .replaceAll(',', '.')
+ .replaceAll('..', '.');
+
+ while (tmp.indexOf('..') != -1) {
+ tmp = tmp.replaceAll('..', '.');
+ }
+ return tmp;
+ }
+
+ String _parseSum(String input) {
+ num sumTotal = 0.0;
+ String text = _cleanupNumber(input);
+
+ try {
+ sumTotal = num.parse(text);
+ } catch (exception) {
+ print(exception);
+ try {
+ int idx = text.indexOf('.');
+ String integerPart = text.substring(0, idx);
+ String fractionalPart = text.substring(idx + 1, text.length);
+ if (fractionalPart.length > 2) {
+ fractionalPart = fractionalPart.substring(0, 2);
+ }
+ return '$integerPart.$fractionalPart';
+ } catch (exception) {
+ print(exception);
+ }
+ }
+ print(sumTotal.toStringAsFixed(2));
+ return sumTotal.toStringAsFixed(2);
+ }
+
+ void _processResult(result) {
+ if (result is List) {
+ final String user = result[0] as String;
+ final String card = result[1] as String;
+ Navigator.of(context).push(new MaterialPageRoute(builder: (context) {
+ String sum = _parseSum(_sumController.text);
+ _sumController.text = "";
+ return PurchaseScreen(helper, app, user, card, sum);
+ }));
+ }
+ }
+
+ void _subscribe() async {
+ platform.setMethodCallHandler((MethodCall call) async {
+ print('Received method chanell call');
+ if (call.method == 'findUser') {
+ try {
+ Response userResponse;
+
+ switch (call.arguments[1]) {
+ case 'card':
+ userResponse =
+ await getUserByCard(call.arguments[0], widget.token);
+ break;
+ case 'phone':
+ userResponse =
+ await getUserByPhone(call.arguments[0], widget.token);
+ break;
+ }
+
+ if (userResponse != null) {
+ print('I have user in method handler!');
+ List users = json.decode(userResponse.body);
+ if (users.length > 0) {
+ return json.encode(users[0]);
+ } else {
+ throw new FlutterError("Users not found");
+ }
+ } else {
+ throw new FlutterError("Users not found");
+ }
+ } catch (error) {
+ print(error.toString());
+ throw new FlutterError("Users not found");
+ }
+ } else if (call.method == 'scanSuccess') {
+ _processResult(call.arguments);
+ }
+ });
+ }
+}
diff --git a/lib/screens/splash.dart b/lib/screens/splash.dart
index ba047a9..bde6283 100644
--- a/lib/screens/splash.dart
+++ b/lib/screens/splash.dart
@@ -11,6 +11,7 @@ import 'package:checker/resources.dart';
import 'package:checker/screens/faq.dart';
import 'package:checker/screens/finish_registration.dart';
import 'package:checker/screens/purchase.dart';
+import 'package:checker/screens/purchase_sum.dart';
import 'package:checker/screens/registration.dart';
import 'package:checker/screens/settings.dart';
import 'package:checker/strings.dart';
@@ -240,23 +241,13 @@ class _SplashScreenState extends BaseState {
: json.encode(call.arguments[0]);
print(userString);
String card = call.arguments[1];
- showNextScreen(new PurchaseScreen(helper, app, userString, card));
+ showNextScreen(new PurchaseScreen(helper, app, userString, card, null));
}
});
- platform.invokeMethod('getEndpoint').then((url) {
- platform.invokeMethod('getAppToken').then((appToken) {
- Map args = StringsLocalization.strings;
- args['token'] = token;
- args['url'] = url;
- args['appToken'] = appToken;
- args['localeCode'] = StringsLocalization.localeCode;
- args['color'] = Resources
- .getPrimaryColor(app)
- .value
- .toString();
- platform.invokeMethod('startScanner', args);
- });
- });
+ Navigator.of(context).pushReplacement(
+ MaterialPageRoute(builder: (context) =>
+ PurchaseSumScreen(helper, app, token))
+ );
}
}
diff --git a/lib/strings.dart b/lib/strings.dart
index 08ce633..ddae94b 100644
--- a/lib/strings.dart
+++ b/lib/strings.dart
@@ -1,22 +1,24 @@
import 'dart:async';
+
+import 'package:flutter/services.dart';
import 'package:sprintf/sprintf.dart';
import 'package:xml/xml.dart' as xml;
-import 'package:flutter/services.dart';
class StringsLocalization {
-
static String localeCode;
static Map strings = new Map();
static Future load(String l) async {
localeCode = l;
- await rootBundle.loadString('assets/values-$localeCode/strings.xml').then((content) {
+ await rootBundle
+ .loadString('assets/values-$localeCode/strings.xml')
+ .then((content) {
content.replaceAll('=\"', '=\\"');
content.replaceAll('\">', '\\">"');
var document = xml.parse(content);
strings.clear();
document.findAllElements('string').forEach((node) {
- strings[node.attributes[0].value] = node.text.toString();
+ strings[node.attributes[0].value] = node.text.toString();
});
});
return strings;
@@ -111,25 +113,45 @@ class StringsLocalization {
return [nominative, singular, plural];
}
+ static _normalizeDouble(String val) => val.substring(0, val.length - 3);
static String confirmPurchase(String val, int code) {
- String trimmedVal = val.substring(0, val.length - 3);
- return sprintf(strings['confirm_purchase'], [val, declineCurrency(int.parse(trimmedVal), code)]);
+ String trimmedVal = _normalizeDouble(val);
+ return sprintf(strings['confirm_purchase'],
+ [val, declineCurrency(int.parse(trimmedVal), code)]);
}
static String purchaseCompleted(String val, int code) {
- String trimmedVal = val.substring(0, val.length - 3);
- return sprintf(strings['purchase_complite'], [val, declineCurrency(int.parse(trimmedVal), code)]);
+ String trimmedVal = _normalizeDouble(val);
+ return sprintf(strings['purchase_complite'],
+ [val, declineCurrency(int.parse(trimmedVal), code)]);
}
+
static String paymentCompleted(String val, int code) {
String trimmedVal = val.substring(0, val.length - 3);
- return sprintf(strings['payment_complite'], [val, declineCurrency(int.parse(trimmedVal), code)]);
+ return sprintf(strings['payment_complite'],
+ [val, declineCurrency(int.parse(trimmedVal), code)]);
}
+
static String returnConfirmation(String sum, String date, int points) =>
- sprintf(strings['return_purchase_content'], [sum, date, points.toString()]);
+ sprintf(
+ strings['return_purchase_content'], [sum, date, points.toString()]);
static String returnConfirmedContent(String sum, String date) =>
- sprintf(strings['return_confirmation_content'], [sum, date]);
+ sprintf(strings['return_confirmation_content'], [sum, date]);
+
+ static String purchaseDetails(
+ String total, String discountTotal, String discount, int code) {
+ final String normTotal = _normalizeDouble(total);
+ final String normDiscountTotal = _normalizeDouble(discountTotal);
+ return sprintf(strings['purchase_details'], [
+ total,
+ declineCurrency(int.parse(normTotal), code),
+ discountTotal,
+ declineCurrency(int.parse(normDiscountTotal), code),
+ discount
+ ]);
+ }
static String registration() => strings['registration'];
static String usage() => strings['usage'];
@@ -142,7 +164,8 @@ class StringsLocalization {
static String askChangeStore() => strings['ask_change_store'];
static String yes() => strings['yes'];
static String no() => strings['no'];
- static String requestSentWaitActivation() => strings['request_sent_wait_activ'];
+ static String requestSentWaitActivation() =>
+ strings['request_sent_wait_activ'];
static String refreshActivationStatus() => strings['update_activ_status'];
static String appActivated() => strings['app_activ'];
static String completeRegistration() => strings['complite_activ'];
@@ -218,7 +241,8 @@ class StringsLocalization {
static String registrationGuide() => strings['registration_guide'];
static String usageGuide() => strings['usage_guide'];
static String commonGuide() => strings['common_guide'].replaceAll('\n', "\n");
- static String supportGuide(String phone, String url) => sprintf(strings['support_guide'], [phone, url]);
+ static String supportGuide(String phone, String url) =>
+ sprintf(strings['support_guide'], [phone, url]);
static String joys() => strings['joys'];
static String joysMinus() => strings['joys_minus'];
static String joysHint() => strings['joys_hint'];
@@ -226,4 +250,6 @@ class StringsLocalization {
static String returnLabel() => strings['returnLabel'];
static String returnConfirmed() => strings['return_confirmation'];
static String points() => strings['points'];
- }
+ static String cancel() => strings['cancel'];
+ static String cancelDialog() => strings['purchase_cancellation'];
+}
diff --git a/pubspec.lock b/pubspec.lock
index f06d8c4..fd4a58b 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -1,5 +1,5 @@
# Generated by pub
-# See https://www.dartlang.org/tools/pub/glossary#lockfile
+# See https://dart.dev/tools/pub/glossary#lockfile
packages:
async:
dependency: transitive
@@ -61,7 +61,7 @@ packages:
name: meta
url: "https://pub.dartlang.org"
source: hosted
- version: "1.1.6"
+ version: "1.1.7"
path:
dependency: transitive
description:
@@ -166,5 +166,5 @@ packages:
source: hosted
version: "3.2.3"
sdks:
- dart: ">=2.0.0 <3.0.0"
+ dart: ">=2.2.2 <3.0.0"
flutter: ">=0.1.4 <2.0.0"