Merge branch 'RG-3434'
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:checker/resources.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
import 'common.dart';
|
||||
import 'consts.dart';
|
||||
@@ -9,6 +11,9 @@ import 'strings.dart';
|
||||
|
||||
abstract class BaseState<T extends StatefulWidget> extends State<T> {
|
||||
|
||||
/// Тип сборки. Определяет, какие брать ресурсы (цвета, картинки)
|
||||
String app;
|
||||
|
||||
/// Ожидание ответа от сервера.
|
||||
bool loading = false;
|
||||
|
||||
@@ -19,13 +24,42 @@ abstract class BaseState<T extends StatefulWidget> extends State<T> {
|
||||
String textFieldValue = '';
|
||||
|
||||
@override Widget build(BuildContext ctx) {
|
||||
return new Scaffold(appBar: getAppBar(),
|
||||
|
||||
platform.invokeMethod('getLocale').then((locale) {
|
||||
Intl.defaultLocale = locale;
|
||||
if (app == null) {
|
||||
platform.invokeMethod('getFlavor').then((flavor) {
|
||||
setState(() {
|
||||
app = flavor;
|
||||
onStart();
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return getMainWidget();
|
||||
}
|
||||
|
||||
Widget getMainWidget() {
|
||||
return app == null ? getBackground() : new Scaffold(appBar: getAppBar(),
|
||||
body: new Stack(children: <Widget>[
|
||||
getScreenContent(),
|
||||
new Center(child: loading ? new CircularProgressIndicator() : null)
|
||||
]));
|
||||
}
|
||||
|
||||
Widget getBackground() {
|
||||
return new Container(
|
||||
decoration: new BoxDecoration(
|
||||
image: new DecorationImage(
|
||||
image: new ExactAssetImage(Resources.getSplash(app)),
|
||||
fit: BoxFit.cover)));
|
||||
}
|
||||
|
||||
void onStart() {
|
||||
|
||||
}
|
||||
|
||||
/// Возвращает контейнер с всеми виджетами экрана.
|
||||
Widget getScreenContent();
|
||||
|
||||
@@ -34,7 +68,7 @@ abstract class BaseState<T extends StatefulWidget> extends State<T> {
|
||||
|
||||
AppBar getAppBar() {
|
||||
return new AppBar(title: new Text(getTitle(), style: new TextStyle(fontSize: 18.0)),
|
||||
backgroundColor: primaryColor, actions: getMenuButtons());
|
||||
backgroundColor: Resources.getPrimaryColor(app), actions: getMenuButtons());
|
||||
}
|
||||
|
||||
List<Widget> getMenuButtons() {
|
||||
@@ -55,7 +89,7 @@ abstract class BaseState<T extends StatefulWidget> extends State<T> {
|
||||
return new Container(margin: new EdgeInsets.only(top: horizontalMargin, bottom: horizontalMargin, left: verticalMargin, right: verticalMargin),
|
||||
child: new Row(crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[new Text(getHintString(), textAlign: TextAlign.left,
|
||||
style: new TextStyle(fontWeight: FontWeight.w300, color: error == null ? greyTextColor : primaryColor, fontSize: 14.0))]));
|
||||
style: new TextStyle(fontWeight: FontWeight.w300, color: error == null ? greyTextColor : Resources.getLogo(app), fontSize: 14.0))]));
|
||||
}
|
||||
|
||||
/// Возвращает подсказку, либо ошибку, если введенные в поле ввода данные неверны.
|
||||
@@ -118,14 +152,14 @@ abstract class BaseState<T extends StatefulWidget> extends State<T> {
|
||||
return new RaisedButton(child: new Text(text,
|
||||
style: new TextStyle(color: Colors.white)),
|
||||
onPressed: onPressed,
|
||||
color: primaryColor);
|
||||
color: Resources.getButtonColor(app));
|
||||
}
|
||||
|
||||
/// Метод возвращает контейнер с отступами, который содержит картинку с логотипом.
|
||||
Widget getLogo() {
|
||||
double containerHeight = 92.0;
|
||||
double imageWidth = 156.0;
|
||||
return new Container(height: containerHeight, child: new Image.asset(logo_png, width: imageWidth));
|
||||
return new Container(height: containerHeight, child: new Image.asset(Resources.getLogo(app), width: imageWidth));
|
||||
}
|
||||
|
||||
/// Возвращает текстовое поле, с однострочным пояснением над ним.
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
|
||||
|
||||
import 'consts.dart';
|
||||
import 'network.dart';
|
||||
import 'resources.dart';
|
||||
import 'package:checker/registration.dart';
|
||||
import 'package:checker/purchase.dart';
|
||||
import 'faq.dart';
|
||||
@@ -62,7 +63,7 @@ forceLogout(BuildContext context) async {
|
||||
|
||||
/// Запуск спецефичной для каждой платформы части приложения - сканера.
|
||||
/// Может производиться с нескольких экранов (splash, finish_registration).
|
||||
startScanner(BuildContext context) async {
|
||||
startScanner(BuildContext context, String app) async {
|
||||
|
||||
String token = await platform.invokeMethod('getToken');
|
||||
// Канал ловит вызовы методов из "нативной" части приложения.
|
||||
@@ -88,6 +89,7 @@ startScanner(BuildContext context) async {
|
||||
'token' : token,
|
||||
'url': url,
|
||||
'appToken': appToken,
|
||||
'color': Resources.getPrimaryColor(app).value
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,8 +7,6 @@ const String url = 'https://pos-api-autoclub.dinect.com/20130701/';
|
||||
const String appToken = 'bdea0f3ba9034b688019a7cac753d1209e2b227f';
|
||||
|
||||
// Assets
|
||||
const String logo_png = 'assets/registration_logo.png';
|
||||
const String splash_png = 'assets/splash.png';
|
||||
const String logout_png = 'assets/logout.png';
|
||||
const String activate_token_bg_png = 'assets/activate_token_message_background.png';
|
||||
const String active_token_bg_png = 'assets/active_token_message_background.png';
|
||||
@@ -17,8 +15,6 @@ const String powered_by_dinect_splash_png = 'assets/powered_by_dinect_splash.png
|
||||
const String powered_by_dinect_png = 'assets/powered_by_dinect.png';
|
||||
const String splash_text_png = 'assets/splash_text.png';
|
||||
|
||||
// Colors
|
||||
const Color primaryColor = const Color(0xffeb0004);
|
||||
const Color greyTextColor = const Color(0xffa5a5a5);
|
||||
const Color textBorderColor = const Color(0xffcfd8dc);
|
||||
const Color tokenActiveTextColor = const Color(0xff1f5a1f);
|
||||
@@ -27,6 +23,7 @@ const Color greenBackground = const Color(0xff8ae28a);
|
||||
const Color faqGrey = const Color(0xff5b5b5b);
|
||||
const Color faqTitlesColor = const Color(0xff404040);
|
||||
const Color inputFieldBackground = const Color(0xffefefef);
|
||||
|
||||
// Dimens
|
||||
const double verticalMargin = 28.0;
|
||||
const double buttonHeight = 48.0;
|
||||
|
||||
@@ -68,7 +68,7 @@ class FAQScreenState<T> extends BaseState<FAQScreen> {
|
||||
|
||||
onWillPop() {
|
||||
if(returnToScanner) {
|
||||
return startScanner(context);
|
||||
return startScanner(context, app);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ class _RegistrationScreenState extends BaseState<FinishRegistrationScreen> {
|
||||
// Если нет, то отправляется запрос на проверку статуса токена.
|
||||
handleTap() async {
|
||||
if (_tokenActive) {
|
||||
startScanner(context);
|
||||
startScanner(context, app);
|
||||
} else {
|
||||
if (await platform.invokeMethod('isOnline')) {
|
||||
String token = await platform.invokeMethod('getToken');
|
||||
|
||||
@@ -3,12 +3,13 @@ import 'package:flutter/services.dart';
|
||||
import 'dart:convert';
|
||||
import 'dart:core';
|
||||
|
||||
import 'package:checker/strings.dart';
|
||||
import 'package:checker/common.dart';
|
||||
import 'package:checker/consts.dart';
|
||||
import 'package:checker/network.dart';
|
||||
import 'package:checker/base_state.dart';
|
||||
import 'package:checker/purchase_success.dart';
|
||||
import 'resources.dart';
|
||||
import 'strings.dart';
|
||||
import 'common.dart';
|
||||
import 'consts.dart';
|
||||
import 'network.dart';
|
||||
import 'base_state.dart';
|
||||
import 'purchase_success.dart';
|
||||
|
||||
/// Экран проведения покупки.
|
||||
class PurchaseScreen extends StatefulWidget {
|
||||
@@ -41,15 +42,15 @@ class PurchaseScreenState<T> extends BaseState<PurchaseScreen> {
|
||||
|
||||
@override Widget getScreenContent() {
|
||||
return new Column(
|
||||
children: <Widget>[new Expanded(child: new ListView(children: <Widget>[
|
||||
getValueWithDescription(StringsLocalization.userName(), user['first_name'] == null ? '' : user['first_name']),
|
||||
getValueWithDescription(StringsLocalization.card(), card),
|
||||
getValueWithDescription(StringsLocalization.reward(), loyalty),
|
||||
getHintLabel(),
|
||||
getInputField(),
|
||||
wrapButton(getScreenMargins(36.0), getCompleteButton()),
|
||||
wrapButton(getScreenMargins(24.0), getScanButton(context, StringsLocalization.scan(), primaryColor))
|
||||
]))]);
|
||||
children: <Widget>[new Expanded(child: new ListView(children: <Widget>[
|
||||
getValueWithDescription(StringsLocalization.userName(), user['first_name'] == null ? '' : user['first_name']),
|
||||
getValueWithDescription(StringsLocalization.card(), card),
|
||||
getValueWithDescription(StringsLocalization.reward(), loyalty),
|
||||
getHintLabel(),
|
||||
getInputField(),
|
||||
wrapButton(getScreenMargins(36.0), getCompleteButton()),
|
||||
wrapButton(getScreenMargins(24.0), getScanButton(context, StringsLocalization.scan(), Resources.getPrimaryColor(app)))
|
||||
]))]);
|
||||
}
|
||||
|
||||
getScreenMargins(double top) {
|
||||
@@ -62,16 +63,16 @@ class PurchaseScreenState<T> extends BaseState<PurchaseScreen> {
|
||||
}
|
||||
|
||||
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(context)),
|
||||
decoration: getDecorationForScanButton());
|
||||
}
|
||||
|
||||
getDecorationForScanButton() {
|
||||
return new BoxDecoration(
|
||||
border: new Border.all(color: primaryColor, width: 1.0),
|
||||
borderRadius: new BorderRadius.all(new Radius.circular(4.0)));
|
||||
return new Container(
|
||||
height: buttonHeight,
|
||||
child: new FlatButton(
|
||||
child: new Text(
|
||||
title,
|
||||
style: new TextStyle(color: textColor)),
|
||||
onPressed: () => startScanner(context, app)),
|
||||
decoration: new BoxDecoration(
|
||||
border: new Border.all(color: Resources.getButtonColor(app), width: 1.0),
|
||||
borderRadius: new BorderRadius.all(new Radius.circular(4.0))));
|
||||
}
|
||||
|
||||
@override String getTitle() {
|
||||
@@ -88,19 +89,19 @@ class PurchaseScreenState<T> extends BaseState<PurchaseScreen> {
|
||||
|
||||
@override getTextWidget() {
|
||||
return new TextField(
|
||||
keyboardType: TextInputType.number,
|
||||
decoration: new InputDecoration.collapsed(
|
||||
keyboardType: TextInputType.number,
|
||||
decoration: new InputDecoration.collapsed(
|
||||
hintText: getHint(),
|
||||
hintStyle: new TextStyle(color: greyTextColor, fontSize: 16.0)
|
||||
),
|
||||
controller: controller,
|
||||
onSubmitted: (String text) {
|
||||
setState(() {
|
||||
controller.text = _parseSum(text);
|
||||
});
|
||||
},
|
||||
textAlign: TextAlign.center,
|
||||
autofocus: true,
|
||||
),
|
||||
controller: controller,
|
||||
onSubmitted: (String text) {
|
||||
setState(() {
|
||||
controller.text = _parseSum(text);
|
||||
});
|
||||
},
|
||||
textAlign: TextAlign.center,
|
||||
autofocus: true,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -138,10 +139,10 @@ class PurchaseScreenState<T> extends BaseState<PurchaseScreen> {
|
||||
|
||||
String _cleanupNumber(String text){
|
||||
String tmp = text
|
||||
.replaceAll(' ', '')
|
||||
.replaceAll('-', '')
|
||||
.replaceAll(',', '.')
|
||||
.replaceAll('..', '.');
|
||||
.replaceAll(' ', '')
|
||||
.replaceAll('-', '')
|
||||
.replaceAll(',', '.')
|
||||
.replaceAll('..', '.');
|
||||
|
||||
while(tmp.indexOf('..') != -1){
|
||||
tmp = tmp.replaceAll('..', '.');
|
||||
@@ -175,22 +176,22 @@ class PurchaseScreenState<T> extends BaseState<PurchaseScreen> {
|
||||
onPurchaseClick() {
|
||||
String val = _parseSum(controller.text);
|
||||
showDialog(context: context, child: new AlertDialog(
|
||||
title: new Text(StringsLocalization.confirmation()),
|
||||
content: new Text(StringsLocalization.confirmPurchase(val)),
|
||||
actions: <Widget>[
|
||||
new FlatButton(
|
||||
child: new Text(StringsLocalization.no()),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
new FlatButton(
|
||||
child: new Text(StringsLocalization.yes()),
|
||||
onPressed: () {
|
||||
purchase(val);
|
||||
},
|
||||
)
|
||||
]));
|
||||
title: new Text(StringsLocalization.confirmation()),
|
||||
content: new Text(StringsLocalization.confirmPurchase(val)),
|
||||
actions: <Widget>[
|
||||
new FlatButton(
|
||||
child: new Text(StringsLocalization.no()),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
new FlatButton(
|
||||
child: new Text(StringsLocalization.yes()),
|
||||
onPressed: () {
|
||||
purchase(val);
|
||||
},
|
||||
)
|
||||
]));
|
||||
}
|
||||
|
||||
purchase(String sumTotal) async {
|
||||
@@ -201,30 +202,30 @@ class PurchaseScreenState<T> extends BaseState<PurchaseScreen> {
|
||||
String token = await platform.invokeMethod('getToken');
|
||||
platform.invokeMethod('getDocID').then((result) {
|
||||
|
||||
String url = user['purchases_url'];
|
||||
String url = user['purchases_url'];
|
||||
|
||||
var body = {
|
||||
'doc_id': result,
|
||||
'curr_iso_code': '643',
|
||||
'commit': 'true',
|
||||
'sum_total': sumTotal
|
||||
};
|
||||
var body = {
|
||||
'doc_id': result,
|
||||
'curr_iso_code': '643',
|
||||
'commit': 'true',
|
||||
'sum_total': sumTotal
|
||||
};
|
||||
|
||||
var headers = {
|
||||
'DM-Authorization': 'dmapptoken $appToken',
|
||||
'Authorization': 'dmtoken ${token}'
|
||||
};
|
||||
var headers = {
|
||||
'DM-Authorization': 'dmapptoken $appToken',
|
||||
'Authorization': 'dmtoken ${token}'
|
||||
};
|
||||
|
||||
httpClient.post(url, body: body, headers: headers).then((response) {
|
||||
httpClient.post(url, body: body, headers: headers).then((response) {
|
||||
|
||||
print(response.body);
|
||||
Navigator.of(context).pop();
|
||||
pushRoute(context, new PurchaseSuccessScreen(sumTotal, user['first_name'] == null ? '' : user['first_name']));
|
||||
print(response.body);
|
||||
Navigator.of(context).pop();
|
||||
pushRoute(context, new PurchaseSuccessScreen(sumTotal, user['first_name'] == null ? '' : user['first_name']));
|
||||
|
||||
}).catchError((error) {
|
||||
purchaseInProgress = false;
|
||||
print(error.toString());
|
||||
});
|
||||
}).catchError((error) {
|
||||
purchaseInProgress = false;
|
||||
print(error.toString());
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ class PurchaseSuccessScreenState<T> extends BaseState<PurchaseSuccessScreen> {
|
||||
|
||||
getScanButton() {
|
||||
String title = StringsLocalization.scan();
|
||||
return buildRaisedButton(title, () => startScanner(context));
|
||||
return buildRaisedButton(title, () => startScanner(context, app));
|
||||
}
|
||||
|
||||
getSuccessMessage() {
|
||||
|
||||
28
lib/resources.dart
Normal file
28
lib/resources.dart
Normal file
@@ -0,0 +1,28 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class Resources {
|
||||
|
||||
static String getLogo(String app) {
|
||||
return app == null ? null : 'assets/${app}_logo.png';
|
||||
}
|
||||
|
||||
static String getSplash(String app) {
|
||||
return 'assets/${app != null ? app : 'pip'}_splash.png';
|
||||
}
|
||||
|
||||
static Color getPrimaryColor(String app) {
|
||||
switch (app) {
|
||||
case 'pip': return new Color(0xff008794);
|
||||
case 'autobonus': return new Color(0xffeb0004);
|
||||
default: return new Color(0xffffffff);
|
||||
}
|
||||
}
|
||||
|
||||
static Color getButtonColor(String app) {
|
||||
switch (app) {
|
||||
case 'pip': return new Color(0xfff49935);
|
||||
case 'autobonus': return new Color(0xffeb0004);
|
||||
default: return new Color(0xffffffff);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,49 +1,70 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'dart:async';
|
||||
import 'common.dart';
|
||||
import 'network.dart';
|
||||
import 'consts.dart';
|
||||
import 'registration.dart';
|
||||
import 'finish_registration.dart';
|
||||
import 'strings.dart';
|
||||
import 'resources.dart';
|
||||
import 'base_state.dart';
|
||||
|
||||
class SplashScreen extends StatelessWidget {
|
||||
class SplashScreen extends StatefulWidget {
|
||||
@override State createState() => new _SplashScreenState();
|
||||
}
|
||||
|
||||
class _SplashScreenState extends BaseState<SplashScreen> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// Появляется splash screen, проверяется токен.
|
||||
Widget getScreenContent() {
|
||||
return app == null
|
||||
? getBackground()
|
||||
: new Stack(
|
||||
children: <Widget>[
|
||||
getBackground(),
|
||||
getLogo(),
|
||||
new Align(
|
||||
alignment: FractionalOffset.bottomRight,
|
||||
child: new Container(
|
||||
margin: new EdgeInsets.only(
|
||||
right: 11.0,
|
||||
bottom: 5.0),
|
||||
child: new Image.asset(powered_by_dinect_splash_png,
|
||||
height: 16.0,
|
||||
width: 122.0)))]);
|
||||
}
|
||||
|
||||
new Future.delayed(const Duration(milliseconds: 500), () {
|
||||
platform.invokeMethod("getLocale").then((locale) {
|
||||
Intl.defaultLocale = locale;
|
||||
print(Intl.defaultLocale);
|
||||
showNextScreen(context);
|
||||
});
|
||||
@override Widget getMainWidget() {
|
||||
return getScreenContent();
|
||||
}
|
||||
|
||||
@override
|
||||
String getTitle() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@override void onStart() {
|
||||
new Future.delayed(const Duration(milliseconds: 1000), () {
|
||||
showNextScreen(context);
|
||||
});
|
||||
|
||||
return new Stack(children: <Widget>[getSplashBackground(), getLogo(),
|
||||
new Align(alignment: FractionalOffset.bottomRight, child:
|
||||
new Container(margin: new EdgeInsets.only(right: 11.0, bottom: 5.0), child:
|
||||
new Image.asset(powered_by_dinect_splash_png, height: 16.0, width: 122.0)))]);
|
||||
}
|
||||
|
||||
/// Возвращает столбец с логотипом приложения и текстом под ним.
|
||||
/// Столбец занимает не все доступное пространство, а необходимый минимум в центре экрана.
|
||||
getLogo() {
|
||||
return new Center(child: new Column(mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[new Image.asset(logo_png, height: 112.0, width: 252.0),
|
||||
new Image.asset(splash_text_png, height: 40.0, width: 240.0)]));
|
||||
}
|
||||
|
||||
/// Возвращает контейнер, который содержит decoration с фоновым изображением.
|
||||
getSplashBackground() {
|
||||
return new Container(decoration:
|
||||
new BoxDecoration(image:
|
||||
new DecorationImage(image: new ExactAssetImage(splash_png), fit: BoxFit.cover)));
|
||||
return new Center(
|
||||
child: new Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
new Image.asset(
|
||||
Resources.getLogo(app),
|
||||
height: 112.0,
|
||||
width: 252.0),
|
||||
new Image.asset(
|
||||
splash_text_png,
|
||||
height: 40.0,
|
||||
width: 240.0)]));
|
||||
}
|
||||
|
||||
/// Запуск следующего экрана приложения.
|
||||
@@ -85,7 +106,7 @@ class SplashScreen extends StatelessWidget {
|
||||
bool active = status['active'] == null ? false : status['active'];
|
||||
|
||||
if (active) {
|
||||
startScanner(context);
|
||||
startScanner(context, app);
|
||||
} else {
|
||||
if (await platform.invokeMethod('isOnline')) {
|
||||
_createToken(context);
|
||||
|
||||
Reference in New Issue
Block a user