From a77e90f625abc72d9a0acaa9fe9595b53f385edc Mon Sep 17 00:00:00 2001 From: Mike Date: Sun, 17 Sep 2023 00:31:21 +0300 Subject: [PATCH 1/8] format --- lib/src/events.dart | 5 +- lib/src/payment.dart | 172 ++++++++++++++++++++++--------------------- 2 files changed, 92 insertions(+), 85 deletions(-) diff --git a/lib/src/events.dart b/lib/src/events.dart index 0996023..c585513 100644 --- a/lib/src/events.dart +++ b/lib/src/events.dart @@ -30,13 +30,13 @@ class PaymentCompleteEvent extends PaymentEvent { } class PaymentAdjustEvent extends PaymentEvent { - final Result result; + final Result result; PaymentAdjustEvent(this.result); } class PaymentAdjustReverseEvent extends PaymentEvent { - final Result result; + final Result result; PaymentAdjustReverseEvent(this.result); } @@ -59,6 +59,7 @@ class PaymentReaderSetDeviceEvent extends PaymentEvent { PaymentReaderSetDeviceEvent(this.deviceName); } + class PaymentRejectReverseEvent extends PaymentEvent { PaymentRejectReverseEvent(); } diff --git a/lib/src/payment.dart b/lib/src/payment.dart index 1c76b73..363f398 100644 --- a/lib/src/payment.dart +++ b/lib/src/payment.dart @@ -12,43 +12,56 @@ import 'entities/entities.dart'; /// Дублирует функционал PaymentConroller /// Класс не имеет возможности работать параллельно в связи с нижележащей имплементацией библиотеки iboxpro class PaymentController { - static final MethodChannel _channel = MethodChannel('iboxpro_flutter')..setMethodCallHandler(_handleMethodCall); - static final StreamController _streamController = StreamController.broadcast(); + static final MethodChannel _channel = MethodChannel('iboxpro_flutter') + ..setMethodCallHandler(_handleMethodCall); + static final StreamController _streamController = + StreamController.broadcast(); /// Поток с событиями успешного входа в систему - static Stream get onLogin => _streamController.stream.whereType(); + static Stream get onLogin => + _streamController.stream.whereType(); + /// Поток с событиями начала оплаты с карты (установлена успешная связь между картой и терминалом) - static Stream get onPaymentStart => _streamController.stream.whereType(); + static Stream get onPaymentStart => + _streamController.stream.whereType(); + /// Поток с событиями завершения оплаты, с данными оплаты и флагом requiredSignature static Stream get onPaymentComplete => - _streamController.stream.whereType(); + _streamController.stream.whereType(); + /// Поток с событиями завершения операции дополнения оплаты - static Stream get onPaymentAdjust => _streamController.stream.whereType(); + static Stream get onPaymentAdjust => + _streamController.stream.whereType(); + /// Поток с событиями завершения операции дополнения возврата оплаты static Stream get onPaymentAdjustReverse => - _streamController.stream.whereType(); + _streamController.stream.whereType(); + /// Поток с событиями любой ошибки оплаты - static Stream get onPaymentError => _streamController.stream.whereType(); + static Stream get onPaymentError => + _streamController.stream.whereType(); + /// Поток с событиями получения информации об оплате - static Stream get onInfo => _streamController.stream.whereType(); + static Stream get onInfo => + _streamController.stream.whereType(); + /// Поток с событиями установки связи и выполнения команд на терминале - static Stream get onReader => _streamController.stream.whereType(); + static Stream get onReader => + _streamController.stream.whereType(); + /// Поток с событиями установки связи с терминалом static Stream get onReaderSetDevice => - _streamController.stream.whereType(); + _streamController.stream.whereType(); + /// Поток с событиями отказа операции возврата оплаты static Stream get onRejectReverse => - _streamController.stream.whereType(); + _streamController.stream.whereType(); /// Производит логин в систему - static Future login({ - required String email, - required String password - }) async { - await _channel.invokeMethod('login', { - 'email': email, - 'password': password - }); + static Future login( + {required String email, required String password}) async { + await _channel + .invokeMethod('login', {'email': email, 'password': password}); } /// Начинает операцию принятия оплаты терминалом @@ -56,14 +69,13 @@ class PaymentController { /// [inputType] вид оплаты, все возможные значения в [InputType] /// Важно: Если вход в систему не осуществлен или нет связи с терминалом, /// то операция не начнется, при этом ошибки никакой не будет - static Future startPayment({ - required double amount, - required int inputType, - required String description, - bool singleStepAuth = true, - String? receiptEmail, - String? receiptPhone - }) async { + static Future startPayment( + {required double amount, + required int inputType, + required String description, + bool singleStepAuth = true, + String? receiptEmail, + String? receiptPhone}) async { await _channel.invokeMethod('startPayment', { 'amount': amount, 'inputType': inputType, @@ -79,14 +91,13 @@ class PaymentController { /// [inputType] вид оплаты, все возможные значения в [InputType] /// Важно: Если вход в систему не осуществлен или нет связи с терминалом, /// то операция не начнется, при этом ошибки никакой не будет - static Future startReversePayment({ - required String id, - required double amount, - required String description, - bool singleStepAuth = true, - String? receiptEmail, - String? receiptPhone - }) async { + static Future startReversePayment( + {required String id, + required double amount, + required String description, + bool singleStepAuth = true, + String? receiptEmail, + String? receiptPhone}) async { await _channel.invokeMethod('startReversePayment', { 'id': id, 'amount': amount, @@ -98,12 +109,11 @@ class PaymentController { } /// Начинает операцию добавления подписи к оплате терминала - static Future adjustPayment({ - required String id, - required Uint8List signature, - String? receiptEmail, - String? receiptPhone - }) async { + static Future adjustPayment( + {required String id, + required Uint8List signature, + String? receiptEmail, + String? receiptPhone}) async { await _channel.invokeMethod('adjustPayment', { 'id': id, 'signature': signature, @@ -113,12 +123,11 @@ class PaymentController { } /// Начинает операцию добавления подписи к оплате терминала - static Future adjustReversePayment({ - required String id, - required Uint8List signature, - String? receiptEmail, - String? receiptPhone - }) async { + static Future adjustReversePayment( + {required String id, + required Uint8List signature, + String? receiptEmail, + String? receiptPhone}) async { await _channel.invokeMethod('adjustReversePayment', { 'id': id, 'signature': signature, @@ -128,12 +137,8 @@ class PaymentController { } /// Начинает операцию по получению информации об оплате - static Future info({ - required String id - }) async { - await _channel.invokeMethod('info', { - 'id': id - }); + static Future info({required String id}) async { + await _channel.invokeMethod('info', {'id': id}); } /// Прерывает операцию принятия оплаты терминалом @@ -142,12 +147,9 @@ class PaymentController { } /// Начинает операцию поиска терминала с указанным наименованием - static Future startSearchBTDevice({ - required String deviceName - }) async { - await _channel.invokeMethod('startSearchBTDevice', { - 'deviceName': deviceName - }); + static Future startSearchBTDevice({required String deviceName}) async { + await _channel + .invokeMethod('startSearchBTDevice', {'deviceName': deviceName}); } /// Завершает операцию поиска терминала @@ -161,13 +163,15 @@ class PaymentController { Map arguments = call.arguments; _streamController.add(PaymentInfoEvent( - Result(errorCode: arguments['errorCode']), - arguments['transaction'] != null ? Transaction.fromMap(arguments['transaction']) : null - )); + Result(errorCode: arguments['errorCode']), + arguments['transaction'] != null + ? Transaction.fromMap(arguments['transaction']) + : null)); break; case 'onLogin': - _streamController.add(PaymentLoginEvent(Result(errorCode: call.arguments['errorCode']))); + _streamController.add( + PaymentLoginEvent(Result(errorCode: call.arguments['errorCode']))); break; case 'onPaymentStart': @@ -176,44 +180,46 @@ class PaymentController { break; case 'onPaymentError': Map arguments = call.arguments; - int type = Platform.isAndroid ? - ErrorType.fromAndroidType(arguments['nativeErrorType']) : - ErrorType.fromIosType(arguments['nativeErrorType']); + int type = Platform.isAndroid + ? ErrorType.fromAndroidType(arguments['nativeErrorType']) + : ErrorType.fromIosType(arguments['nativeErrorType']); _streamController.add(PaymentErrorEvent(PaymentError( - type: type, - nativeType: call.arguments['nativeErrorType'], - message: call.arguments['errorMessage'] - ))); + type: type, + nativeType: call.arguments['nativeErrorType'], + message: call.arguments['errorMessage']))); break; case 'onPaymentComplete': - _streamController.add( - PaymentCompleteEvent(Transaction.fromMap(call.arguments['transaction']), call.arguments['requiredSignature']) - ); + _streamController.add(PaymentCompleteEvent( + Transaction.fromMap(call.arguments['transaction']), + call.arguments['requiredSignature'])); break; case 'onPaymentAdjust': - _streamController.add(PaymentAdjustEvent(Result(errorCode: call.arguments['errorCode']))); + _streamController.add( + PaymentAdjustEvent(Result(errorCode: call.arguments['errorCode']))); break; case 'onReaderSetBTDevice': - _streamController.add(PaymentReaderSetDeviceEvent(call.arguments['name'])); + _streamController + .add(PaymentReaderSetDeviceEvent(call.arguments['name'])); break; case 'onReaderEvent': Map arguments = call.arguments; - int type = Platform.isAndroid ? - ReaderEventType.fromAndroidType(arguments['nativeReaderEventType']) : - ReaderEventType.fromIosType(arguments['nativeReaderEventType']); + int type = Platform.isAndroid + ? ReaderEventType.fromAndroidType( + arguments['nativeReaderEventType']) + : ReaderEventType.fromIosType(arguments['nativeReaderEventType']); - _streamController.add( - PaymentReaderEvent(ReaderEvent(type: type, nativeType: arguments['nativeReaderEventType'])) - ); + _streamController.add(PaymentReaderEvent(ReaderEvent( + type: type, nativeType: arguments['nativeReaderEventType']))); break; case 'onReversePaymentAdjust': - _streamController.add(PaymentAdjustReverseEvent(Result(errorCode: call.arguments['errorCode']))); + _streamController.add(PaymentAdjustReverseEvent( + Result(errorCode: call.arguments['errorCode']))); break; case 'onReverseReject': From 058bf001399991286f47c623c3ce8d259dd723a6 Mon Sep 17 00:00:00 2001 From: Mike Date: Sun, 17 Sep 2023 00:50:18 +0300 Subject: [PATCH 2/8] implement setCustomReaderParams --- .../IboxproFlutterHandlerImpl.kt | 14 +++ example/lib/pages/main_page.dart | 92 ++++++++++++------- lib/src/payment.dart | 10 ++ 3 files changed, 83 insertions(+), 33 deletions(-) diff --git a/android/src/main/kotlin/com/unact/iboxpro_flutter/IboxproFlutterHandlerImpl.kt b/android/src/main/kotlin/com/unact/iboxpro_flutter/IboxproFlutterHandlerImpl.kt index 547341d..2af5eb8 100644 --- a/android/src/main/kotlin/com/unact/iboxpro_flutter/IboxproFlutterHandlerImpl.kt +++ b/android/src/main/kotlin/com/unact/iboxpro_flutter/IboxproFlutterHandlerImpl.kt @@ -176,6 +176,16 @@ class IboxproFlutterHandlerImpl: MethodCallHandler { methodChannel.invokeMethod("onLogin", arguments) } + private fun setCustomReaderParams(call: MethodCall) { + val params = call.arguments as HashMap + val notup = params["NOTUP"] as Boolean? + + val readerParams = Hashtable() + readerParams["NOTUP"] = notup ?: false + + paymentController.setCustomReaderParams(readerParams) + } + private fun startPayment(call: MethodCall) { val params = call.arguments as HashMap val inputType = PaymentController.PaymentInputType.fromValue(params["inputType"] as Int) @@ -306,6 +316,10 @@ class IboxproFlutterHandlerImpl: MethodCallHandler { login(call) result.success(null) } + "setCustomReaderParams" -> { + setCustomReaderParams(call) + result.success(null) + } "startPayment" -> { startPayment(call) result.success(null) diff --git a/example/lib/pages/main_page.dart b/example/lib/pages/main_page.dart index 2b1aad7..475651a 100644 --- a/example/lib/pages/main_page.dart +++ b/example/lib/pages/main_page.dart @@ -17,10 +17,12 @@ class _MainPage extends State { String _deviceName = ''; late StreamSubscription _onLoginSubscription; - late StreamSubscription _onReaderSetDeviceSubscription; + late StreamSubscription + _onReaderSetDeviceSubscription; void _showSnackBar(String content) { - ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(content))); + ScaffoldMessenger.of(context) + .showSnackBar(SnackBar(content: Text(content))); } @override @@ -36,7 +38,8 @@ class _MainPage extends State { _showSnackBar('Произошла ошибка'); } }); - _onReaderSetDeviceSubscription = PaymentController.onReaderSetDevice.listen((event) { + _onReaderSetDeviceSubscription = + PaymentController.onReaderSetDevice.listen((event) { _showSnackBar('Успешно установлена связь с терминалом'); }); } @@ -52,27 +55,27 @@ class _MainPage extends State { List _buildLoginPart(BuildContext context) { return [ TextFormField( - initialValue: _loginEmail, - maxLines: 1, - decoration: InputDecoration(labelText: 'Логин'), - onChanged: (val) => _loginEmail = val - ), + initialValue: _loginEmail, + maxLines: 1, + keyboardType: TextInputType.emailAddress, + decoration: InputDecoration(labelText: 'Логин'), + onChanged: (val) => _loginEmail = val), TextFormField( - initialValue: _password, - obscureText: true, - maxLines: 1, - decoration: InputDecoration(labelText: 'Пароль'), - onChanged: (val) => _password = val - ), + initialValue: _password, + obscureText: true, + maxLines: 1, + decoration: InputDecoration(labelText: 'Пароль'), + onChanged: (val) => _password = val), ElevatedButton( child: Text('Войти'), onPressed: () async { showDialog( - context: context, - builder: (BuildContext context) => Center(child: CircularProgressIndicator()) - ); + context: context, + builder: (BuildContext context) => + Center(child: CircularProgressIndicator())); - await PaymentController.login(email: _loginEmail, password: _password); + await PaymentController.login( + email: _loginEmail, password: _password); }, ) ]; @@ -81,11 +84,10 @@ class _MainPage extends State { List _buildSearchDevicePart(BuildContext context) { return [ TextFormField( - initialValue: _deviceName, - maxLines: 1, - decoration: InputDecoration(labelText: 'Имя терминала'), - onChanged: (val) => _deviceName = val - ), + initialValue: _deviceName, + maxLines: 1, + decoration: InputDecoration(labelText: 'Имя терминала'), + onChanged: (val) => _deviceName = val), ElevatedButton( child: Text('Подключиться к терминалу'), onPressed: () async { @@ -102,19 +104,44 @@ class _MainPage extends State { ]; } - List _buildPaymentPart(BuildContext context) { + List _buildReaderParams(BuildContext context) { return [ Row( mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + ElevatedButton( + child: Text('Включить авто NFC'), + onPressed: () async { + await PaymentController.setCustomReaderParams(notup: true); + _showSnackBar('Автоматическое включение NFC активировано'); + }, + ), + ElevatedButton( + child: Text('Отключить авто NFC'), + onPressed: () async { + await PaymentController.setCustomReaderParams(notup: false); + _showSnackBar('Автоматическое включение NFC отключено'); + }, + ) + ], + ) + ]; + } + List _buildPaymentPart(BuildContext context) { + return [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ ElevatedButton( child: Text('Оплатить'), - onPressed: () => Navigator.push(context, MaterialPageRoute(builder: (_) => PaymentPage())), + onPressed: () => Navigator.push( + context, MaterialPageRoute(builder: (_) => PaymentPage())), ), ElevatedButton( child: Text('Вернуть'), - onPressed: () => Navigator.push(context, MaterialPageRoute(builder: (_) => ReversePaymentPage())), + onPressed: () => Navigator.push(context, + MaterialPageRoute(builder: (_) => ReversePaymentPage())), ) ], ) @@ -129,13 +156,12 @@ class _MainPage extends State { title: Text('IboxproFlutter'), ), body: Center( - child: ListView( - padding: EdgeInsets.all(8), - children: _buildLoginPart(context) - ..addAll(_buildSearchDevicePart(context)) - ..addAll(_buildPaymentPart(context)) - ) - ), + child: ListView( + padding: EdgeInsets.all(8), + children: _buildLoginPart(context) + ..addAll(_buildSearchDevicePart(context)) + ..addAll(_buildReaderParams(context)) + ..addAll(_buildPaymentPart(context)))), ); } } diff --git a/lib/src/payment.dart b/lib/src/payment.dart index 363f398..66bc949 100644 --- a/lib/src/payment.dart +++ b/lib/src/payment.dart @@ -64,6 +64,16 @@ class PaymentController { .invokeMethod('login', {'email': email, 'password': password}); } + /// Устанавливает параметры работы ридера. + /// + /// [notup] (true/false) – автоматическое включение NFC на ридере P17 + /// при проведении транзакции + static Future setCustomReaderParams({notup = true}) async { + await _channel.invokeMethod('setCustomReaderParams', { + 'NOTUP': notup, + }); + } + /// Начинает операцию принятия оплаты терминалом /// /// [inputType] вид оплаты, все возможные значения в [InputType] From ca497e682c8919ac19c14d5ebaef892e16ca8047 Mon Sep 17 00:00:00 2001 From: Mike Date: Sun, 17 Sep 2023 01:19:54 +0300 Subject: [PATCH 3/8] update gradle --- android/build.gradle | 6 +++--- android/gradle/wrapper/gradle-wrapper.properties | 2 +- example/android/build.gradle | 6 +++--- .../gradle/wrapper/gradle-wrapper.properties | 2 +- example/android/settings.gradle | 13 +++++++++++++ 5 files changed, 21 insertions(+), 8 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index c77dcc3..fa0c445 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -2,14 +2,14 @@ group 'com.unact.iboxpro_flutter' version '1.0-SNAPSHOT' buildscript { - ext.kotlin_version = '1.6.0' + ext.kotlin_version = '1.7.10' repositories { google() mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:7.0.2' + classpath 'com.android.tools.build:gradle:7.4.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } @@ -29,7 +29,7 @@ apply plugin: 'com.android.library' apply plugin: 'kotlin-android' android { - compileSdkVersion 31 + compileSdkVersion 33 sourceSets { main.java.srcDirs += 'src/main/kotlin' diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 297f2fe..ceccc3a 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-all.zip diff --git a/example/android/build.gradle b/example/android/build.gradle index 8a9374e..ce647a4 100644 --- a/example/android/build.gradle +++ b/example/android/build.gradle @@ -1,12 +1,12 @@ buildscript { - ext.kotlin_version = '1.6.0' + ext.kotlin_version = '1.7.10' repositories { google() mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:7.0.2' + classpath 'com.android.tools.build:gradle:7.4.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } @@ -26,6 +26,6 @@ subprojects { project.evaluationDependsOn(':app') } -task clean(type: Delete) { +tasks.register("clean", Delete) { delete rootProject.buildDir } diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties index b8793d3..cfe88f6 100644 --- a/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/example/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-all.zip diff --git a/example/android/settings.gradle b/example/android/settings.gradle index 5a2f14f..8d75433 100644 --- a/example/android/settings.gradle +++ b/example/android/settings.gradle @@ -13,3 +13,16 @@ plugins.each { name, path -> include ":$name" project(":$name").projectDir = pluginDirectory } + +// See https://github.com/flutter/flutter/wiki/Plugins-and-Packages-repository-structure#gradle-structure for more info. +buildscript { + repositories { + maven { + url "https://plugins.gradle.org/m2/" + } + } + dependencies { + classpath "gradle.plugin.com.google.cloud.artifactregistry:artifactregistry-gradle-plugin:2.2.1" + } +} +apply plugin: "com.google.cloud.artifactregistry.gradle-plugin" From 966c001698462328ea455886830b50eea4be986b Mon Sep 17 00:00:00 2001 From: Mike Date: Mon, 18 Dec 2023 23:03:27 +0300 Subject: [PATCH 4/8] rollback kotlin and gradle version increase --- android/build.gradle | 4 ++-- android/gradle/wrapper/gradle-wrapper.properties | 2 +- example/android/build.gradle | 8 ++++---- .../gradle/wrapper/gradle-wrapper.properties | 2 +- example/android/settings.gradle | 15 +-------------- 5 files changed, 9 insertions(+), 22 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index fa0c445..db7c5d9 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -2,14 +2,14 @@ group 'com.unact.iboxpro_flutter' version '1.0-SNAPSHOT' buildscript { - ext.kotlin_version = '1.7.10' + ext.kotlin_version = '1.6.0' repositories { google() mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:7.4.2' + classpath 'com.android.tools.build:gradle:7.0.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index ceccc3a..ab716dd 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip \ No newline at end of file diff --git a/example/android/build.gradle b/example/android/build.gradle index ce647a4..fe24169 100644 --- a/example/android/build.gradle +++ b/example/android/build.gradle @@ -1,12 +1,12 @@ buildscript { - ext.kotlin_version = '1.7.10' + ext.kotlin_version = '1.6.0' repositories { google() mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:7.4.2' + classpath 'com.android.tools.build:gradle:7.0.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } @@ -26,6 +26,6 @@ subprojects { project.evaluationDependsOn(':app') } -tasks.register("clean", Delete) { +task clean(type: Delete) { delete rootProject.buildDir -} +} \ No newline at end of file diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties index cfe88f6..8b6dc59 100644 --- a/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/example/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip \ No newline at end of file diff --git a/example/android/settings.gradle b/example/android/settings.gradle index 8d75433..121d30d 100644 --- a/example/android/settings.gradle +++ b/example/android/settings.gradle @@ -12,17 +12,4 @@ plugins.each { name, path -> def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() include ":$name" project(":$name").projectDir = pluginDirectory -} - -// See https://github.com/flutter/flutter/wiki/Plugins-and-Packages-repository-structure#gradle-structure for more info. -buildscript { - repositories { - maven { - url "https://plugins.gradle.org/m2/" - } - } - dependencies { - classpath "gradle.plugin.com.google.cloud.artifactregistry:artifactregistry-gradle-plugin:2.2.1" - } -} -apply plugin: "com.google.cloud.artifactregistry.gradle-plugin" +} \ No newline at end of file From 3a12fc7d76207020bcc08cf77aff8ac8a97b4d31 Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 19 Dec 2023 00:23:54 +0300 Subject: [PATCH 5/8] remove null-safety from notup --- .../com/unact/iboxpro_flutter/IboxproFlutterHandlerImpl.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/android/src/main/kotlin/com/unact/iboxpro_flutter/IboxproFlutterHandlerImpl.kt b/android/src/main/kotlin/com/unact/iboxpro_flutter/IboxproFlutterHandlerImpl.kt index 2af5eb8..62f2952 100644 --- a/android/src/main/kotlin/com/unact/iboxpro_flutter/IboxproFlutterHandlerImpl.kt +++ b/android/src/main/kotlin/com/unact/iboxpro_flutter/IboxproFlutterHandlerImpl.kt @@ -178,10 +178,10 @@ class IboxproFlutterHandlerImpl: MethodCallHandler { private fun setCustomReaderParams(call: MethodCall) { val params = call.arguments as HashMap - val notup = params["NOTUP"] as Boolean? + val notup = params["NOTUP"] as Boolean val readerParams = Hashtable() - readerParams["NOTUP"] = notup ?: false + readerParams["NOTUP"] = notup paymentController.setCustomReaderParams(readerParams) } From dda4d5bb73e91b9708136014410e6703dc7695ba Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 19 Dec 2023 00:24:32 +0300 Subject: [PATCH 6/8] add iOS support for setCustomReaderParams --- ios/Classes/SwiftIboxproFlutterPlugin.swift | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/ios/Classes/SwiftIboxproFlutterPlugin.swift b/ios/Classes/SwiftIboxproFlutterPlugin.swift index ec6534d..0487ab8 100644 --- a/ios/Classes/SwiftIboxproFlutterPlugin.swift +++ b/ios/Classes/SwiftIboxproFlutterPlugin.swift @@ -104,6 +104,16 @@ public class SwiftIboxproFlutterPlugin: NSObject, FlutterPlugin { } } + private func setCustomReaderParams(call: FlutterMethodCall) { + let params = call.arguments as! [String: Any] + let notup = params["NOTUP"] as! Bool + + var readerParams = [String: Any]() + readerParams["NOTUP"] = notup + + paymentController.setCustomReaderParams(readerParams: readerParams) + } + public func startPayment(_ call: FlutterMethodCall) { let params = call.arguments as! [String: Any] let inputType = TransactionInputType( @@ -211,6 +221,9 @@ public class SwiftIboxproFlutterPlugin: NSObject, FlutterPlugin { case "login": login(call) return result(nil) + case "setCustomReaderParams": + setCustomReaderParams(call) + return result(nil) case "startPayment": startPayment(call) return result(nil) From fab6f2f168dab951bbf1a559177f67a240a3ffbf Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 19 Dec 2023 00:26:43 +0300 Subject: [PATCH 7/8] rename param and remove autoformatting --- example/lib/pages/main_page.dart | 45 +++++--- lib/src/payment.dart | 178 +++++++++++++++---------------- 2 files changed, 117 insertions(+), 106 deletions(-) diff --git a/example/lib/pages/main_page.dart b/example/lib/pages/main_page.dart index 475651a..8cf55f5 100644 --- a/example/lib/pages/main_page.dart +++ b/example/lib/pages/main_page.dart @@ -15,6 +15,8 @@ class _MainPage extends State { String _loginEmail = ''; String _password = ''; String _deviceName = ''; + bool _isHidden = true; + bool _nfcActivation = false; late StreamSubscription _onLoginSubscription; late StreamSubscription @@ -62,9 +64,22 @@ class _MainPage extends State { onChanged: (val) => _loginEmail = val), TextFormField( initialValue: _password, - obscureText: true, + obscureText: _isHidden, + keyboardType: _isHidden ? null : TextInputType.visiblePassword, + enableSuggestions: false, + autocorrect: false, maxLines: 1, - decoration: InputDecoration(labelText: 'Пароль'), + decoration: InputDecoration( + labelText: 'Пароль', + suffixIcon: IconButton( + icon: Icon(_isHidden ? Icons.visibility : Icons.visibility_off), + onPressed: () { + setState(() { + _isHidden = !_isHidden; + }); + }, + ), + ), onChanged: (val) => _password = val), ElevatedButton( child: Text('Войти'), @@ -109,20 +124,22 @@ class _MainPage extends State { Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ - ElevatedButton( - child: Text('Включить авто NFC'), - onPressed: () async { - await PaymentController.setCustomReaderParams(notup: true); - _showSnackBar('Автоматическое включение NFC активировано'); - }, + Expanded( + child: + Text('Авто NFC: ${_nfcActivation ? "Включено" : "Отключено"}'), ), - ElevatedButton( - child: Text('Отключить авто NFC'), - onPressed: () async { - await PaymentController.setCustomReaderParams(notup: false); - _showSnackBar('Автоматическое включение NFC отключено'); + Switch( + value: _nfcActivation, + onChanged: (bool newValue) async { + await PaymentController.setCustomReaderParams(nfcActivation: newValue); + setState(() { + _nfcActivation = newValue; + }); + _showSnackBar(newValue + ? 'Автоматическое включение NFC активировано' + : 'Автоматическое включение NFC отключено'); }, - ) + ), ], ) ]; diff --git a/lib/src/payment.dart b/lib/src/payment.dart index 66bc949..9815a58 100644 --- a/lib/src/payment.dart +++ b/lib/src/payment.dart @@ -12,65 +12,52 @@ import 'entities/entities.dart'; /// Дублирует функционал PaymentConroller /// Класс не имеет возможности работать параллельно в связи с нижележащей имплементацией библиотеки iboxpro class PaymentController { - static final MethodChannel _channel = MethodChannel('iboxpro_flutter') - ..setMethodCallHandler(_handleMethodCall); - static final StreamController _streamController = - StreamController.broadcast(); + static final MethodChannel _channel = MethodChannel('iboxpro_flutter')..setMethodCallHandler(_handleMethodCall); + static final StreamController _streamController = StreamController.broadcast(); /// Поток с событиями успешного входа в систему - static Stream get onLogin => - _streamController.stream.whereType(); - + static Stream get onLogin => _streamController.stream.whereType(); /// Поток с событиями начала оплаты с карты (установлена успешная связь между картой и терминалом) - static Stream get onPaymentStart => - _streamController.stream.whereType(); - + static Stream get onPaymentStart => _streamController.stream.whereType(); /// Поток с событиями завершения оплаты, с данными оплаты и флагом requiredSignature static Stream get onPaymentComplete => - _streamController.stream.whereType(); - + _streamController.stream.whereType(); /// Поток с событиями завершения операции дополнения оплаты - static Stream get onPaymentAdjust => - _streamController.stream.whereType(); - + static Stream get onPaymentAdjust => _streamController.stream.whereType(); /// Поток с событиями завершения операции дополнения возврата оплаты static Stream get onPaymentAdjustReverse => - _streamController.stream.whereType(); - + _streamController.stream.whereType(); /// Поток с событиями любой ошибки оплаты - static Stream get onPaymentError => - _streamController.stream.whereType(); - + static Stream get onPaymentError => _streamController.stream.whereType(); /// Поток с событиями получения информации об оплате - static Stream get onInfo => - _streamController.stream.whereType(); - + static Stream get onInfo => _streamController.stream.whereType(); /// Поток с событиями установки связи и выполнения команд на терминале - static Stream get onReader => - _streamController.stream.whereType(); - + static Stream get onReader => _streamController.stream.whereType(); /// Поток с событиями установки связи с терминалом static Stream get onReaderSetDevice => - _streamController.stream.whereType(); - + _streamController.stream.whereType(); /// Поток с событиями отказа операции возврата оплаты static Stream get onRejectReverse => - _streamController.stream.whereType(); + _streamController.stream.whereType(); /// Производит логин в систему - static Future login( - {required String email, required String password}) async { - await _channel - .invokeMethod('login', {'email': email, 'password': password}); + static Future login({ + required String email, + required String password + }) async { + await _channel.invokeMethod('login', { + 'email': email, + 'password': password + }); } /// Устанавливает параметры работы ридера. /// - /// [notup] (true/false) – автоматическое включение NFC на ридере P17 + /// [nfcActivation] (true/false) – автоматическое включение NFC на ридере P17 /// при проведении транзакции - static Future setCustomReaderParams({notup = true}) async { + static Future setCustomReaderParams({bool nfcActivation = false}) async { await _channel.invokeMethod('setCustomReaderParams', { - 'NOTUP': notup, + 'NOTUP': nfcActivation, }); } @@ -79,13 +66,14 @@ class PaymentController { /// [inputType] вид оплаты, все возможные значения в [InputType] /// Важно: Если вход в систему не осуществлен или нет связи с терминалом, /// то операция не начнется, при этом ошибки никакой не будет - static Future startPayment( - {required double amount, - required int inputType, - required String description, - bool singleStepAuth = true, - String? receiptEmail, - String? receiptPhone}) async { + static Future startPayment({ + required double amount, + required int inputType, + required String description, + bool singleStepAuth = true, + String? receiptEmail, + String? receiptPhone + }) async { await _channel.invokeMethod('startPayment', { 'amount': amount, 'inputType': inputType, @@ -101,13 +89,14 @@ class PaymentController { /// [inputType] вид оплаты, все возможные значения в [InputType] /// Важно: Если вход в систему не осуществлен или нет связи с терминалом, /// то операция не начнется, при этом ошибки никакой не будет - static Future startReversePayment( - {required String id, - required double amount, - required String description, - bool singleStepAuth = true, - String? receiptEmail, - String? receiptPhone}) async { + static Future startReversePayment({ + required String id, + required double amount, + required String description, + bool singleStepAuth = true, + String? receiptEmail, + String? receiptPhone + }) async { await _channel.invokeMethod('startReversePayment', { 'id': id, 'amount': amount, @@ -119,11 +108,12 @@ class PaymentController { } /// Начинает операцию добавления подписи к оплате терминала - static Future adjustPayment( - {required String id, - required Uint8List signature, - String? receiptEmail, - String? receiptPhone}) async { + static Future adjustPayment({ + required String id, + required Uint8List signature, + String? receiptEmail, + String? receiptPhone + }) async { await _channel.invokeMethod('adjustPayment', { 'id': id, 'signature': signature, @@ -133,11 +123,12 @@ class PaymentController { } /// Начинает операцию добавления подписи к оплате терминала - static Future adjustReversePayment( - {required String id, - required Uint8List signature, - String? receiptEmail, - String? receiptPhone}) async { + static Future adjustReversePayment({ + required String id, + required Uint8List signature, + String? receiptEmail, + String? receiptPhone + }) async { await _channel.invokeMethod('adjustReversePayment', { 'id': id, 'signature': signature, @@ -147,8 +138,12 @@ class PaymentController { } /// Начинает операцию по получению информации об оплате - static Future info({required String id}) async { - await _channel.invokeMethod('info', {'id': id}); + static Future info({ + required String id + }) async { + await _channel.invokeMethod('info', { + 'id': id + }); } /// Прерывает операцию принятия оплаты терминалом @@ -157,9 +152,12 @@ class PaymentController { } /// Начинает операцию поиска терминала с указанным наименованием - static Future startSearchBTDevice({required String deviceName}) async { - await _channel - .invokeMethod('startSearchBTDevice', {'deviceName': deviceName}); + static Future startSearchBTDevice({ + required String deviceName + }) async { + await _channel.invokeMethod('startSearchBTDevice', { + 'deviceName': deviceName + }); } /// Завершает операцию поиска терминала @@ -173,15 +171,13 @@ class PaymentController { Map arguments = call.arguments; _streamController.add(PaymentInfoEvent( - Result(errorCode: arguments['errorCode']), - arguments['transaction'] != null - ? Transaction.fromMap(arguments['transaction']) - : null)); + Result(errorCode: arguments['errorCode']), + arguments['transaction'] != null ? Transaction.fromMap(arguments['transaction']) : null + )); break; case 'onLogin': - _streamController.add( - PaymentLoginEvent(Result(errorCode: call.arguments['errorCode']))); + _streamController.add(PaymentLoginEvent(Result(errorCode: call.arguments['errorCode']))); break; case 'onPaymentStart': @@ -190,46 +186,44 @@ class PaymentController { break; case 'onPaymentError': Map arguments = call.arguments; - int type = Platform.isAndroid - ? ErrorType.fromAndroidType(arguments['nativeErrorType']) - : ErrorType.fromIosType(arguments['nativeErrorType']); + int type = Platform.isAndroid ? + ErrorType.fromAndroidType(arguments['nativeErrorType']) : + ErrorType.fromIosType(arguments['nativeErrorType']); _streamController.add(PaymentErrorEvent(PaymentError( - type: type, - nativeType: call.arguments['nativeErrorType'], - message: call.arguments['errorMessage']))); + type: type, + nativeType: call.arguments['nativeErrorType'], + message: call.arguments['errorMessage'] + ))); break; case 'onPaymentComplete': - _streamController.add(PaymentCompleteEvent( - Transaction.fromMap(call.arguments['transaction']), - call.arguments['requiredSignature'])); + _streamController.add( + PaymentCompleteEvent(Transaction.fromMap(call.arguments['transaction']), call.arguments['requiredSignature']) + ); break; case 'onPaymentAdjust': - _streamController.add( - PaymentAdjustEvent(Result(errorCode: call.arguments['errorCode']))); + _streamController.add(PaymentAdjustEvent(Result(errorCode: call.arguments['errorCode']))); break; case 'onReaderSetBTDevice': - _streamController - .add(PaymentReaderSetDeviceEvent(call.arguments['name'])); + _streamController.add(PaymentReaderSetDeviceEvent(call.arguments['name'])); break; case 'onReaderEvent': Map arguments = call.arguments; - int type = Platform.isAndroid - ? ReaderEventType.fromAndroidType( - arguments['nativeReaderEventType']) - : ReaderEventType.fromIosType(arguments['nativeReaderEventType']); + int type = Platform.isAndroid ? + ReaderEventType.fromAndroidType(arguments['nativeReaderEventType']) : + ReaderEventType.fromIosType(arguments['nativeReaderEventType']); - _streamController.add(PaymentReaderEvent(ReaderEvent( - type: type, nativeType: arguments['nativeReaderEventType']))); + _streamController.add( + PaymentReaderEvent(ReaderEvent(type: type, nativeType: arguments['nativeReaderEventType'])) + ); break; case 'onReversePaymentAdjust': - _streamController.add(PaymentAdjustReverseEvent( - Result(errorCode: call.arguments['errorCode']))); + _streamController.add(PaymentAdjustReverseEvent(Result(errorCode: call.arguments['errorCode']))); break; case 'onReverseReject': From 5d942f7c1485502081186ae4f104a50cb2ed1de3 Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 19 Dec 2023 00:51:59 +0300 Subject: [PATCH 8/8] fix some formatting --- example/lib/pages/main_page.dart | 97 +++++++++++++++----------------- 1 file changed, 46 insertions(+), 51 deletions(-) diff --git a/example/lib/pages/main_page.dart b/example/lib/pages/main_page.dart index 8cf55f5..0ee9c12 100644 --- a/example/lib/pages/main_page.dart +++ b/example/lib/pages/main_page.dart @@ -19,12 +19,10 @@ class _MainPage extends State { bool _nfcActivation = false; late StreamSubscription _onLoginSubscription; - late StreamSubscription - _onReaderSetDeviceSubscription; + late StreamSubscription _onReaderSetDeviceSubscription; void _showSnackBar(String content) { - ScaffoldMessenger.of(context) - .showSnackBar(SnackBar(content: Text(content))); + ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(content))); } @override @@ -40,8 +38,7 @@ class _MainPage extends State { _showSnackBar('Произошла ошибка'); } }); - _onReaderSetDeviceSubscription = - PaymentController.onReaderSetDevice.listen((event) { + _onReaderSetDeviceSubscription = PaymentController.onReaderSetDevice.listen((event) { _showSnackBar('Успешно установлена связь с терминалом'); }); } @@ -57,40 +54,40 @@ class _MainPage extends State { List _buildLoginPart(BuildContext context) { return [ TextFormField( - initialValue: _loginEmail, - maxLines: 1, - keyboardType: TextInputType.emailAddress, - decoration: InputDecoration(labelText: 'Логин'), - onChanged: (val) => _loginEmail = val), + initialValue: _loginEmail, + maxLines: 1, + keyboardType: TextInputType.emailAddress, + decoration: InputDecoration(labelText: 'Логин'), + onChanged: (val) => _loginEmail = val), TextFormField( - initialValue: _password, - obscureText: _isHidden, - keyboardType: _isHidden ? null : TextInputType.visiblePassword, - enableSuggestions: false, - autocorrect: false, - maxLines: 1, - decoration: InputDecoration( - labelText: 'Пароль', - suffixIcon: IconButton( - icon: Icon(_isHidden ? Icons.visibility : Icons.visibility_off), - onPressed: () { - setState(() { - _isHidden = !_isHidden; - }); - }, - ), + initialValue: _password, + obscureText: _isHidden, + keyboardType: _isHidden ? null : TextInputType.visiblePassword, + enableSuggestions: false, + autocorrect: false, + maxLines: 1, + decoration: InputDecoration( + labelText: 'Пароль', + suffixIcon: IconButton( + icon: Icon(_isHidden ? Icons.visibility : Icons.visibility_off), + onPressed: () { + setState(() { + _isHidden = !_isHidden; + }); + }, ), - onChanged: (val) => _password = val), + ), + onChanged: (val) => _password = val + ), ElevatedButton( child: Text('Войти'), onPressed: () async { showDialog( - context: context, - builder: (BuildContext context) => - Center(child: CircularProgressIndicator())); + context: context, + builder: (BuildContext context) => Center(child: CircularProgressIndicator()) + ); - await PaymentController.login( - email: _loginEmail, password: _password); + await PaymentController.login(email: _loginEmail, password: _password); }, ) ]; @@ -99,10 +96,11 @@ class _MainPage extends State { List _buildSearchDevicePart(BuildContext context) { return [ TextFormField( - initialValue: _deviceName, - maxLines: 1, - decoration: InputDecoration(labelText: 'Имя терминала'), - onChanged: (val) => _deviceName = val), + initialValue: _deviceName, + maxLines: 1, + decoration: InputDecoration(labelText: 'Имя терминала'), + onChanged: (val) => _deviceName = val + ), ElevatedButton( child: Text('Подключиться к терминалу'), onPressed: () async { @@ -125,8 +123,7 @@ class _MainPage extends State { mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ Expanded( - child: - Text('Авто NFC: ${_nfcActivation ? "Включено" : "Отключено"}'), + child: Text('Авто NFC: ${_nfcActivation ? "Включено" : "Отключено"}'), ), Switch( value: _nfcActivation, @@ -136,8 +133,8 @@ class _MainPage extends State { _nfcActivation = newValue; }); _showSnackBar(newValue - ? 'Автоматическое включение NFC активировано' - : 'Автоматическое включение NFC отключено'); + ? 'Автоматическое включение NFC активировано' + : 'Автоматическое включение NFC отключено'); }, ), ], @@ -152,13 +149,11 @@ class _MainPage extends State { children: [ ElevatedButton( child: Text('Оплатить'), - onPressed: () => Navigator.push( - context, MaterialPageRoute(builder: (_) => PaymentPage())), + onPressed: () => Navigator.push(context, MaterialPageRoute(builder: (_) => PaymentPage())), ), ElevatedButton( child: Text('Вернуть'), - onPressed: () => Navigator.push(context, - MaterialPageRoute(builder: (_) => ReversePaymentPage())), + onPressed: () => Navigator.push(context, MaterialPageRoute(builder: (_) => ReversePaymentPage())), ) ], ) @@ -173,12 +168,12 @@ class _MainPage extends State { title: Text('IboxproFlutter'), ), body: Center( - child: ListView( - padding: EdgeInsets.all(8), - children: _buildLoginPart(context) - ..addAll(_buildSearchDevicePart(context)) - ..addAll(_buildReaderParams(context)) - ..addAll(_buildPaymentPart(context)))), + child: ListView( + padding: EdgeInsets.all(8), + children: _buildLoginPart(context) + ..addAll(_buildSearchDevicePart(context)) + ..addAll(_buildReaderParams(context)) + ..addAll(_buildPaymentPart(context)))), ); } }