From ff8ddf43348f1c645aa097c8b1556ebf827be7e3 Mon Sep 17 00:00:00 2001 From: Ivan Murashov Date: Tue, 18 Jul 2017 16:49:47 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B0=20=D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80=D0=BA=D0=B0?= =?UTF-8?q?=20=D1=81=D1=82=D0=B0=D1=82=D1=83=D1=81=D0=B0=20=D1=82=D0=BE?= =?UTF-8?q?=D0=BA=D0=B5=D0=BD=D0=B0,=20=D0=BE=D0=B1=D1=80=D0=B0=D0=B1?= =?UTF-8?q?=D0=BE=D1=82=D0=BA=D0=B0=20=D1=81=D1=82=D0=B0=D1=82=D1=83=D1=81?= =?UTF-8?q?=D0=B0=20=D1=82=D0=BE=D0=BA=D0=B5=D0=BD=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- android/app/build.gradle | 2 +- android/app/src/main/AndroidManifest.xml | 8 +- .../checker/activity/CameraActivity.java | 6 +- .../dinect/checker/activity/MainActivity.java | 62 ++++++++--- .../service/RegistrationIntentService.java | 2 +- .../dinect/checker/view/CameraPreview.java | 2 +- assets/activate_token_message_background.png | Bin 0 -> 14502 bytes lib/activate_token.dart | 103 ++++++++++++++++++ lib/main.dart | 64 ++++++++++- lib/registration.dart | 54 ++++----- lib/splash.dart | 43 ++++++-- pubspec.yaml | 1 + 12 files changed, 287 insertions(+), 60 deletions(-) create mode 100644 assets/activate_token_message_background.png create mode 100644 lib/activate_token.dart diff --git a/android/app/build.gradle b/android/app/build.gradle index 0b26478..1ea1db3 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -25,7 +25,7 @@ android { defaultConfig { targetSdkVersion 21 testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" - applicationId "com.dinnect.checker" + applicationId "com.dinect.checker" } buildTypes { diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 2f27478..b28861b 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,5 +1,5 @@ @@ -18,7 +18,7 @@ additional functionality it is fine to subclass or reimplement FlutterApplication and put your custom class here. --> - - diff --git a/android/app/src/main/java/com/dinect/checker/activity/CameraActivity.java b/android/app/src/main/java/com/dinect/checker/activity/CameraActivity.java index 6564507..b61d425 100644 --- a/android/app/src/main/java/com/dinect/checker/activity/CameraActivity.java +++ b/android/app/src/main/java/com/dinect/checker/activity/CameraActivity.java @@ -1,4 +1,4 @@ -package com.dinnect.checker.activity; +package com.dinect.checker.activity; import android.app.Activity; import android.content.pm.ActivityInfo; @@ -29,8 +29,8 @@ import net.sourceforge.zbar.Symbol; import net.sourceforge.zbar.SymbolSet; import net.sourceforge.zbar.Config; -import com.dinnect.checker.R; -import com.dinnect.checker.view.CameraPreview; +import com.dinect.checker.R; +import com.dinect.checker.view.CameraPreview; public class CameraActivity extends Activity { diff --git a/android/app/src/main/java/com/dinect/checker/activity/MainActivity.java b/android/app/src/main/java/com/dinect/checker/activity/MainActivity.java index 18a13cd..a57c639 100644 --- a/android/app/src/main/java/com/dinect/checker/activity/MainActivity.java +++ b/android/app/src/main/java/com/dinect/checker/activity/MainActivity.java @@ -1,10 +1,12 @@ -package com.dinnect.checker.activity; +package com.dinect.checker.activity; import android.os.Bundle; +import android.content.Context; import android.content.Intent; import android.util.Log; -import com.dinnect.checker.activity.CameraActivity; -import com.dinnect.checker.service.RegistrationIntentService; +import android.content.SharedPreferences; +import com.dinect.checker.activity.CameraActivity; +import com.dinect.checker.service.RegistrationIntentService; import io.flutter.app.FlutterActivity; import io.flutter.plugins.GeneratedPluginRegistrant; @@ -16,32 +18,56 @@ import io.flutter.plugin.common.MethodChannel.Result; import com.google.android.gms.iid.InstanceID; +import java.util.Map; + public class MainActivity extends FlutterActivity { - private static final String INSTANCE_ID_CHANNEL = "com.dinnect.checker/instance_id"; + private static final String INSTANCE_ID_CHANNEL = "com.dinect.checker/instance_id"; + private static final String PREF_POS_TOKEN = "pref_pos_token"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); GeneratedPluginRegistrant.registerWith(this); + final SharedPreferences preferences = getPreferences(Context.MODE_PRIVATE); + new MethodChannel(getFlutterView(), INSTANCE_ID_CHANNEL).setMethodCallHandler( new MethodCallHandler() { @Override public void onMethodCall(MethodCall call, Result result) { - if (call.method.equals("getInstanceID")) { + switch (call.method) { - InstanceID instanceID = InstanceID.getInstance(MainActivity.this); - String id = instanceID.getId(); + case "getInstanceID": - if (id != null) { - result.success(id); - } else { - result.error("UNAVAILABLE", "Can't get instanceID.", null); - } + InstanceID instanceID = InstanceID.getInstance(MainActivity.this); + String id = instanceID.getId(); - } else { - result.notImplemented(); + if (id != null) { + result.success(id); + } else { + result.error("UNAVAILABLE", "Can't get instanceID.", null); + } + break; + + case "saveToken": + Map arguments = call.arguments(); + String token = (String) arguments.get("token"); + Log.d("kifio", token); + preferences.edit().putString(PREF_POS_TOKEN, token).apply(); + break; + + case "getToken": + result.success(preferences.getString(PREF_POS_TOKEN, null)); + break; + + case "startScanner": + startActivity(new Intent(MainActivity.this, CameraActivity.class)); + break; + + default: + result.notImplemented(); + break; } } }); @@ -55,4 +81,12 @@ public class MainActivity extends FlutterActivity { } + public void saveToken() { + + } + + public void getToken() { + + } + } diff --git a/android/app/src/main/java/com/dinect/checker/service/RegistrationIntentService.java b/android/app/src/main/java/com/dinect/checker/service/RegistrationIntentService.java index 85e56d0..b801b26 100644 --- a/android/app/src/main/java/com/dinect/checker/service/RegistrationIntentService.java +++ b/android/app/src/main/java/com/dinect/checker/service/RegistrationIntentService.java @@ -1,4 +1,4 @@ -package com.dinnect.checker.service; +package com.dinect.checker.service; import android.app.IntentService; import android.content.Intent; diff --git a/android/app/src/main/java/com/dinect/checker/view/CameraPreview.java b/android/app/src/main/java/com/dinect/checker/view/CameraPreview.java index 68d0c22..040215e 100644 --- a/android/app/src/main/java/com/dinect/checker/view/CameraPreview.java +++ b/android/app/src/main/java/com/dinect/checker/view/CameraPreview.java @@ -1,4 +1,4 @@ -package com.dinnect.checker.view; +package com.dinect.checker.view; import java.io.IOException; diff --git a/assets/activate_token_message_background.png b/assets/activate_token_message_background.png new file mode 100644 index 0000000000000000000000000000000000000000..e852596827c6417b828360fe86657a1d02200160 GIT binary patch literal 14502 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 literal 0 HcmV?d00001 diff --git a/lib/activate_token.dart b/lib/activate_token.dart new file mode 100644 index 0000000..87bcebd --- /dev/null +++ b/lib/activate_token.dart @@ -0,0 +1,103 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'main.dart'; + +/// Экран регистрации магазина и кассы. +class FinishRegistrationScreen extends StatefulWidget { + @override State createState() => new _RegistrationScreenState(); +} + +class _RegistrationScreenState extends BaseState { + + @override Widget build(BuildContext context) { + return new Scaffold(appBar: _getAppBar(), body: _getScreen(context)); + } + + AppBar _getAppBar() { + return new AppBar(title: new Text("Регистрация магазина"), + backgroundColor: const Color(0xff4272e7), actions: [ + new IconButton( + icon: new Icon(Icons.help_outline), + tooltip: 'Air it', + onPressed: faq, + ), + new IconButton( + icon: new Image(height: 24.0, width: 24.0, image: new AssetImage(logout_png)), + tooltip: 'Restitch it', + onPressed: logout, + ) + ]); + } + + Widget _getScreen(BuildContext context) { + return new Center(child: new Column(children: [ + _getLogo(), + _getDecoratedInputField(merchantIDHint), + _getDecoratedInputField(posIDHint), + _getMessage(), + _getButton(context) + ])); + } + + Container _getLogo() { + return new Container(padding: new EdgeInsets.only(top: 16.0, bottom: 16.0), + child: new Image.asset(logo_png, height: 24.0, width: 156.0)); + } + + Container _getDecoratedInputField(String hint) { + return new Container( + padding: new EdgeInsets.only(left: 28.0, right: 28.0, top: 8.0), + child: new Container(height: 48.0, + padding: new EdgeInsets.only(left: 16.0, right: 16.0), + decoration: _getDecoraionForInputField(), + child: _getInputField(hint))) ; + } + + TextField _getInputField(String hint) { + return new TextField(decoration: new InputDecoration(hintText: hint, + hideDivider: true, + hintStyle: new TextStyle(color: const Color(0xffa5a5a5), + fontSize: 16.0)), onChanged: null); + } + + Container _getMessage() { + return new Container(padding: new EdgeInsets.only(top: 20.0, left: 26.0, right: 26.0), + child: new Container(height: 128.0, decoration: _getDecoraionForMessageField(), + padding: new EdgeInsets.only(top: 16.0, bottom: 8.0, left: 28.0, right: 28.0), + child: new Text('Запрос на активацию программы отправлен, дождитесь подтверждения активации администратором', + textAlign: TextAlign.center, style: new TextStyle(fontWeight: FontWeight.bold, color: const Color(0xff4e3a19))))); + } + + Decoration _getDecoraionForMessageField() { + return new BoxDecoration(image: new DecorationImage( + image: new ExactAssetImage(activate_token_bg_png), fit: BoxFit.fill)); + } + + Decoration _getDecoraionForInputField() { + return new BoxDecoration(color: Colors.white, + border: new Border.all( + color: const Color(0xffcfd8dc), width: 1.0,), + borderRadius: new BorderRadius.all(new Radius.circular(4.0))); + } + + Container _getButton(BuildContext context) { + return new Container(padding: new EdgeInsets.only(top: 36.0), + child: new Container(height: 64.0, padding: new EdgeInsets.all(8.0), + child: new RaisedButton(child: new Text('Обновить статус активации', + style: new TextStyle(color: Colors.white)), + onPressed: _checkToken(context), + disabledColor: const Color(0xffbfbfbf), + color: const Color(0xff3078c0)))); + } +} + +_checkToken(BuildContext context) { + checkToken(context, new CheckTokenCallback()); +} + +class CheckTokenCallback extends Callback { + + call(BuildContext context) { + startScanner(); + } +} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 9d82383..2953d10 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,17 +1,75 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'splash.dart'; +import 'dart:async'; +import 'dart:convert'; -const String _name = 'Ivan Murashov'; +/// Главный класс приложения. +/// Здесь распоосложены константы и некоторые методы, которые могут вызываться с разных экранов приложения. + +// Serious constants const String intUrl = 'https://pos-api-int.dinect.com/20130701/'; const String intToken = '9fec83cdca38c357e6b65dbb17514cdd36bf2a08'; +// Hints +const String merchantIDHint = 'ID магазина'; +const String posIDHint = 'Номер кассы'; + +// 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'; + final httpClient = createHttpClient(); void main() { runApp(new Checker()); } +/// Токен кассы. Инициализируется при регистрации. +String token; + +/// Проверка статуса токена. Токен может быть активирован, либо не активирован. +void checkToken(BuildContext context, Callback callback) { + + String url = intUrl + 'tokens/' + token + '?_dmapptoken=' + intToken; + print(url); + + httpClient.get(url).then((response) { + + print(response.body); + Map parsedMap = JSON.decode(response.body); + bool active = parsedMap['active']; + + if (!active) { + callback.call(context); + } else { + // Запускается экран сканера, токен кассы активирован, с его помощью можно делать запросы к pos-api. + startScanner(); + } + + }).catchError((error) { + print(error.toString()); + }); +} + +/// Запуск спецефичной для каждой платформы части приложения - сканера. +/// Может производиться с нескольких экранов (splash, finish_registration). +startScanner() async{ + const platform = const MethodChannel('com.dinect.checker/instance_id'); + await platform.invokeMethod('startScanner'); +} + +/// Навигация по приложению. +/// widget - следующий экран приложения. +pushRoute(BuildContext context, Widget widget) { + Navigator.of(context).push(new MaterialPageRoute( + builder: (BuildContext context) { + return widget; + })); +} + class Checker extends StatelessWidget { @override Widget build(BuildContext context) { return new MaterialApp(title: "DemoApp", home: new SplashScreen()); @@ -27,4 +85,8 @@ abstract class BaseState extends State { void logout() { } +} + +abstract class Callback { + void call(BuildContext context); } \ No newline at end of file diff --git a/lib/registration.dart b/lib/registration.dart index 0001a8d..144e12b 100644 --- a/lib/registration.dart +++ b/lib/registration.dart @@ -1,6 +1,8 @@ +import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'main.dart'; +import 'activate_token.dart'; /// Экран регистрации магазина и кассы. class RegistrationScreen extends StatefulWidget { @@ -9,14 +11,11 @@ class RegistrationScreen extends StatefulWidget { class _RegistrationScreenState extends BaseState { - static const String _merchantIDHint = 'ID магазина'; - static const String _posIDHint = 'Номер кассы'; - String _merchantID = ""; String _posID = ""; @override Widget build(BuildContext context) { - return new Scaffold(appBar: _getAppBar(), body: _getScreen()); + return new Scaffold(appBar: _getAppBar(), body: _getScreen(context)); } AppBar _getAppBar() { @@ -35,25 +34,19 @@ class _RegistrationScreenState extends BaseState { ]); } - Widget _getScreen() { - return new Center(child: new Column(children: _getChildren())); + Widget _getScreen(BuildContext context) { + return new Center(child: new Column(children: [ + _getLogo(), + _getDecoratedInputField(merchantIDHint, 0.0), + _getDecoratedInputField(posIDHint, 36.0), + _getButton(context) + ])); } - List _getChildren() { - return[ - _getLogo(), - _getDecoratedInputField(_merchantIDHint, 0.0), - _getDecoratedInputField(_posIDHint, 36.0), - _getButton() - ]; - } Container _getLogo() { return new Container(height: 192.0, - child: new Center( - child: new Image.asset('assets/registration_logo.png', - height: 24.0, - width: 156.0))); + child: new Image.asset(logo_png, height: 24.0, width: 156.0)); } Container _getDecoratedInputField(String hint, double topPadding) { @@ -75,9 +68,9 @@ class _RegistrationScreenState extends BaseState { void _handleUserInput(String hint, String text) { if (text.length > 0) { setState(() { - if (hint == _merchantIDHint) + if (hint == merchantIDHint) _merchantID = text; - else if (hint == _posIDHint) + else if (hint == posIDHint) _posID = text; }); } @@ -90,13 +83,14 @@ class _RegistrationScreenState extends BaseState { borderRadius: new BorderRadius.all(new Radius.circular(4.0))); } - Container _getButton() { + Container _getButton(BuildContext context) { return new Container(padding: new EdgeInsets.only(top: 36.0), child: new Container(height: 64.0, padding: new EdgeInsets.all(8.0), child: new RaisedButton(child: new Text('ЗАРЕГИСТРИРОВАТЬ', style: new TextStyle(color: Colors.white)), - onPressed: _isFieldsAreFilled() ? () => _register(_merchantID) : null, - disabledColor: const Color(0xffbfbfbf)))); + onPressed: _isFieldsAreFilled() ? () => _registerShop(context, _merchantID) : null, + disabledColor: const Color(0xffbfbfbf), + color: const Color(0xff3078c0)))); } _isFieldsAreFilled() { @@ -105,9 +99,13 @@ class _RegistrationScreenState extends BaseState { return _merchantID.length == 5 && _posID.length > 0; } - _register(String merchantShop) async { + void _registerShop(BuildContext context, String merchantShop) { + _register(context, merchantShop); + } - const platform = const MethodChannel('com.dinnect.checker/instance_id'); + _register(BuildContext context, String merchantShop) async { + + const platform = const MethodChannel('com.dinect.checker/instance_id'); String url = intUrl + 'tokens/?_dmapptoken=' + intToken; String pos = await platform.invokeMethod('getInstanceID'); print(pos); @@ -127,6 +125,12 @@ class _RegistrationScreenState extends BaseState { httpClient.post(url, body: body).then((response) { print(response.body); + Map parsedMap = JSON.decode(response.body); + token = parsedMap['token']; + platform.invokeMethod('saveToken', {'token' : token}).then((value) { + print(value.toString()); + }); + pushRoute(context, new FinishRegistrationScreen()); }).catchError((error) { print(error.toString()); }); diff --git a/lib/splash.dart b/lib/splash.dart index 2a289a9..07a9411 100644 --- a/lib/splash.dart +++ b/lib/splash.dart @@ -1,24 +1,47 @@ -import 'dart:async'; -import 'registration.dart'; - +import 'package:flutter/services.dart'; import 'package:flutter/material.dart'; +import 'main.dart'; +import 'registration.dart'; +import 'activate_token.dart'; +import 'dart:async'; class SplashScreen extends StatelessWidget { @override Widget build(BuildContext context) { + // Splash скрин зависает мимнимум на 1 секунду. + // После этого начинается проверка токена. new Future.delayed(const Duration(milliseconds: 1000), () { - _goToNextScreen(context); + _showNextScreen(context); }); - return new Image.asset('assets/splash.png', fit: BoxFit.cover); + return new Image.asset(logo_png, fit: BoxFit.cover); } - _goToNextScreen(BuildContext context) async { - Navigator.of(context).push(new MaterialPageRoute( - builder: (BuildContext context) { - return new RegistrationScreen(); - })); + /// Запуск следующего экрана приложения. + _showNextScreen(BuildContext context) async { + + const platform = const MethodChannel('com.dinect.checker/instance_id'); + token = await platform.invokeMethod('getToken'); + + // В случае, если в приложении отсутствует токен, + // необходимо запустить регистрацию кассы. + if (token == null) { + pushRoute(context, new RegistrationScreen()); + } else { + checkToken(context, new CheckTokenCallback()); + } + } + +} + +class CheckTokenCallback extends Callback { + + /// Запускается экран ожидания активации токена. + /// В реальности токен активируется в админке вручную, + /// на тестовом сервере токен активируется через несколько минут после создания. + call(BuildContext context) { + pushRoute(context, new FinishRegistrationScreen()); } } \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index c7b847f..ec73eea 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -23,6 +23,7 @@ flutter: - assets/registration_logo.png - assets/splash.png - assets/logout.png + - assets/activate_token_message_background.png # To add assets from package dependencies, first ensure the asset # is in the lib/ directory of the dependency. Then,