diff --git a/README.md b/README.md
index d2edd42..284ed3f 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,66 @@
-Приложение Checker.
+#Приложение Checker.
Для запуска необходимо установить [Dart](https://www.dartlang.org/install) - язык программирования и
[flutter](https://flutter.io/setup/) - фреймворк для создания кроссплатформенных мобильных приложений на этом языке.
-# Перед тем, как собирать приложение, необходимо в файле lib/consts.dart установить правильное значение appName. Для автоклуба - это AutoBonus.
Для сборки и запуска приложения используются команды flutter run (собирает debug apk, устанавливает его на устройство) и
-flutter build (собирает release apk, не устанавливает на устрйоство).
+flutter build (собирает release apk, не устанавливает на устройство).
Команды run и build необходимо выполнять с опцией --flavor, чтобы apk файл собирался с необходимыми ресурсами и настройками.
-Название конкретной flavor передается в аргументе. Все flavors перечислены в файле android/app/build.gradle.
\ No newline at end of file
+Название конкретной flavor передается в аргументе. Все flavors перечислены в файле android/app/build.gradle.
+
+#Добавление брендированного приложения
+
+Для добавления брендированного приложения с названием %name% необходимо:
+
+1) В каталог assets/ положить изображения %name%_logo.png и %name%_splash.png
+ В качестве splash очень желательно использовать квадрат белого цвета 100x100.
+
+2) В файл pubscpec.yaml в раздел assets/ добавить пути этих изображений.
+
+3) В файл lib/resources.dart в методы ```getPrimaryColor``` и ```getButtonsColor```
+ добавить цвета необходимые цвета.*
+
+4) В файле consts.dart изменить значения переменных appName, url, appToken на правильные для сборки значения.*
+
+5) В файл android/app/build.gradle в раздел productFlavors добавить блок следующего вида:
+```
+%name% {
+ applicationId 'com.dinect.autobonus'
+ buildConfigField "String", "locale", "\"ru\""
+ buildConfigField "String", "flavor", "\"%name%\""
+ buildConfigField "int", "currency", "643"
+ buildConfigField "String", "supportPhone", "\"8-800-234-6064\""
+ buildConfigField "String", "supportUrl", "\"https://www.auto-club.biz\""
+}
+```
+
+где все параметры необходимо заменить на соответствующие приложению значения.
+
+6) В каталог android/app/src/ добавить каталоги %name%/res в которых воссоздать структуру ресурсов аналогичную представленной в каталоге android/app/src/pip/res/:
+Каталоги mipmap должны содержать иконки, каталоги values должны содержать .xml файлы с названием приложения в следующем формате:
+```
+
+ %name%
+
+```
+
+
+Иконки проще всего нарезать тут:
+https://romannurik.github.io/AndroidAssetStudio/icons-launcher.html
+
+В качестве Foreground выбрать иконку приложения размером 512x512, выставить необходимые параметры и скачать архив с нарещанными иконками.
+
+После выполнения всех этих пунктов появится возможность собирать приложение
+как описано выше(flutter run --flavor %name% либо flutter build apk --flavor %name%).
+
+\* - параметры из этих пунктов будут при первой же возможности перенесены в пункт 5, чтобы менять их из одного места.
+
+#Добавление локализации приложения
+
+1) В каталог lib/i18n добавить файл messages_%locale%.dart.
+Файл делать по аналогии с messages_en.dart. Либо с messages_ru.dart.
+
+2) В каталог android/app/src/main/res добавить каталог values-%locale% с единственным файлом strings.xml.
+Файл должен иметь структуру полностью аналогичную файлу android/app/src/main/res/values/strings.xml, измениться должны только значения для строк.
\ No newline at end of file
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 7bef710..b1031b6 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -42,40 +42,22 @@ android {
productFlavors {
- autobonus_en {
- applicationId 'com.dinect.autobonus'
- buildConfigField "String", "locale", "\"en\""
- buildConfigField "String", "flavor", "\"autobonus\""
- }
-
- autobonus_ru {
+ autobonus {
applicationId 'com.dinect.autobonus'
buildConfigField "String", "locale", "\"ru\""
buildConfigField "String", "flavor", "\"autobonus\""
+ buildConfigField "int", "currency", "643"
+ buildConfigField "String", "supportPhone", "\"8-800-234-6064\""
+ buildConfigField "String", "supportUrl", "\"https://www.auto-club.biz\""
}
- autobonus_ua {
- applicationId 'com.dinect.autobonus'
- buildConfigField "String", "locale", "\"ua\""
- buildConfigField "String", "flavor", "\"autobonus\""
- }
-
- pip_en {
- applicationId 'com.dinect.pip'
- buildConfigField "String", "locale", "\"en\""
- buildConfigField "String", "flavor", "\"pip\""
- }
-
- pip_ru {
- applicationId 'com.dinect.pip'
- buildConfigField "String", "locale", "\"ru\""
- buildConfigField "String", "flavor", "\"pip\""
- }
-
- pip_ua {
+ pip {
applicationId 'com.dinect.pip'
buildConfigField "String", "locale", "\"ua\""
buildConfigField "String", "flavor", "\"pip\""
+ buildConfigField "int", "currency", "980"
+ buildConfigField "String", "supportPhone", "\"+38 080 030 9997\\n+38 044 390 1697\""
+ buildConfigField "String", "supportUrl", "\"http://discount.kiev.ua/\""
}
}
@@ -84,20 +66,11 @@ android {
main.jniLibs.srcDir 'jniLibs'
- pip_ua {
+ pip {
res.srcDirs = ['src/pip/res']
manifest.srcFile 'src/pip/AndroidManifest.xml'
}
- pip_ru {
- res.srcDirs = ['src/pip/res']
- manifest.srcFile 'src/pip/AndroidManifest.xml'
- }
-
- pip_en {
- res.srcDirs = ['src/pip/res']
- manifest.srcFile 'src/pip/AndroidManifest.xml'
- }
}
}
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index cda80be..fd3a3fc 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -2,7 +2,7 @@
+ android:versionName="1.1.0">
diff --git a/android/app/src/main/java/com/dinect/checker/AbstractScannerActivity.java b/android/app/src/main/java/com/dinect/checker/AbstractScannerActivity.java
index 6e2a1ff..8aea8a7 100644
--- a/android/app/src/main/java/com/dinect/checker/AbstractScannerActivity.java
+++ b/android/app/src/main/java/com/dinect/checker/AbstractScannerActivity.java
@@ -23,27 +23,36 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.Bundle;
-import android.os.Handler;
import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.util.Pair;
+import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;
+import android.widget.EditText;
import android.widget.FrameLayout;
-import android.widget.Toast;
import android.widget.TextView;
+import android.widget.Toast;
import com.dinect.checker.net.ApiClient;
-import java.util.Queue;
-import java.util.concurrent.ArrayBlockingQueue;
-import java.util.concurrent.atomic.AtomicInteger;
+import org.json.JSONArray;
+import org.json.JSONException;
+
+import java.io.IOException;
+import java.util.Locale;
+
+import okhttp3.Call;
+import okhttp3.Callback;
+import okhttp3.Response;
+import okhttp3.ResponseBody;
/**
@@ -54,26 +63,13 @@ public abstract class AbstractScannerActivity extends AppCompatActivity {
private final static String TAG = "Checker.ScannerActivity";
- private static final String[] CLICK_MESSAGES = {
- "Там ничего нет.",
- "Зачем ты это делаешь?",
- "Перестань!",
- "Ну и зачем?..",
- };
-
- private final AtomicInteger counter = new AtomicInteger(0);
- private int mColor;
+ private int counter;
public static final String SCAN_MODES = "SCAN_MODES";
public static final String ERROR_INFO = "ERROR_INFO";
-
- protected AppCompatActivity ctx;
- protected ApiClient apiClient;
- protected NetworkThread networkThread;
- protected DecrementCounterThread counterThread;
protected LogoutDialogFragment logoutDialog;
- protected NotificationThread notificationThread;
+ private ApiClient mClient;
boolean isCameraAvailable() {
Log.d(TAG, "isCameraAvailable");
@@ -86,7 +82,15 @@ public abstract class AbstractScannerActivity extends AppCompatActivity {
final Intent response = new Intent();
response.putExtra(ERROR_INFO, message);
setResult(RESULT_CANCELED, response);
- notificationThread = null;
+ }
+
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ final String appToken = getIntent().getStringExtra(MainActivity.PREF_APP_TOKEN);
+ final String token = getIntent().getStringExtra(MainActivity.PREF_POS_TOKEN);
+ final String url = getIntent().getStringExtra(MainActivity.PREF_API_URL) + "/users/";
+ mClient = new ApiClient(url, appToken, token);
}
/**
@@ -103,9 +107,6 @@ public abstract class AbstractScannerActivity extends AppCompatActivity {
cancelRequest("Camera unavailable");
return false;
}
- ctx = this;
- notificationThread = new NotificationThread(this);
- notificationThread.start();
// Hide the window title.
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(layoutID);
@@ -115,120 +116,65 @@ public abstract class AbstractScannerActivity extends AppCompatActivity {
/**
* Configure toolbar of app
*/
- protected final void initToolbar(final int toolbarId, final @NonNull String title) {
- Log.d(TAG, "initToolbar");
- final Toolbar toolbar = (Toolbar) findViewById(toolbarId);
- mColor = (int) getIntent().getLongExtra(MainActivity.PREF_APP_BAR_COLOR, 0xffffff);
- toolbar.setBackgroundColor(mColor);
+ protected final void initToolbar(Intent intent) {
+
+ final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
+ toolbar.setBackgroundColor((int) intent.getLongExtra(MainActivity.PREF_APP_BAR_COLOR, 0xffffff));
setSupportActionBar(toolbar);
final ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
- actionBar.setTitle(title);
+ actionBar.setTitle(null);
actionBar.setDisplayHomeAsUpEnabled(false);
}
+
+ initManualInput();
setupSecretClickHandler(toolbar);
}
- private void setupSecretClickHandler(final @NonNull Toolbar toolbar) {
+ private void initManualInput() {
+ EditText manualInput = (EditText) findViewById(R.id.manual_input);
+
+
+ manualInput.setOnEditorActionListener(new TextView.OnEditorActionListener() {
+ @Override
+ public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+ handleBarcode(v.getText().toString());
+ return false;
+ }
+ });
+
+ }
+
+ private void setupSecretClickHandler(final @NonNull View toolbar) {
// Configure increment handler
- counterThread = new DecrementCounterThread(counter, 700L);
toolbar.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
- String toastMessage = null;
- switch (counter.incrementAndGet()) {
- case 1:
- if (false == counterThread.isRunning()) {
- counterThread.start();
- }
- break;
- case 5:
- toastMessage = CLICK_MESSAGES[0];
- break;
- case 11:
- toastMessage = CLICK_MESSAGES[1];
- break;
- case 17:
- toastMessage = CLICK_MESSAGES[2];
- break;
- case 23:
- toastMessage = null;
- counterThread.pause();
- Toast.makeText(ctx, CLICK_MESSAGES[3], Toast.LENGTH_SHORT).show();
- switchScanner();
- break;
- }
- Log.d(TAG, "toolbar clicked " + counter.get() + " times");
-
- if (null != toastMessage) {
- notificationThread.addMessage(toastMessage);
+ if (counter == 15) {
+ switchScanner();
+ } else {
+ counter++;
}
+ Log.d(TAG, "toolbar clicked " + counter + " times");
}
});
}
-
- private class DecrementCounterThread extends Thread {
- final long delay;
- final AtomicInteger counter;
- private boolean running = false;
- private int previous = 0;
-
- public DecrementCounterThread(final AtomicInteger counter, final long delay) {
- // Configure decrement handler
- Log.d(TAG, "setupSecretClickHandler: DecrementCounterThread()");
- this.counter = counter;
- this.delay = delay;
- }
-
- @Override
- public void run() {
- running = true;
- while (running) {
- try {
- Thread.sleep(delay);
- if (counter.get() > 0) {
- if (previous > counter.get()) {
- previous = counter.decrementAndGet();
- Log.d(TAG, "decrement counter, now " + counter.get());
- } else {
- previous = counter.get();
- }
- }
- } catch (final IllegalArgumentException | InterruptedException e) {
- Log.d(TAG, "disable counter decrease Thread", e);
- }
- }
- }
-
- public boolean isRunning() {
- return running;
- }
-
- public void pause() {
- Log.d(TAG, "pause decrementer");
- running = false;
- }
- }
-
private void switchScanner() {
- final SharedPreferences prefs = getSharedPreferences("MainActivity", Context.MODE_PRIVATE);
- int idx = prefs.getInt(MainActivity.SCANNER_BACKEND_KEY, 0);
- Log.d(TAG, "current scanner backend " + idx + ", " + MainActivity.SCANNER_BACKEND[idx].toString());
- if (idx >= MainActivity.SCANNER_BACKEND.length - 1) {
- idx = 0;
- } else {
- idx++;
- }
+ final SharedPreferences prefs = getSharedPreferences("scanner", Context.MODE_PRIVATE);
+
+ int idx = (prefs.getInt(MainActivity.SCANNER_BACKEND_KEY, 0) == MainActivity.ZXING)
+ ? MainActivity.ZBAR
+ : MainActivity.ZXING;
+
Log.d(TAG, "switch to scanner backend " + idx + ", " + MainActivity.SCANNER_BACKEND[idx].toString());
prefs.edit().putInt(MainActivity.SCANNER_BACKEND_KEY, idx).apply();
- final Intent response = new Intent();
- response.putExtra("item", "restartScanner");
cancelRequest("Scanner backend changed");
+ setResult(RESULT_OK);
finish();
}
@@ -244,51 +190,60 @@ public abstract class AbstractScannerActivity extends AppCompatActivity {
protected abstract View initScanner();
- /**
- * Initialize network client
- */
- protected final void initNetwork(final Intent intent) {
- Log.d(TAG, "initNetwork");
- final String url = intent.getStringExtra(MainActivity.PREF_API_URL);
- final String appToken = intent.getStringExtra(MainActivity.PREF_APP_TOKEN);
- final String token = intent.getStringExtra(MainActivity.PREF_POS_TOKEN);
-
- Log.d(TAG, "initializing addScanner activity with url "
- + url + ", appToken " + appToken + ", token " + token);
-
- apiClient = new ApiClient(url, appToken, token);
- }
-
- /**
- * Handles barcode.
- * Makes network call in separate thread and call
- * networkResponseCallback
- *
- * @param card scanned card number
- */
public void handleBarcode(final @NonNull String card) {
- Log.d(TAG, "handleBarcode");
- notificationThread.addMessage(card);
- networkThread = new NetworkThread(this, apiClient);
- networkThread.card(card).start();
+ mClient.findUser(card, new Callback() {
+ @Override
+ public void onFailure(Call call, IOException e) {
+ handleFail(card);
+ }
+
+ @Override
+ public void onResponse(Call call, Response response) throws IOException {
+ try {
+ ResponseBody body = response.body();
+ if (body != null) {
+ switch (response.code()) {
+ case 200:
+ final JSONArray users = new JSONArray(body.string());
+ if (users.length() > 0) {
+ handleSuccess(card, users.get(0).toString());
+ } else {
+ handleFail(card);
+ }
+ break;
+ case 204:
+ handleFail(card);
+ break;
+ }
+ }
+ } catch (final IOException | JSONException e) {
+ Log.e(TAG, e.getMessage(), e);
+ handleFail(card);
+ }
+ }
+ });
}
- protected final void networkResponseCallback(final @NonNull Pair result) {
- Log.d(TAG, "networkResponseCallback");
- if (null != result.first) {
- Log.d(TAG, "user found, finish activity with result");
- final Intent intent = new Intent();
- intent.putExtra("user", result.second);
- intent.putExtra("card", result.first);
- setResult(RESULT_OK, intent);
- networkThread.cancel();
- notificationThread.cancel();
- finish();
- } else {
- if (null != result.second) {
- notificationThread.addMessage(result.second);
+ protected final void handleSuccess(final String card, final String user) {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ setResult(RESULT_OK, new Intent().putExtra("user", user).putExtra("card", card));
+ finish();
}
- }
+ });
+ }
+
+ protected final void handleFail(final String card) {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ String message = String.format(getString(R.string.identifier_not_found), card)
+ + ".\n"
+ + String.format(getString(R.string.error_contact_support), BuildConfig.supportPhone);
+ Toast.makeText(AbstractScannerActivity.this, message, Toast.LENGTH_SHORT).show();
+ }
+ });
}
@Override
@@ -297,10 +252,25 @@ public abstract class AbstractScannerActivity extends AppCompatActivity {
return true;
}
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ menu.findItem(R.id.settings).setIcon(getResources().getDrawable(R.drawable.settings));
+ menu.findItem(R.id.faq).setIcon(getResources().getDrawable(R.drawable.help));
+ menu.findItem(R.id.logout).setIcon(getResources().getDrawable(R.drawable.logout));
+ return super.onPrepareOptionsMenu(menu);
+ }
+
@Override
public boolean onOptionsItemSelected(MenuItem item) {
- if (item.getItemId() == R.id.logout) {
- logoutDialog = LogoutDialogFragment.newInstance(mColor);
+ if (item.getItemId() == R.id.settings) {
+ final Intent intent = new Intent();
+ intent.putExtra("item", "settings");
+ setResult(RESULT_OK, intent);
+ finish();
+ return true;
+ } else if (item.getItemId() == R.id.logout) {
+ int color = (int) getIntent().getLongExtra(MainActivity.PREF_APP_BAR_COLOR, 0xffffff);
+ logoutDialog = LogoutDialogFragment.newInstance(color);
logoutDialog.show(getFragmentManager(), "logout");
return true;
} else if (item.getItemId() == R.id.faq) {
@@ -366,54 +336,4 @@ public abstract class AbstractScannerActivity extends AppCompatActivity {
return builder.create();
}
}
-
- private class NotificationThread extends Thread {
-
- private final static int MAX_NOTIFICATION_MESSAGES = 2;
-
- private boolean run = true;
- private final Queue queue;
- private final AbstractScannerActivity ctx;
-
- public NotificationThread(final @NonNull AbstractScannerActivity ctx) {
- this.queue = new ArrayBlockingQueue<>(MAX_NOTIFICATION_MESSAGES);
- this.ctx = ctx;
- }
-
- @Override
- public void run() {
- while (run) {
- if (null != queue.peek()) {
- Log.d(TAG, "null != queue.peek()");
- final String message = queue.poll();
- Log.d(TAG, "message: " + message);
- if (null != message) {
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- Toast.makeText(ctx, message, Toast.LENGTH_SHORT).show();
- }
- });
- }
- }
- try {
- Thread.sleep(300);
- } catch (final InterruptedException ie) {
- run = false;
- }
- }
- }
-
- public void addMessage(final @NonNull String message) {
- if (queue.size() == MAX_NOTIFICATION_MESSAGES) {
- Log.d(TAG, "Discard message: " + queue.poll());
- }
- queue.add(message);
- Log.d(TAG, "Add message: " + message);
- }
-
- public void cancel() {
- run = false;
- }
- }
}
diff --git a/android/app/src/main/java/com/dinect/checker/MainActivity.java b/android/app/src/main/java/com/dinect/checker/MainActivity.java
index 98bd57b..11cf72a 100644
--- a/android/app/src/main/java/com/dinect/checker/MainActivity.java
+++ b/android/app/src/main/java/com/dinect/checker/MainActivity.java
@@ -1,28 +1,31 @@
package com.dinect.checker;
-import android.os.Bundle;
-import android.content.Intent;
-import android.util.Log;
-import android.widget.Toast;
import android.content.Context;
-import android.content.SharedPreferences;
+import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.os.Bundle;
+import android.util.Log;
+import android.widget.Toast;
+
+import com.dinect.checker.net.ApiClient;
import com.dinect.checker.zbar.CameraActivity;
import com.dinect.checker.zxing.ScannerActivity;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
import java.util.Locale;
+import java.util.Map;
import io.flutter.app.FlutterActivity;
-import io.flutter.plugins.GeneratedPluginRegistrant;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
-
-import java.util.Map;
-import java.util.ArrayList;
-import java.lang.System;
-import java.util.Set;
+import io.flutter.plugins.GeneratedPluginRegistrant;
public class MainActivity extends FlutterActivity {
@@ -30,155 +33,136 @@ public class MainActivity extends FlutterActivity {
private static final int START_SCANNER_REQUEST_CODE = 2017;
- 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";
- static final String PREF_API_URL = "prefs_api_token";
- static final String PREF_APP_TOKEN = "pres_app_token";
- static final String PREF_POS_TOKEN = "pref_pos_token";
+ public static final String PREF_API_URL = "prefs_api_token";
+ public static final String PREF_APP_TOKEN = "pres_app_token";
+ public static final String PREF_POS_TOKEN = "pref_pos_token";
static final String PREF_APP_BAR_COLOR = "pref_app_bar_color";
+ public static final int ZXING = 0;
+ public static final int ZBAR = 1;
+
static final Class[] SCANNER_BACKEND = {
ScannerActivity.class,
CameraActivity.class,
};
+
static final String SCANNER_BACKEND_KEY = "scanner_backend_idx";
private MethodChannel mChannel;
- private SharedPreferences mPreferences;
+ private Map mScannerArgs;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(this);
- initLocale(this);
- mPreferences = getPreferences(Context.MODE_PRIVATE);
-
- Log.d(TAG, "application prefs:");
- for(final Map.Entry kv: mPreferences.getAll().entrySet()){
- Log.d(TAG, " key = " + kv.getKey() + ", value = " + kv.getValue().toString());
- }
-
mChannel = new MethodChannel(getFlutterView(), "com.dinect.checker/instance_id");
mChannel.setMethodCallHandler(
new MethodCallHandler() {
@Override
public void onMethodCall(MethodCall call, Result result) {
- switch (call.method) {
- case "saveToken":
- Map tokenArguments = call.arguments();
- mPreferences.edit().putString(PREF_POS_TOKEN, (String) tokenArguments.get("token")).apply();
- break;
- case "getToken":
- result.success(mPreferences.getString(PREF_POS_TOKEN, null));
- break;
- case "saveMerchantID":
- Map merchantIDArguments = call.arguments();
- mPreferences.edit().putString(PREF_POS_MERCHANT_ID, (String) merchantIDArguments.get("merchantID")).apply();
- break;
- case "getLocale":
- result.success(BuildConfig.locale);
- break;
- case "getFlavor":
- result.success(BuildConfig.flavor);
- break;
- case "getMerchantID":
- result.success(mPreferences.getString(PREF_POS_MERCHANT_ID, null));
- break;
- case "startScanner":
- final Map arguments = call.arguments();
- final int idx = mPreferences.getInt(SCANNER_BACKEND_KEY, 0);
- Log.d(TAG, "use " + SCANNER_BACKEND[idx].toString() + " backend, with idx = " + idx);
- Intent cameraIntent = new Intent(MainActivity.this, SCANNER_BACKEND[idx]);
- cameraIntent.putExtra(PREF_API_URL, (String) arguments.get("url"));
- cameraIntent.putExtra(PREF_APP_TOKEN, (String) arguments.get("appToken"));
- cameraIntent.putExtra(PREF_POS_TOKEN, (String) arguments.get("token"));
- cameraIntent.putExtra(PREF_APP_BAR_COLOR, (Long) arguments.get("color"));
- startActivityForResult(cameraIntent, START_SCANNER_REQUEST_CODE);
- break;
- 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 "isOnline":
- boolean online = Utils.isOnline(MainActivity.this);
- if (!online) {
- Toast.makeText(MainActivity.this, "Проверьте интернет соединение", Toast.LENGTH_SHORT).show();
- }
- result.success(online);
- break;
- case "getPosID":
- String posId = mPreferences.getString(PREF_POS_ID, null);
- if (posId == null) {
- posId = String.valueOf(System.currentTimeMillis());
- }
- mPreferences.edit().putString(PREF_POS_ID, posId).apply();
- result.success(posId);
- break;
- default:
- result.notImplemented();
- break;
- }
+ callMethod(call, result);
}
});
}
+ private void callMethod(MethodCall call, Result result) {
+ switch (call.method) {
+ case "getLocale":
+ result.success(getLanguage());
+ break;
+ case "getFlavor":
+ result.success(BuildConfig.flavor);
+ break;
+ case "getCurrency":
+ result.success(BuildConfig.currency);
+ break;
+ case "startScanner":
+ mScannerArgs = call.arguments();
+ startScannerActivity();
+ break;
+ case "isOnline":
+ checkInternetConnection(result);
+ break;
+ case "getSupportPhone":
+ result.success(BuildConfig.supportPhone);
+ break;
+ case "getSupportUrl":
+ result.success(BuildConfig.supportUrl);
+ break;
+ default:
+ result.notImplemented();
+ break;
+ }
+ }
+
+ private String getLanguage() {
+ List availableLanguages = Arrays.asList("ru", "en");
+ if (availableLanguages.contains(Locale.getDefault().getLanguage())) {
+ return Locale.getDefault().getLanguage();
+ } else {
+ return BuildConfig.locale;
+ }
+ }
+
+ private void checkInternetConnection(Result result) {
+ boolean connected = Utils.isOnline(this);
+ if (!connected)
+ Toast.makeText(this, "Проверьте интернет соединение", Toast.LENGTH_SHORT).show();
+ result.success(connected);
+ }
+
+ private void setLocale(String locale) {
+ Resources res = getResources();
+ Configuration configuration = new Configuration(res.getConfiguration());
+ configuration.locale = new Locale(locale);
+ Locale.setDefault(configuration.locale);
+ res.updateConfiguration(configuration, res.getDisplayMetrics());
+ }
+
+ private void startScannerActivity() {
+ final int idx = getSharedPreferences("scanner", Context.MODE_PRIVATE).getInt(SCANNER_BACKEND_KEY, 0);
+ Intent cameraIntent = new Intent(MainActivity.this, SCANNER_BACKEND[idx]);
+ cameraIntent.putExtra(PREF_API_URL, (String) mScannerArgs.get("url"));
+ cameraIntent.putExtra(PREF_APP_TOKEN, (String) mScannerArgs.get("appToken"));
+ cameraIntent.putExtra(PREF_POS_TOKEN, (String) mScannerArgs.get("token"));
+ cameraIntent.putExtra(PREF_APP_BAR_COLOR, (Long) mScannerArgs.get("color"));
+ setLocale((String) mScannerArgs.get("locale"));
+ startActivityForResult(cameraIntent, START_SCANNER_REQUEST_CODE);
+ }
+
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (requestCode == START_SCANNER_REQUEST_CODE && resultCode == RESULT_CANCELED) {
- finish();
- } else if (requestCode == START_SCANNER_REQUEST_CODE && resultCode == RESULT_OK) {
- if (data != null) {
- String user = data.getExtras().getString("user", null);
- if (user != null) {
- String card = data.getExtras().getString("card", null);
- ArrayList args = new ArrayList<>(2);
- args.add(user);
- args.add(card);
- mChannel.invokeMethod("purchase", args);
- } else {
- String menuItem = data.getExtras().getString("item", null);
- Log.d(TAG, menuItem);
- if (menuItem != null) {
- mChannel.invokeMethod(menuItem, null);
+ if (requestCode == START_SCANNER_REQUEST_CODE) {
+ if (resultCode == RESULT_CANCELED) {
+ finish();
+ } else if (resultCode == RESULT_OK) {
+ if (data != null) {
+ String user = data.getExtras().getString("user", null);
+ if (user != null) {
+ String card = data.getExtras().getString("card", null);
+ ArrayList args = new ArrayList<>(2);
+ args.add(user);
+ args.add(card);
+ mChannel.invokeMethod("purchase", args);
+ } else {
+ String menuItem = data.getExtras().getString("item", null);
+ Log.d(TAG, menuItem);
+ if (menuItem != null) {
+ mChannel.invokeMethod(menuItem, null);
+ }
}
+ } else {
+ startScannerActivity();
}
}
}
}
- public static void initLocale(Context context) {
- Resources res = context.getResources();
- Configuration configuration = new Configuration(res.getConfiguration());
- switch (BuildConfig.locale) {
- case "en":
- configuration.locale = new Locale("en");
- Locale.setDefault(configuration.locale);
- res.updateConfiguration(configuration, res.getDisplayMetrics());
- break;
- case "ru":
- configuration.locale = new Locale("ru");
- Locale.setDefault(configuration.locale);
- res.updateConfiguration(configuration, res.getDisplayMetrics());
- break;
- case "ua":
- configuration.locale = new Locale("ua");
- Locale.setDefault(configuration.locale);
- res.updateConfiguration(configuration, res.getDisplayMetrics());
- break;
- }
+ public void getFlavor() {
}
- public void getFlavor() {
+ public void getCurrency() {
}
@@ -186,15 +170,7 @@ public class MainActivity extends FlutterActivity {
}
- public void handleItemClick() {
-
- }
-
- public void getDocID() {
-
- }
-
- public void removeKeys() {
+ public void setUserLocale() {
}
@@ -202,32 +178,16 @@ public class MainActivity extends FlutterActivity {
}
- public void getInstanceID() {
-
- }
-
- public void saveToken() {
-
- }
-
- public void getToken() {
-
- }
-
- public void getPosID() {
-
- }
-
- public void saveMerchantID() {
-
- }
-
- public void getMerchantID() {
-
- }
-
public void isOnline() {
}
+ public void getSupportPhone() {
+
+ }
+
+ public void getSupportUrl() {
+
+ }
+
}
diff --git a/android/app/src/main/java/com/dinect/checker/NetworkThread.java b/android/app/src/main/java/com/dinect/checker/NetworkThread.java
deleted file mode 100644
index e1288fd..0000000
--- a/android/app/src/main/java/com/dinect/checker/NetworkThread.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2017 .
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.dinect.checker;
-
-import android.support.annotation.NonNull;
-import android.util.Log;
-import android.util.Pair;
-
-import com.dinect.checker.net.ApiClient;
-
-/**
- * Created by anonymous on 03.08.17.
- */
-
-public final class NetworkThread extends Thread {
-
- private static final String TAG = "Checker.NetworkThread";
-
- private AbstractScannerActivity activity;
- private final ApiClient client;
- private String card;
-
- /**
- * @param activity caller activity (with networkResponseCallback())
- * @param client ApiClient instance
- */
- public NetworkThread(final @NonNull AbstractScannerActivity activity, final @NonNull ApiClient client) {
- this.activity = activity;
- this.client = client;
- }
-
- @Override
- public void run() {
- if (null != activity) {
- final Pair response = client.findUser(activity, card);
- Log.d(TAG, "network request done with result: " + response.first);
- activity.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- activity.networkResponseCallback(response);
- }
- });
- }
- }
-
- /**
- * Set card for network call
- *
- * @parm card number to search
- */
- public NetworkThread card(final @NonNull String card) {
- this.card = card;
- return this;
- }
-
- void cancel() {
- activity = null;
- }
-}
diff --git a/android/app/src/main/java/com/dinect/checker/Utils.java b/android/app/src/main/java/com/dinect/checker/Utils.java
index b4987f2..5175eeb 100644
--- a/android/app/src/main/java/com/dinect/checker/Utils.java
+++ b/android/app/src/main/java/com/dinect/checker/Utils.java
@@ -11,8 +11,11 @@ public class Utils {
}
public static boolean isOnline(Context context) {
- ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
- NetworkInfo netInfo = cm.getActiveNetworkInfo();
+ NetworkInfo netInfo = getConnectivityManager(context).getActiveNetworkInfo();
return netInfo != null && netInfo.isConnected();
}
+
+ private static ConnectivityManager getConnectivityManager(Context context) {
+ return (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ }
}
\ No newline at end of file
diff --git a/android/app/src/main/java/com/dinect/checker/net/ApiClient.java b/android/app/src/main/java/com/dinect/checker/net/ApiClient.java
index 3ea5cbb..95de9e6 100644
--- a/android/app/src/main/java/com/dinect/checker/net/ApiClient.java
+++ b/android/app/src/main/java/com/dinect/checker/net/ApiClient.java
@@ -15,101 +15,44 @@
*/
package com.dinect.checker.net;
-import android.content.Context;
import android.support.annotation.NonNull;
-import android.util.Log;
-import android.util.Pair;
-import org.json.JSONArray;
-import org.json.JSONException;
-
-import java.lang.String;
-import java.io.IOException;
import java.util.concurrent.TimeUnit;
+import okhttp3.Callback;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
-import okhttp3.Response;
-
-import com.dinect.checker.R;
/**
* Created by anonymous
*/
-
public final class ApiClient {
private static final String TAG = "Checker.ApiClient";
- private static final int TIMEOUT_CONNECTION = 3;
- private static final int TIMEOUT_READ = 3;
- private static final int TIMEOUT_WRITE = 3;
+ private static final int TIMEOUT = 3;
- public final String endpoint;
- public final String appToken;
- public final String token;
+ private OkHttpClient mHttp;
+ private String mEndpoint;
-
- final OkHttpClient http;
-
- /**
- * @param endpoint POS API endpoint
- * @param appToken Application Token
- * @param token POS token
- */
- public ApiClient(final @NonNull String endpoint, final @NonNull String appToken, final @NonNull String token) {
- this.endpoint = endpoint;
- this.appToken = appToken;
- this.token = token;
-
- http = new OkHttpClient().
+ public ApiClient(final String url, final @NonNull String appToken, final @NonNull String token) {
+ mEndpoint = url;
+ mHttp = new OkHttpClient().
newBuilder()
- .connectTimeout(TIMEOUT_CONNECTION, TimeUnit.SECONDS)
- .readTimeout(TIMEOUT_READ, TimeUnit.SECONDS)
- .writeTimeout(TIMEOUT_WRITE, TimeUnit.SECONDS)
+ .connectTimeout(TIMEOUT, TimeUnit.SECONDS)
+ .readTimeout(TIMEOUT, TimeUnit.SECONDS)
+ .writeTimeout(TIMEOUT, TimeUnit.SECONDS)
.addInterceptor(new DinectAuthorizationInterceptor(appToken, token, "checker/0.1", true))
.build();
}
-
- /***
- *
- * @param card card/foreigncarf number
- * @return (null, error) on fail or (card, user) info on success
- */
- public Pair findUser(Context ctx, final @NonNull String card) {
-
- final Request.Builder builder = new Request.Builder();
- final Request request;
-
- final HttpUrl.Builder httpBuilder = HttpUrl.parse(endpoint + "/users/").newBuilder();
-
- httpBuilder.addQueryParameter("auto", card);
- request = builder
- .url(httpBuilder.build())
- .build();
-
- try {
- final Response response = http.newCall(request).execute();
- final String body = response.body().string();
- final String NOT_FOUND_MESSAGE = String.format(ctx.getString(R.string.identifier_not_found, card));
- switch (response.code()) {
- case 200:
- final JSONArray users = new JSONArray(body);
- if (users.length() > 0) {
- return new Pair<>(card, users.get(0).toString());
- } else {
- return new Pair<>(null, NOT_FOUND_MESSAGE);
- }
- case 204:
- return new Pair<>(null, NOT_FOUND_MESSAGE);
- default:
- return new Pair<>(null, "Что-то пошло не так");
- }
- } catch (final IOException | JSONException e) {
- Log.e(TAG, e.getMessage(), e);
- return new Pair<>(null, "Упс...");
+ public void findUser(String card, Callback callback) {
+ final Request.Builder requestBuilder = new Request.Builder();
+ final HttpUrl url = HttpUrl.parse(mEndpoint);
+ if (url != null) {
+ HttpUrl.Builder httpBuilder = url.newBuilder().addQueryParameter("auto", card);
+ mHttp.newCall(requestBuilder.url(httpBuilder.build()).build()).enqueue(callback);
}
}
}
diff --git a/android/app/src/main/java/com/dinect/checker/net/DinectAuthorizationInterceptor.java b/android/app/src/main/java/com/dinect/checker/net/DinectAuthorizationInterceptor.java
index 9d39896..edc4588 100644
--- a/android/app/src/main/java/com/dinect/checker/net/DinectAuthorizationInterceptor.java
+++ b/android/app/src/main/java/com/dinect/checker/net/DinectAuthorizationInterceptor.java
@@ -79,8 +79,6 @@ public final class DinectAuthorizationInterceptor implements Interceptor {
}
final Request request = requestBuilder.url(url).headers(headers).build();
- final Response response = chain.proceed(request);
-
- return response;
+ return chain.proceed(request);
}
}
\ No newline at end of file
diff --git a/android/app/src/main/java/com/dinect/checker/zbar/CameraActivity.java b/android/app/src/main/java/com/dinect/checker/zbar/CameraActivity.java
index 93860b8..08903ef 100644
--- a/android/app/src/main/java/com/dinect/checker/zbar/CameraActivity.java
+++ b/android/app/src/main/java/com/dinect/checker/zbar/CameraActivity.java
@@ -1,12 +1,12 @@
package com.dinect.checker.zbar;
import android.content.Intent;
-import android.content.pm.PackageManager;
import android.hardware.Camera;
import android.os.Bundle;
import android.os.Handler;
import android.text.TextUtils;
import android.view.View;
+import android.widget.EditText;
import android.widget.Toast;
import com.dinect.checker.AbstractScannerActivity;
@@ -19,7 +19,8 @@ import net.sourceforge.zbar.ImageScanner;
import net.sourceforge.zbar.Symbol;
import net.sourceforge.zbar.SymbolSet;
-public class CameraActivity extends AbstractScannerActivity implements Camera.PreviewCallback {
+public class CameraActivity extends AbstractScannerActivity implements
+ Camera.PreviewCallback {
public static final String ERROR_INFO = "ERROR_INFO";
@@ -39,12 +40,11 @@ public class CameraActivity extends AbstractScannerActivity implements Camera.Pr
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- if (!init(R.layout.activity_zbar_scanner)) {
+ if (!init(R.layout.a_zbar)) {
return;
}
- initNetwork(getIntent());
- initToolbar(R.id.toolbar, getString(R.string.scanner_title));
+ initToolbar(getIntent());
mPreview = (CameraPreview) initScanner();
diff --git a/android/app/src/main/java/com/dinect/checker/zxing/ScannerActivity.java b/android/app/src/main/java/com/dinect/checker/zxing/ScannerActivity.java
index 16d2680..41a34bb 100644
--- a/android/app/src/main/java/com/dinect/checker/zxing/ScannerActivity.java
+++ b/android/app/src/main/java/com/dinect/checker/zxing/ScannerActivity.java
@@ -19,6 +19,7 @@ import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
+import android.widget.EditText;
import com.dinect.checker.AbstractScannerActivity;
import com.dinect.checker.R;
@@ -35,23 +36,21 @@ import me.dm7.barcodescanner.zxing.ZXingScannerView;
public class ScannerActivity extends AbstractScannerActivity
implements ZXingScannerView.ResultHandler {
- private static final int SCAN_INTERVAL_PERIOD = 2000;
+ private static final int SCAN_INTERVAL_PERIOD = 500;
private ZXingScannerView scannerView;
@Override
public void onCreate(Bundle state) {
super.onCreate(state);
- if (!init(R.layout.activity_zxing_scanner)) {
+
+ if (!init(R.layout.a_zxing)) {
return;
}
- initNetwork(getIntent());
- initToolbar(R.id.zxingToolbar, getString(R.string.scanner_title));
+
+ initToolbar(getIntent());
scannerView = (ZXingScannerView) initScanner();
- ArrayList formats = new ArrayList<>();
- formats.add(BarcodeFormat.UPC_EAN_EXTENSION);
- scannerView.setFormats(formats);
addScanner(scannerView, R.id.zxingRoot);
}
@@ -81,12 +80,8 @@ public class ScannerActivity extends AbstractScannerActivity
@Override
public void handleResult(Result raw) {
- final String card = raw.getText();
-
- handleBarcode(card);
-
- final Handler handler = new Handler();
- handler.postDelayed(new Runnable() {
+ handleBarcode(raw.getText());
+ scannerView.postDelayed(new Runnable() {
@Override
public void run() {
scannerView.resumeCameraPreview(ScannerActivity.this);
diff --git a/android/app/src/main/res/drawable-xxxhdpi/help.png b/android/app/src/main/res/drawable-xxxhdpi/help.png
new file mode 100644
index 0000000..5d7029a
Binary files /dev/null and b/android/app/src/main/res/drawable-xxxhdpi/help.png differ
diff --git a/android/app/src/main/res/drawable-xxxhdpi/help_outline.png b/android/app/src/main/res/drawable-xxxhdpi/help_outline.png
deleted file mode 100644
index 3b4a2fc..0000000
Binary files a/android/app/src/main/res/drawable-xxxhdpi/help_outline.png and /dev/null differ
diff --git a/android/app/src/main/res/drawable-xxxhdpi/ic_more_vert.png b/android/app/src/main/res/drawable-xxxhdpi/ic_more_vert.png
new file mode 100644
index 0000000..0f2a7e8
Binary files /dev/null and b/android/app/src/main/res/drawable-xxxhdpi/ic_more_vert.png differ
diff --git a/android/app/src/main/res/drawable-xxxhdpi/logout.png b/android/app/src/main/res/drawable-xxxhdpi/logout.png
index 83b23bb..2f79181 100644
Binary files a/android/app/src/main/res/drawable-xxxhdpi/logout.png and b/android/app/src/main/res/drawable-xxxhdpi/logout.png differ
diff --git a/android/app/src/main/res/drawable-xxxhdpi/settings.png b/android/app/src/main/res/drawable-xxxhdpi/settings.png
new file mode 100644
index 0000000..1e19365
Binary files /dev/null and b/android/app/src/main/res/drawable-xxxhdpi/settings.png differ
diff --git a/android/app/src/main/res/layout/activity_zbar_scanner.xml b/android/app/src/main/res/layout/a_zbar.xml
similarity index 88%
rename from android/app/src/main/res/layout/activity_zbar_scanner.xml
rename to android/app/src/main/res/layout/a_zbar.xml
index f23117d..0fb2abb 100644
--- a/android/app/src/main/res/layout/activity_zbar_scanner.xml
+++ b/android/app/src/main/res/layout/a_zbar.xml
@@ -41,11 +41,7 @@
android:layout_marginTop="56dp"
android:background="#00ff00" />
-
+
-
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/menu/menu.xml b/android/app/src/main/res/menu/menu.xml
index 564d0c3..a89d3df 100644
--- a/android/app/src/main/res/menu/menu.xml
+++ b/android/app/src/main/res/menu/menu.xml
@@ -2,16 +2,27 @@
\ No newline at end of file
diff --git a/android/app/src/main/res/values-ru/strings.xml b/android/app/src/main/res/values-ru/strings.xml
index d203e90..9313589 100644
--- a/android/app/src/main/res/values-ru/strings.xml
+++ b/android/app/src/main/res/values-ru/strings.xml
@@ -1,12 +1,15 @@
-
+
AutoBonus
Сканер карты
Сканировать
- FAQ
+ Справка
Выход
+ Настройки
Подтверждение
Вы действительно хотите выйти и ввести другой номер магазина?
Да
Нет
"Идентификатор %s не найден"
+ Введите штрихкод вручную
+ Можете воспользоваться ручным вводом или позвонить на номер:%s
diff --git a/android/app/src/main/res/values-ua/strings.xml b/android/app/src/main/res/values-ua/strings.xml
index bd673a5..9a2af0d 100644
--- a/android/app/src/main/res/values-ua/strings.xml
+++ b/android/app/src/main/res/values-ua/strings.xml
@@ -2,11 +2,14 @@
AutoBonus
Сканер карти
Сканувати
- FAQ
+ Допомога
Вихід
+ Налаштування
Підтвердження
Ви дійсно хочете вийти і ввести інший номер магазину?
Так
Ні
"Ідентифікатор %s не знайден"
+ Введіть штрихкод вручну
+ Можете скористатися ручним введенням або зателефонувати на номер:\n%s
diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml
index bc190eb..85f4376 100644
--- a/android/app/src/main/res/values/strings.xml
+++ b/android/app/src/main/res/values/strings.xml
@@ -2,11 +2,14 @@
AutoBonus
Card Scanner
Scan
- FAQ
+ Help
Logout
+ Settings
Сonfirmation
Do you really want to log out and enter a different store number?
Yes
No
"Identifier %s is not found"
+ Enter the barcode manually
+ You can use manual input or call the number:\n%s
diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml
index e36e3aa..e491f12 100644
--- a/android/app/src/main/res/values/styles.xml
+++ b/android/app/src/main/res/values/styles.xml
@@ -1,6 +1,8 @@
-
+
diff --git a/android/app/src/pip/AndroidManifest.xml b/android/app/src/pip/AndroidManifest.xml
deleted file mode 100644
index cda80be..0000000
--- a/android/app/src/pip/AndroidManifest.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/android/app/src/pip/ic_launcher-web.png b/android/app/src/pip/ic_launcher-web.png
deleted file mode 100644
index fd2adeb..0000000
Binary files a/android/app/src/pip/ic_launcher-web.png and /dev/null differ
diff --git a/android/build.gradle b/android/build.gradle
index f5004b9..ebe4957 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -4,7 +4,7 @@ buildscript {
}
dependencies {
- classpath 'com.android.tools.build:gradle:2.2.3'
+ classpath 'com.android.tools.build:gradle:2.3.3'
}
}
diff --git a/assets/check.png b/assets/check.png
new file mode 100644
index 0000000..58ac030
Binary files /dev/null and b/assets/check.png differ
diff --git a/assets/expansion_icon.png b/assets/faq_expansion_icon.png
similarity index 100%
rename from assets/expansion_icon.png
rename to assets/faq_expansion_icon.png
diff --git a/assets/help.png b/assets/help.png
new file mode 100644
index 0000000..5d7029a
Binary files /dev/null and b/assets/help.png differ
diff --git a/assets/logout.png b/assets/logout.png
index 83b23bb..2f79181 100644
Binary files a/assets/logout.png and b/assets/logout.png differ
diff --git a/assets/settings.png b/assets/settings.png
new file mode 100644
index 0000000..1e19365
Binary files /dev/null and b/assets/settings.png differ
diff --git a/assets/settings_arrow.png b/assets/settings_arrow.png
new file mode 100644
index 0000000..a68e66c
Binary files /dev/null and b/assets/settings_arrow.png differ
diff --git a/checker.iml b/checker.iml
deleted file mode 100644
index 3b8d8be..0000000
--- a/checker.iml
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
new file mode 100644
index 0000000..24d2c05
--- /dev/null
+++ b/ios/Podfile.lock
@@ -0,0 +1,33 @@
+PODS:
+ - Flutter (1.0.0)
+ - FMDB (2.7.2):
+ - FMDB/standard (= 2.7.2)
+ - FMDB/standard (2.7.2)
+ - path_provider (0.0.1):
+ - Flutter
+ - sqflite (0.0.1):
+ - Flutter
+ - FMDB
+
+DEPENDENCIES:
+ - Flutter (from `/Users/kifio/flutter/bin/cache/artifacts/engine/ios`)
+ - path_provider (from `/Users/kifio/.pub-cache/hosted/pub.dartlang.org/path_provider-0.2.1+1/ios`)
+ - sqflite (from `/Users/kifio/.pub-cache/hosted/pub.dartlang.org/sqflite-0.2.2/ios`)
+
+EXTERNAL SOURCES:
+ Flutter:
+ :path: /Users/kifio/flutter/bin/cache/artifacts/engine/ios
+ path_provider:
+ :path: /Users/kifio/.pub-cache/hosted/pub.dartlang.org/path_provider-0.2.1+1/ios
+ sqflite:
+ :path: /Users/kifio/.pub-cache/hosted/pub.dartlang.org/sqflite-0.2.2/ios
+
+SPEC CHECKSUMS:
+ Flutter: d674e78c937094a75ac71dd77e921e840bea3dbf
+ FMDB: 6198a90e7b6900cfc046e6bc0ef6ebb7be9236aa
+ path_provider: f96fff6166a8867510d2c25fdcc346327cc4b259
+ sqflite: 8e2d9fe1e7cdc95d4d537fc7eb2d23c8dc428e3c
+
+PODFILE CHECKSUM: 351e02e34b831289961ec3558a535cbd2c4965d2
+
+COCOAPODS: 1.2.0
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index 2490465..7129cd8 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -11,6 +11,7 @@
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+ 755861CA44FB15BD2EFD12F7 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 28B464359F9DDCC3EF756D7D /* libPods-Runner.a */; };
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; };
@@ -54,6 +55,7 @@
/* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
+ 28B464359F9DDCC3EF756D7D /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
@@ -120,12 +122,20 @@
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
BBA9BB5B1F179C320053B6EA /* libzbar.a in Frameworks */,
+ 755861CA44FB15BD2EFD12F7 /* libPods-Runner.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
+ 578B8FA7D56ACA2E56C02128 /* Pods */ = {
+ isa = PBXGroup;
+ children = (
+ );
+ name = Pods;
+ sourceTree = "";
+ };
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
@@ -148,6 +158,7 @@
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
BBA9BB001F1786510053B6EA /* Frameworks */,
+ 578B8FA7D56ACA2E56C02128 /* Pods */,
);
sourceTree = "";
};
@@ -195,6 +206,7 @@
BBA9BB351F1792690053B6EA /* CoreMedia.framework */,
BBA9BB331F17925F0053B6EA /* CoreGraphics.framework */,
BBA9BB311F1792570053B6EA /* AVFoundation.framework */,
+ 28B464359F9DDCC3EF756D7D /* libPods-Runner.a */,
);
name = Frameworks;
sourceTree = "";
@@ -270,12 +282,15 @@
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
+ 586CFDEBE2C82C2A9F7DA22E /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
+ 889CEA9B47E2F8AFF76F6433 /* [CP] Embed Pods Frameworks */,
+ 1F7C9AAD1A9D38F5484B84D1 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -342,6 +357,21 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
+ 1F7C9AAD1A9D38F5484B84D1 /* [CP] Copy Pods Resources */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "[CP] Copy Pods Resources";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@@ -356,6 +386,36 @@
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
};
+ 586CFDEBE2C82C2A9F7DA22E /* [CP] Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
+ showEnvVarsInLog = 0;
+ };
+ 889CEA9B47E2F8AFF76F6433 /* [CP] Embed Pods Frameworks */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "[CP] Embed Pods Frameworks";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
diff --git a/ios/Runner.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcworkspace/contents.xcworkspacedata
index 1d526a1..21a3cc1 100644
--- a/ios/Runner.xcworkspace/contents.xcworkspacedata
+++ b/ios/Runner.xcworkspace/contents.xcworkspacedata
@@ -4,4 +4,7 @@
+
+
diff --git a/ios/Runner/ScannerViewController.swift b/ios/Runner/ScannerViewController.swift
index 0cae00b..91a18a1 100644
--- a/ios/Runner/ScannerViewController.swift
+++ b/ios/Runner/ScannerViewController.swift
@@ -17,8 +17,6 @@ extension ZBarSymbolSet: Sequence {
}
}
-// TODO: Реализовать окно сканнера в этом контроллере, вместо вызова ZBarReaderViewController
-
@objc class ScannerViewController: UIViewController, ZBarReaderDelegate {
override func viewDidLoad() {
diff --git a/lib/base/base_screen.dart b/lib/base/base_screen.dart
new file mode 100644
index 0000000..4ff6667
--- /dev/null
+++ b/lib/base/base_screen.dart
@@ -0,0 +1,13 @@
+import 'package:checker/db.dart';
+import 'package:flutter/material.dart';
+
+abstract class BaseScreen extends StatefulWidget {
+
+ final SqliteHelper helper;
+ final String app;
+
+ BaseScreen(this.helper, this.app);
+
+ @override
+ State createState();
+}
\ No newline at end of file
diff --git a/lib/base_state.dart b/lib/base/base_state.dart
similarity index 75%
rename from lib/base_state.dart
rename to lib/base/base_state.dart
index 0ceb4be..43356ad 100644
--- a/lib/base_state.dart
+++ b/lib/base/base_state.dart
@@ -1,16 +1,19 @@
-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';
-import 'strings.dart';
+import 'package:checker/common.dart';
+import 'package:checker/consts.dart';
+import 'package:checker/screens/settings.dart';
+import 'package:checker/screens/faq.dart';
+import 'package:checker/strings.dart';
+import 'package:checker/db.dart';
abstract class BaseState extends State {
+ /// Класс для работы с бд.
+ SqliteHelper helper;
+
/// Тип сборки. Определяет, какие брать ресурсы (цвета, картинки)
String app;
@@ -21,24 +24,7 @@ abstract class BaseState extends State {
String error;
/// Введенное пользователем значение.
- String textFieldValue = '';
-
- @override Widget build(BuildContext ctx) {
-
- platform.invokeMethod('getLocale').then((locale) {
- Intl.defaultLocale = locale;
- if (app == null) {
- platform.invokeMethod('getFlavor').then((flavor) {
- setState(() {
- app = flavor;
- onStart();
- });
- });
- }
- });
-
- return getMainWidget();
- }
+ String dinCode = '';
Widget getMainWidget() {
return app == null ? getBackground() : new Scaffold(appBar: getAppBar(),
@@ -56,31 +42,63 @@ abstract class BaseState extends State {
fit: BoxFit.cover)));
}
- void onStart() {
-
- }
-
/// Возвращает контейнер с всеми виджетами экрана.
Widget getScreenContent();
/// Возвращает заголовок для AppBar
- String getTitle();
+ String getTitle() {
+ return null;
+ }
AppBar getAppBar() {
- return new AppBar(title: new Text(getTitle(), style: new TextStyle(fontSize: 18.0)),
+ return new AppBar(title: new Container(
+ margin: new EdgeInsets.only(left: 16.0),
+ child: new Text(getTitle(), style: new TextStyle(fontSize: 18.0))),
backgroundColor: Resources.getPrimaryColor(app), actions: getMenuButtons());
}
List getMenuButtons() {
- return [getFaqButton()];
+ return [
+ new PopupMenuButton(
+ onSelected: onOptionsItemClick,
+ itemBuilder: (BuildContext context) {
+ return [new PopupMenuItem(
+ value: 0,
+ child: getMenuItem(settings_png, StringsLocalization.settings())),
+ new PopupMenuItem(
+ value: 1,
+ child: getMenuItem(help_png, StringsLocalization.help())),
+ new PopupMenuItem(
+ value: 2,
+ child: getMenuItem(logout_png, StringsLocalization.logout()))
+ ];
+ }
+ )
+ ];
}
- Widget getFaqButton() {
- return new IconButton(icon: new Icon(Icons.help_outline), onPressed: () => faq(context, false));
+ void onOptionsItemClick(int index) {
+ switch (index) {
+ case 0: {
+ pushRoute(context, new SettingsScreen(helper, app, false));
+ break;
+ }
+ case 1: {
+ pushRoute(context, new FAQScreen(false));
+ break;
+ }
+ case 2: {
+ logout(context, helper);
+ }
+ }
}
- Widget getLogoutButton() {
- return new IconButton(icon: new Image.asset(logout_png, height: iconHeight, width: iconHeight), onPressed: () => logout(context));
+ /// Возвращает пункт меню (Картинка с текстом)
+ Widget getMenuItem(String image, String text) {
+ return new Row(children: [
+ new Image.asset(image, width: 28.0, height: 28.0),
+ new Container(padding: new EdgeInsets.only(left: 8.0), child: new Text(text))
+ ]);
}
/// Возврвщает контейнер, внутри которого Text с подсказкой.
@@ -88,31 +106,31 @@ abstract class BaseState extends State {
double horizontalMargin = 8.0;
return new Container(margin: new EdgeInsets.only(top: horizontalMargin, bottom: horizontalMargin, left: verticalMargin, right: verticalMargin),
child: new Row(crossAxisAlignment: CrossAxisAlignment.start,
- children: [new Text(getHintString(), textAlign: TextAlign.left,
- style: new TextStyle(fontWeight: FontWeight.w300, color: error == null ? greyTextColor : Resources.getLogo(app), fontSize: 14.0))]));
+ children: [new Text(getHintOrError(), textAlign: TextAlign.left,
+ style: new TextStyle(fontWeight: FontWeight.w300, color: error == null ? greyTextColor : Resources.getPrimaryColor(app), fontSize: 14.0))]));
}
/// Возвращает подсказку, либо ошибку, если введенные в поле ввода данные неверны.
- String getHintString() {
- if (textFieldValue.length == 0 && error == null) {
+ String getHintOrError() {
+ if (dinCode.length == 0 && error == null) {
return ' ';
} else if (error != null) {
return error;
} else {
- return getHint();
+ return getHintString();
}
}
/// Возвращает текст подсказки для поля ввода.
/// Должен быть переопределен на экранах, на которых есть поле ввода.
- String getHint() {
+ String getHintString() {
return null;
}
/// Смена состояния экрана при изменении текста в поле ввода.
void handleUserInput(String text) {
setState(() {
- textFieldValue = text;
+ dinCode = text;
});
}
@@ -185,5 +203,4 @@ abstract class BaseState extends State {
Widget wrapButton(EdgeInsets margin, Widget widget) {
return new Container(margin: margin, height: buttonHeight, child: new Row(children: [new Expanded(child: widget)]));
}
-
-}
+}
\ No newline at end of file
diff --git a/lib/base/settings_base_state.dart b/lib/base/settings_base_state.dart
new file mode 100644
index 0000000..1ca0aae
--- /dev/null
+++ b/lib/base/settings_base_state.dart
@@ -0,0 +1,68 @@
+import 'package:checker/base/base_state.dart';
+import 'package:checker/consts.dart';
+import 'package:checker/db.dart';
+import 'package:checker/strings.dart';
+import 'package:flutter/material.dart';
+
+abstract class SettingsBaseState extends BaseState {
+
+ SettingsBaseState(SqliteHelper helper, String app) {
+ this.helper = helper;
+ this.app = app;
+ }
+
+ int selectedItem;
+
+ @override Widget build(BuildContext context) {
+ return new Scaffold(appBar: getAppBar(),
+ body: getScreenContent());
+ }
+
+ @override
+ Widget getScreenContent() {
+ getSelectedValue();
+ List widgets = new List();
+
+ for (String option in getOptions()) {
+ widgets.add(getItem(option));
+ }
+
+ return new ListView(children: widgets);
+ }
+
+ List getOptions();
+
+ void saveOption();
+
+ void getSelectedValue();
+
+ @override
+ List getMenuButtons() {
+ return null;
+ }
+
+ Widget getItem(String option) {
+ return new Container(
+ height: 56.0,
+ child: (new FlatButton(onPressed: () {
+ saveOption();
+ setState(() {
+ selectedItem = getOptions().indexOf(option);
+ });
+ },
+ child: new Row(children: [
+ new Expanded(child: new Text(option)),
+ getCheckMark(getOptions().indexOf(option))]))));
+ }
+
+ Widget getCheckMark(int index) {
+ return index == selectedItem ? new Image.asset(check_png,
+ width: 28.0,
+ height: 28.0) : new Image.asset(check_png, color: new Color(0xffffff));
+ }
+
+ @override
+ String getTitle() {
+ return StringsLocalization.settings();
+ }
+}
\ No newline at end of file
diff --git a/lib/common.dart b/lib/common.dart
index 49aeadb..3a64b8d 100644
--- a/lib/common.dart
+++ b/lib/common.dart
@@ -1,40 +1,50 @@
-import 'package:flutter/services.dart';
+import 'package:checker/screens/faq.dart';
+import 'package:checker/screens/purchase.dart';
+import 'package:checker/screens/settings.dart';
+import 'package:checker/screens/splash.dart';
import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
import 'consts.dart';
+import 'db.dart';
import 'network.dart';
import 'resources.dart';
-import 'package:checker/registration.dart';
-import 'package:checker/purchase.dart';
-import 'faq.dart';
import 'strings.dart';
// Канал для взаимодействия с кодом платформы.
const platform = const MethodChannel('com.dinect.checker/instance_id');
// Метод обеспечивает замену текущего объекта route новым.
-pushRoute(BuildContext context, Widget widget) {
+pushRouteReplacement(BuildContext context, Widget widget) {
var route = new MaterialPageRoute(builder: (BuildContext context) => widget);
Navigator.of(context).pushReplacement(route);
}
-// Добавление route, с возможностью вернуться к предыдущему экрану.
-faq(BuildContext context, bool returnToScanner) {
- var route = new MaterialPageRoute(builder: (BuildContext context) => new FAQScreen(returnToScanner));
+pushRoute(BuildContext context, Widget widget) {
+ var route = new MaterialPageRoute(builder: (BuildContext context) => widget);
Navigator.of(context).push(route);
}
+// Добавление route, с возможностью вернуться к предыдущему экрану.
+faq(BuildContext context, bool returnToScanner) {
+ pushRoute(context, new FAQScreen(returnToScanner));
+}
+
// В методе отправляется запрос на удаление токена кассы, очищаются SharedPreferences приложения.
-logout(BuildContext context) async {
- String token = await platform.invokeMethod('getToken');
- VoidCallback positiveCalback = () {
+logout(BuildContext context, SqliteHelper helper) async {
+
+ String token = await helper.getToken();
+ String locale = await helper.getLocale();
+
+ VoidCallback positiveCallback = () {
if (token != null) {
- deleteToken(token).then((response) {
- print(response.body);
- platform.invokeMethod('removeKeys').then((result) {
+ deleteToken(token, locale).then((response) {
+ helper.clear().then((result) {
+ helper.close().then((_) {
Navigator.of(context).pop();
Navigator.of(context).pop();
- pushRoute(context, new RegistrationScreen()); // Запускаем регистрацию
+ pushRouteReplacement(context, new SplashScreen()); // Запускаем регистрацию
+ });
});
}).catchError((error) {
print(error.toString());
@@ -45,16 +55,22 @@ logout(BuildContext context) async {
}
};
- showYesNoDialog(context, StringsLocalization.confirmation(), StringsLocalization.askChangeStore(), positiveCalback);
+ showYesNoDialog(context, StringsLocalization.confirmation(), StringsLocalization.askChangeStore(), positiveCallback);
}
-forceLogout(BuildContext context) async {
- String token = await platform.invokeMethod('getToken');
- deleteToken(token).then((response) {
- print(response.body);
- platform.invokeMethod('removeKeys').then((result) {
- Navigator.of(context).pop();
- pushRoute(context, new RegistrationScreen()); // Запускаем регистрацию
+forceLogout(String token , BuildContext context) async {
+
+ deleteToken(token, 'ru').then((response) {
+ SqliteHelper helper = new SqliteHelper();
+ helper.open().then((_) {
+ helper.clear().then((_) {
+ helper.close().then((_) {
+ while (Navigator.of(context).canPop()) {
+ Navigator.of(context).pop();
+ }
+ pushRouteReplacement(context, new SplashScreen());
+ });
+ });
});
}).catchError((error) {
print(error.toString());
@@ -63,50 +79,88 @@ forceLogout(BuildContext context) async {
/// Запуск спецефичной для каждой платформы части приложения - сканера.
/// Может производиться с нескольких экранов (splash, finish_registration).
-startScanner(BuildContext context, String app) async {
-
- String token = await platform.invokeMethod('getToken');
- // Канал ловит вызовы методов из "нативной" части приложения.
- // Могут быть вызваны либо logaut либо faq, либо purchase.
- if (token != null) {
- platform.setMethodCallHandler((MethodCall call) async {
-
- print('call.method: ${call.method}');
- if (call.method == 'logout') {
- forceLogout(context);
- } else if (call.method == 'faq') {
- faq(context, true);
- } else {
- String userString = call.arguments[0];
- print('user: ${userString}');
- String card = call.arguments[1];
- print('card: ${card}');
- var route = new MaterialPageRoute(builder: (BuildContext context) => new PurchaseScreen(userString, card));
- Navigator.of(context).pushReplacement(route);
- }
- });
- await platform.invokeMethod('startScanner', {
- 'token' : token,
- 'url': url,
- 'appToken': appToken,
- 'color': Resources.getPrimaryColor(app).value
+startScanner(BuildContext context, String app, SqliteHelper helper) async {
+ if (helper == null) {
+ helper = new SqliteHelper();
+ helper.open().then((_) {
+ startScanner(context, app, helper);
});
+ } else {
+ String token = await helper.getToken();
+ String locale = await helper.getLocale();
+ helper.close();
+ // Канал ловит вызовы методов из "нативной" части приложения.
+ // Могут быть вызваны либо logout либо faq, либо purchase.
+ if (token != null) {
+ platform.setMethodCallHandler((MethodCall call) async {
+ if (call.method == 'logout') {
+ forceLogout(token, context);
+ } else if (call.method == 'faq') {
+ faq(context, true);
+ } else if(call.method == 'settings') {
+ helper = new SqliteHelper();
+ helper.open().then((_) {
+ pushRoute(context, new SettingsScreen(helper, app, true));
+ });
+ } else {
+ String userString = call.arguments[0];
+ String card = call.arguments[1];
+ var route = new MaterialPageRoute(
+ builder: (BuildContext context) =>
+ new PurchaseScreen(
+ userString, card));
+ while (Navigator.of(context).canPop()) {
+ Navigator.of(context).pop();
+ }
+ Navigator.of(context).pushReplacement(route);
+ }
+ });
+
+ await platform.invokeMethod('startScanner', {
+ 'token': token,
+ 'url': url,
+ 'appToken': appToken,
+ 'locale': locale,
+ 'color': Resources
+ .getPrimaryColor(app)
+ .value
+ });
+ }
}
}
// Запуск диалога с двумя кнопками
showYesNoDialog(BuildContext context, String title, String content, VoidCallback positiveCallback) {
- showDialog(context: context, child: new AlertDialog(
- title: new Text(title),
- content: new Text(content),
- actions: [
- new FlatButton(
- child: new Text(StringsLocalization.no()),
- onPressed: () {
- Navigator.of(context).pop();
- }
- ),
- new FlatButton(
- child: new Text(StringsLocalization.yes()),
- onPressed: positiveCallback)]));
+ showDialog(context: context, child: new AlertDialog(
+ title: new Text(title),
+ content: new Text(content),
+ actions: [
+ new FlatButton(
+ child: new Text(StringsLocalization.no()),
+ onPressed: () {
+ Navigator.of(context).pop();
+ }
+ ),
+ new FlatButton(
+ child: new Text(StringsLocalization.yes()),
+ onPressed: positiveCallback)]));
}
+
+getCurrencyTitle(int code) {
+ switch(code) {
+ case 643: return StringsLocalization.nominativeRuble();
+ case 840: return StringsLocalization.nominativeDollar();
+ case 980: return StringsLocalization.nominativeHryvna();
+ case 978: return StringsLocalization.nominativeEuro();
+ case 398: return StringsLocalization.nominativeTenge();
+ }
+}
+
+getLocaleTitle(String code) {
+ switch(code) {
+ case 'ru': return 'Русский';
+ case 'en': return 'English';
+ case 'ua': return 'Український';
+ case 'es': return 'Español';
+ }
+}
\ No newline at end of file
diff --git a/lib/consts.dart b/lib/consts.dart
index 71325ef..9156fca 100644
--- a/lib/consts.dart
+++ b/lib/consts.dart
@@ -1,16 +1,23 @@
import 'package:flutter/material.dart';
// Serious constants
-const String appName = "AutoBonus";
+const String appName = "Autobonus";
const String url = 'https://pos-api-autoclub.dinect.com/20130701/';
const String appToken = 'bdea0f3ba9034b688019a7cac753d1209e2b227f';
+//const String url = 'https://pos-api-int.dinect.com/20130701/';
+//const String appToken = '9fec83cdca38c357e6b65dbb17514cdd36bf2a08';
+
// Assets
const String logout_png = 'assets/logout.png';
+const String help_png = 'assets/help.png';
+const String settings_png = 'assets/settings.png';
+const String settings_arrow_png = 'assets/settings_arrow.png';
+const String check_png = 'assets/check.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';
-const String expansion_icon_png = 'assets/expansion_icon.png';
+const String expansion_icon_png = 'assets/faq_expansion_icon.png';
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';
@@ -27,4 +34,4 @@ const Color inputFieldBackground = const Color(0xffefefef);
// Dimens
const double verticalMargin = 28.0;
const double buttonHeight = 48.0;
-const double iconHeight = 20.0;
+const double iconHeight = 20.0;
\ No newline at end of file
diff --git a/lib/db.dart b/lib/db.dart
new file mode 100644
index 0000000..925f774
--- /dev/null
+++ b/lib/db.dart
@@ -0,0 +1,143 @@
+import 'dart:async';
+import 'dart:io';
+
+import 'package:path/path.dart';
+import 'package:sqflite/sqflite.dart';
+import 'package:path_provider/path_provider.dart';
+
+/// Данные о таблице сессии пользователя.
+const String tableSession = "session";
+
+const String columnMerchantID = "merchant_id"; // DIN code, который вводится при авторизации
+const String columnToken = "token"; // Токен для pos. Приходит с бэкэнда.
+const String columnPosID = "pos_id"; // идентификатор для создания токена на бэке.
+const String columnDocID = "doc_id"; // идентификатор, для проведения покупки на бэкенде.
+
+/// Данные о таблице данных приложения.
+const String tableSettings = "settings";
+
+const String columnCurrency = "currency"; // валюта.
+const String columnLocale = "locale"; // локаль.
+
+//{
+// columnMerchantID: merchantID,
+// columnToken: token,
+// columnPosID: posID,
+// columnDocID: docID
+//}
+
+/// База данных, для хранения временных данных (din, token, locale, etc.)
+class SqliteHelper {
+
+ Database db;
+
+ Future open() async {
+ Directory documentsDirectory = await getApplicationDocumentsDirectory();
+ String path = join(documentsDirectory.path, "demo.db");
+ db = await openDatabase(path, version: 1,
+ onCreate: (Database db, int version) async {
+
+ await db.execute('''create table $tableSession (
+ $columnMerchantID text primary key,
+ $columnToken text,
+ $columnPosID text,
+ $columnDocID integer)''');
+
+ await db.execute('''create table $tableSettings (
+ $columnCurrency integer,
+ $columnLocale text)''');
+ });
+ }
+
+ /// Создается запись в таблице, содержащая
+ /// необходимые для идентификации пользователя и проведения запросов.
+ Future createSession(String merchantID, String posID, String token) async {
+
+ Map session = {
+ columnMerchantID: merchantID,
+ columnPosID: posID,
+ columnToken: token,
+ columnDocID: 0
+ };
+
+ return db.insert(tableSession, session);
+ }
+
+ /// Создается запись в таблице, содержащая данные, которые не зависят от сессии.
+ Future createAppInfo(String locale, int currency) async {
+ List