Проведение покупки, проверка деактивированного токена, подтверждение логаута, функциональная маска на сканере, кнопка назад в faq
This commit is contained in:
@@ -45,6 +45,7 @@ import android.view.Surface;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
import java.io.IOException;
|
||||
import java.lang.Exception;
|
||||
import java.util.List;
|
||||
import com.dinect.checker.R;
|
||||
|
||||
@@ -57,6 +58,8 @@ public class CameraActivity extends AppCompatActivity implements SurfaceHolder.C
|
||||
|
||||
private boolean mBarcodeScanned = false;
|
||||
private boolean previewing = true;
|
||||
private Handler autoFocusHandler;
|
||||
private int mOffset;
|
||||
|
||||
static {
|
||||
System.loadLibrary("iconv");
|
||||
@@ -83,6 +86,10 @@ public class CameraActivity extends AppCompatActivity implements SurfaceHolder.C
|
||||
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
|
||||
mOffset = (int) (56 * getResources().getDisplayMetrics().density);
|
||||
|
||||
autoFocusHandler = new Handler();
|
||||
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
|
||||
if (actionBar != null) {
|
||||
@@ -95,9 +102,7 @@ public class CameraActivity extends AppCompatActivity implements SurfaceHolder.C
|
||||
|
||||
Camera.Parameters params = mCamera.getParameters();
|
||||
List<String> focusModes = params.getSupportedFocusModes();
|
||||
for (String fMode : focusModes) {
|
||||
Log.d("kifio", fMode);
|
||||
}
|
||||
|
||||
if (focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
|
||||
params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
|
||||
} else if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
|
||||
@@ -132,6 +137,12 @@ public class CameraActivity extends AppCompatActivity implements SurfaceHolder.C
|
||||
public void surfaceCreated(SurfaceHolder holder) {
|
||||
try {
|
||||
mCamera.setPreviewDisplay(holder);
|
||||
mCamera.startPreview();
|
||||
try {
|
||||
mCamera.autoFocus(autoFocusCallback);
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Log.d("kifio", "surfaceCreated");
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
@@ -147,6 +158,7 @@ public class CameraActivity extends AppCompatActivity implements SurfaceHolder.C
|
||||
@Override
|
||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||
Log.d("kifio", "surfaceDestroyed");
|
||||
mCamera.cancelAutoFocus();
|
||||
}
|
||||
|
||||
void setCameraDisplayOrientation(int cameraId) {
|
||||
@@ -209,24 +221,6 @@ public class CameraActivity extends AppCompatActivity implements SurfaceHolder.C
|
||||
finish();
|
||||
}
|
||||
|
||||
private void initCountours() {
|
||||
|
||||
DisplayMetrics displayMetrics = new DisplayMetrics();
|
||||
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
|
||||
int width = displayMetrics.widthPixels;
|
||||
|
||||
Resources res = getResources();
|
||||
mContours.put("left", (int) res.getDimension(R.dimen.scanner_contour_top));
|
||||
mContours.put("top", (int) res.getDimension(R.dimen.scanner_contour_left));
|
||||
mContours.put("width", (int) res.getDimension(R.dimen.scanner_contour_height));
|
||||
mContours.put("height", width - (2 * (int) res.getDimension(R.dimen.scanner_contour_left)));
|
||||
|
||||
// Log.d("kifio", "left: " + mContours.get("left"));
|
||||
// Log.d("kifio", "top: " + mContours.get("top"));
|
||||
// Log.d("kifio", "width: " + mContours.get("width"));
|
||||
// Log.d("kifio", "height: " + mContours.get("height"));
|
||||
}
|
||||
|
||||
PreviewCallback previewCallback = new PreviewCallback() {
|
||||
public void onPreviewFrame(byte[] data, Camera camera) {
|
||||
|
||||
@@ -235,7 +229,8 @@ public class CameraActivity extends AppCompatActivity implements SurfaceHolder.C
|
||||
|
||||
Image barcode = new Image(size.width, size.height, "Y800");
|
||||
barcode.setData(data);
|
||||
// barcode.setCrop(mContours.get("left"), mContours.get("top"), mContours.get("width"), mContours.get("height"));
|
||||
|
||||
barcode.setCrop((size.width / 2) - mOffset, 0, (size.width / 2) + mOffset, size.height);
|
||||
|
||||
int result = mScanner.scanImage(barcode);
|
||||
|
||||
@@ -255,4 +250,18 @@ public class CameraActivity extends AppCompatActivity implements SurfaceHolder.C
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private Runnable doAutoFocus = new Runnable() {
|
||||
public void run() {
|
||||
if (previewing)
|
||||
mCamera.autoFocus(autoFocusCallback);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
AutoFocusCallback autoFocusCallback = new AutoFocusCallback() {
|
||||
public void onAutoFocus(boolean success, Camera camera) {
|
||||
autoFocusHandler.postDelayed(doAutoFocus, 1000);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -15,12 +15,15 @@ import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
|
||||
import io.flutter.plugin.common.MethodChannel.Result;
|
||||
import com.google.android.gms.iid.InstanceID;
|
||||
import java.util.Map;
|
||||
import java.lang.System;
|
||||
|
||||
public class MainActivity extends FlutterActivity {
|
||||
|
||||
private static final int START_SCANNER_REQUEST_CODE = 2017;
|
||||
private static final String PREF_POS_TOKEN = "pref_pos_token";
|
||||
private static final String PREF_POS_MERCHANT_ID = "pref_pos_merchant_id";
|
||||
private static final String PREF_DOC_ID = "pref_doc_id";
|
||||
private static final String PREF_POS_ID = "pref_pos_id";
|
||||
|
||||
private MethodChannel mChannel;
|
||||
private SharedPreferences mPreferences;
|
||||
@@ -69,6 +72,28 @@ public class MainActivity extends FlutterActivity {
|
||||
case "removeKeys":
|
||||
mPreferences.edit().remove(PREF_POS_TOKEN).apply();
|
||||
mPreferences.edit().remove(PREF_POS_MERCHANT_ID).apply();
|
||||
mPreferences.edit().remove(PREF_DOC_ID).apply();
|
||||
mPreferences.edit().remove(PREF_POS_ID).apply();
|
||||
result.success(null);
|
||||
break;
|
||||
case "getDocID":
|
||||
int docId = mPreferences.getInt(PREF_DOC_ID, 0) + 1;
|
||||
mPreferences.edit().putInt(PREF_DOC_ID, docId).apply();
|
||||
result.success(String.valueOf(docId));
|
||||
break;
|
||||
case "getPosID":
|
||||
|
||||
String posId = mPreferences.getString(PREF_POS_ID, null);
|
||||
|
||||
if (posId == null) {
|
||||
posId = String.valueOf(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
Log.d("kifio", posId);
|
||||
|
||||
mPreferences.edit().putString(PREF_POS_ID, posId).apply();
|
||||
result.success(posId);
|
||||
|
||||
break;
|
||||
default:
|
||||
result.notImplemented();
|
||||
@@ -96,6 +121,10 @@ public class MainActivity extends FlutterActivity {
|
||||
}
|
||||
}
|
||||
|
||||
private void getDocID() {
|
||||
|
||||
}
|
||||
|
||||
private void removeKeys() {
|
||||
|
||||
}
|
||||
@@ -116,6 +145,10 @@ public class MainActivity extends FlutterActivity {
|
||||
|
||||
}
|
||||
|
||||
public void getPosID() {
|
||||
|
||||
}
|
||||
|
||||
public void saveMerchantID() {
|
||||
|
||||
}
|
||||
|
||||
@@ -10,38 +10,35 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
<!-- <LinearLayout android:orientation="vertical"
|
||||
<LinearLayout android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="?attr/actionBarSize">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<View android:layout_height="0dp"
|
||||
android:layout_weight="0.42"
|
||||
android:layout_weight="0.5"
|
||||
android:layout_width="match_parent"
|
||||
android:background="#с0000000"/>
|
||||
|
||||
<FrameLayout android:layout_height="0dp"
|
||||
android:layout_weight="0.16"
|
||||
android:layout_width="match_parent">
|
||||
|
||||
<View android:layout_height="match_parent"
|
||||
android:layout_width="24dp"
|
||||
android:layout_gravity="left"
|
||||
android:background="#с0000000"/>
|
||||
|
||||
<View android:layout_height="match_parent"
|
||||
android:layout_width="24dp"
|
||||
android:layout_gravity="right"
|
||||
android:background="#с0000000"/>
|
||||
|
||||
</FrameLayout>
|
||||
android:background="#с0000000"
|
||||
android:layout_marginBottom="56dp"/>
|
||||
|
||||
<View android:layout_height="0dp"
|
||||
android:layout_weight="0.42"
|
||||
android:layout_weight="0.5"
|
||||
android:layout_width="match_parent"
|
||||
android:background="#с0000000"/>
|
||||
android:background="#с0000000"
|
||||
android:layout_marginTop="56dp"/>
|
||||
|
||||
</LinearLayout> -->
|
||||
</LinearLayout>
|
||||
|
||||
<View android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_gravity="center"
|
||||
android:background="#00ff00"
|
||||
android:layout_marginBottom="56dp"/>
|
||||
|
||||
<View android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_gravity="center"
|
||||
android:background="#00ff00"
|
||||
android:layout_marginTop="56dp"/>
|
||||
|
||||
<android.support.v7.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
|
||||
@@ -42,7 +42,7 @@ class _RegistrationScreenState extends BaseState<FinishRegistrationScreen> {
|
||||
if (_tokenActive) {
|
||||
startScanner(context);
|
||||
} else {
|
||||
checkToken(context).then((response) {
|
||||
checkTokenStatus(context).then((response) {
|
||||
|
||||
print(response.body);
|
||||
Map parsedMap = JSON.decode(response.body);
|
||||
|
||||
25
lib/faq.dart
25
lib/faq.dart
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import 'main.dart';
|
||||
import 'base_state.dart';
|
||||
|
||||
/// Класс содержит заголовки и текст блоков FAQ.
|
||||
class Entry {
|
||||
@@ -33,24 +34,22 @@ class EntryItem extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
/// Экран проведения покупки.
|
||||
class FAQScreen extends StatelessWidget {
|
||||
class FAQScreen extends StatefulWidget {
|
||||
@override State createState() => new FAQScreenState<FAQScreen>();
|
||||
}
|
||||
|
||||
AppBar getAppBar(BuildContext context) {
|
||||
return new AppBar(title: new Text('FAQ', style: new TextStyle(fontSize: 18.0)),
|
||||
backgroundColor: primaryColor, actions: <Widget>[getLogoutButton(context)]);
|
||||
class FAQScreenState<T> extends BaseState<FAQScreen> {
|
||||
|
||||
@override String getTitle() {
|
||||
return "FAQ";
|
||||
}
|
||||
|
||||
getLogoutButton(BuildContext context) {
|
||||
return new IconButton(icon: new Image.asset(logout_png, height: iconHeight, width: iconHeight), onPressed: () => logout(context));
|
||||
}
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return new MaterialApp(home: new Scaffold(appBar: getAppBar(context), body: getBody()));
|
||||
@overide getMenuButtons(BuildContext context) {
|
||||
return <Widget>[getLogoutButton()];
|
||||
}
|
||||
|
||||
/// Метод возвращает ListView с блоками faq.
|
||||
getBody() {
|
||||
@override Widget getScreenContent() {
|
||||
return new ListView.builder(
|
||||
itemBuilder: (BuildContext context, int index) => new EntryItem(data[index]),
|
||||
itemCount: data.length);
|
||||
@@ -64,8 +63,6 @@ class FAQScreen extends StatelessWidget {
|
||||
new Entry('ОБЩАЯ ИНФОРМАЦИЯ', commonGuide)
|
||||
];
|
||||
|
||||
/// TODO: Отформатировать строки
|
||||
|
||||
static const String registrationGuide = '''После запуска приложения вы окажетесь на странице регистрации магазина.
|
||||
Введите DIN код магазина (выдается партнером/менеджером International Auto Club, дублируется на почту)
|
||||
Нажать кнопку: «Зарегистрировать»
|
||||
|
||||
@@ -55,10 +55,28 @@ void main() {
|
||||
}
|
||||
|
||||
/// Проверка статуса токена. Токен может быть активирован, либо не активирован.
|
||||
checkToken(BuildContext context) async {
|
||||
checkTokenStatus(BuildContext context) async {
|
||||
return httpClient.get(intUrl + 'tokens/' + token + '?_dmapptoken=' + intToken);
|
||||
}
|
||||
|
||||
createToken(String merchantId) async {
|
||||
|
||||
String url = intUrl + 'tokens/?_dmapptoken=' + intToken;
|
||||
|
||||
String posID = await platform.invokeMethod('getPosID');
|
||||
print('posID: ${posID}');
|
||||
|
||||
print('merchantId: ${merchantId}');
|
||||
|
||||
// Поле description - необязательное.
|
||||
var body = {
|
||||
'merchant_shop': merchantId,
|
||||
'pos': posID,
|
||||
};
|
||||
|
||||
return httpClient.post(url, body: body);
|
||||
}
|
||||
|
||||
/// Запуск спецефичной для каждой платформы части приложения - сканера.
|
||||
/// Может производиться с нескольких экранов (splash, finish_registration).
|
||||
startScanner(BuildContext context) async {
|
||||
@@ -88,7 +106,7 @@ startScanner(BuildContext context) async {
|
||||
print(response.body);
|
||||
|
||||
List usersList = JSON.decode(response.body);
|
||||
|
||||
print('usersList.length: ${usersList.length}');
|
||||
if (usersList.length > 0) {
|
||||
pushRoute(context, new PurchaseScreen(usersList[0], card));
|
||||
}
|
||||
@@ -105,13 +123,26 @@ startScanner(BuildContext context) async {
|
||||
}
|
||||
|
||||
logout(BuildContext context) {
|
||||
showDialog(context: context, child: new AlertDialog(
|
||||
title: new Text('Подтверждение'),
|
||||
content: new Text('Вы действительно хотите выйти и ввести другой номер магазина?'),
|
||||
actions: <Widget>[
|
||||
new FlatButton(
|
||||
child: new Text('Нет'),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
),
|
||||
new FlatButton(
|
||||
child: new Text('Да'),
|
||||
onPressed: () {
|
||||
if (token != null) {
|
||||
String url = intUrl + 'tokens/' + token + '?_dmapptoken=' + intToken;
|
||||
print(url);
|
||||
httpClient.delete(url).then((response) {
|
||||
httpClient.delete(url).then((response) async {
|
||||
print(response.body);
|
||||
const platform = const MethodChannel('com.dinect.checker/instance_id');
|
||||
platform.invokeMethod('removeKeys');
|
||||
await platform.invokeMethod('removeKeys');
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).pop();
|
||||
pushRoute(context, new RegistrationScreen());
|
||||
}).catchError((error) {
|
||||
@@ -119,7 +150,11 @@ logout(BuildContext context) {
|
||||
});
|
||||
} else {
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
}
|
||||
)]));
|
||||
|
||||
}
|
||||
|
||||
/// Навигация по приложению.
|
||||
|
||||
@@ -27,7 +27,7 @@ class PurchaseScreenState<T> extends BaseState<PurchaseScreen> {
|
||||
}
|
||||
|
||||
Map user;
|
||||
String card;
|
||||
String card = '';
|
||||
String integerPart = '', fractionalPart = '';
|
||||
String loyality = '';
|
||||
|
||||
@@ -40,7 +40,7 @@ class PurchaseScreenState<T> extends BaseState<PurchaseScreen> {
|
||||
getValueWithTitle('Вознаграждение', loyality),
|
||||
getHintLabel(),
|
||||
getDecoratedTextWidget(),
|
||||
buildButton(new EdgeInsets.only(top: 36.0, left: buttonVerticalMargin, right: buttonVerticalMargin), buildRaisedButton(context, 'ЗАВЕРШИТЬ ПОКУПКУ', () => _purchase(context))),
|
||||
buildButton(new EdgeInsets.only(top: 36.0, left: buttonVerticalMargin, right: buttonVerticalMargin), buildRaisedButton(context, 'ЗАВЕРШИТЬ ПОКУПКУ', () => onPurchaseClick(context))),
|
||||
buildButton(new EdgeInsets.only(top: 24.0, left: buttonVerticalMargin, right: buttonVerticalMargin), buildFlatButton(context, 'СКАНИРОВАТЬ', primaryColor))])
|
||||
].reversed.toList()));
|
||||
}
|
||||
@@ -123,7 +123,7 @@ class PurchaseScreenState<T> extends BaseState<PurchaseScreen> {
|
||||
return temporaryInteger + '.' + temporaryFractional;
|
||||
}
|
||||
|
||||
_purchase(BuildContext context) {
|
||||
onPurchaseClick(BuildContext context) {
|
||||
String val = _buildSum();
|
||||
print(val);
|
||||
showDialog(context: context, child: new AlertDialog(
|
||||
@@ -139,10 +139,39 @@ class PurchaseScreenState<T> extends BaseState<PurchaseScreen> {
|
||||
new FlatButton(
|
||||
child: new Text('Да'),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
pushRoute(context, new PurchaseSuccessScreen(val, user['first_name']));
|
||||
purchase(val);
|
||||
},
|
||||
)
|
||||
]));
|
||||
}
|
||||
|
||||
purchase(String sum_total) {
|
||||
|
||||
platform.invokeMethod('getDocID').then((result) {
|
||||
|
||||
String url = user['purchases_url'];
|
||||
|
||||
var body = {
|
||||
'doc_id': result,
|
||||
'curr_iso_code': '643',
|
||||
'commit': 'true',
|
||||
'sum_total': sum_total
|
||||
};
|
||||
|
||||
var headers = {
|
||||
'DM-Authorization': 'dmapptoken 9fec83cdca38c357e6b65dbb17514cdd36bf2a08',
|
||||
'Authorization': 'dmtoken ${token}'
|
||||
};
|
||||
|
||||
httpClient.post(url, body: body, headers: headers).then((response) {
|
||||
|
||||
print(response.body);
|
||||
Navigator.of(context).pop();
|
||||
pushRoute(context, new PurchaseSuccessScreen(sum_total, user['first_name']));
|
||||
|
||||
}).catchError((error) {
|
||||
print(error.toString());
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -54,16 +54,7 @@ class _RegistrationScreenState extends BaseState<RegistrationScreen> {
|
||||
/// Получение от платформы id установки, формирование запроса на получение токена, сохранение токена.
|
||||
_register(BuildContext context) async {
|
||||
|
||||
String url = intUrl + 'tokens/?_dmapptoken=' + intToken;
|
||||
String pos = (new DateTime.now().millisecondsSinceEpoch / 1000).toString();
|
||||
|
||||
// Поле description - необязательное.
|
||||
var body = {
|
||||
'merchant_shop': textFieldValue,
|
||||
'pos': pos,
|
||||
};
|
||||
|
||||
httpClient.post(url, body: body).then((response) {
|
||||
createToken(textFieldValue).then((response) {
|
||||
|
||||
setState(() {
|
||||
error = null;
|
||||
|
||||
@@ -42,27 +42,50 @@ class SplashScreen extends StatelessWidget {
|
||||
pushRoute(context, new RegistrationScreen());
|
||||
} else {
|
||||
|
||||
checkToken(context).then((response) {
|
||||
|
||||
print(response.body);
|
||||
|
||||
Map parsedMap = JSON.decode(response.body);
|
||||
bool active = parsedMap['active'];
|
||||
|
||||
if (active) {
|
||||
// Запускается экран сканера, токен кассы активирован, с его помощью можно делать запросы к pos-api.
|
||||
startScanner(context);
|
||||
} else {
|
||||
// Запускается экран ожидания активации токена.
|
||||
// В реальности токен активируется в админке вручную,
|
||||
// на тестовом сервере токен активируется через несколько минут после создания.
|
||||
pushRoute(context, new FinishRegistrationScreen());
|
||||
}
|
||||
|
||||
checkTokenStatus(context).then((statusResponse) {
|
||||
handleStatusResponse(context, statusResponse);
|
||||
}).catchError((error) {
|
||||
print('Handle exception!');
|
||||
print(error.toString());
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
startRegistration() async {
|
||||
|
||||
}
|
||||
|
||||
handleStatusResponse(BuildContext context, var statusResponse) async {
|
||||
int code = statusResponse.statusCode;
|
||||
print('resp: ${code}');
|
||||
|
||||
if (code == 404) {
|
||||
platform.invokeMethod('removeKeys').then((result) {
|
||||
print('try to start registration');
|
||||
pushRoute(context, new RegistrationScreen());
|
||||
});
|
||||
} else {
|
||||
|
||||
Map statusResponseMap = JSON.decode(statusResponse.body);
|
||||
bool active = statusResponseMap['active'];
|
||||
|
||||
if (active) {
|
||||
startScanner(context);
|
||||
} else {
|
||||
createToken(await platform.invokeMethod('getMerchantID')).then((response) {
|
||||
print('response.body: ${response.body}');
|
||||
|
||||
if (response.statusCode == 409) {
|
||||
pushRoute(context, new FinishRegistrationScreen());
|
||||
} else {
|
||||
startRegistration();
|
||||
}
|
||||
|
||||
}).catchError((error) {
|
||||
platform.invokeMethod('removeKeys').then((result) => pushRoute(context, new RegistrationScreen()));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user