From c07ed1c837aa7d681e588e1a31c7de33319e4c62 Mon Sep 17 00:00:00 2001 From: Alexander Junggeburth Date: Thu, 3 Feb 2022 17:33:25 +0100 Subject: [PATCH 01/30] [wip] persistent project and initialization --- build.gradle | 2 +- core/build.gradle | 11 +-- .../io/snabble/sdk/InitializationState.kt | 8 ++ .../src/main/java/io/snabble/sdk/Snabble.java | 14 +++ firebase-detector/build.gradle | 10 +- gradle/wrapper/gradle-wrapper.properties | 2 +- .../src/main/java/io/snabble/testapp/App.java | 21 ---- .../java/io/snabble/testapp/BaseActivity.java | 34 ++----- .../java/io/snabble/testapp/HomeFragment.java | 98 +++++++++---------- ui/build.gradle | 8 +- .../io/snabble/sdk/ui/SnabbleBaseFragment.kt | 71 ++++++++++++++ .../main/java/io/snabble/sdk/ui/SnabbleUI.kt | 3 +- .../java/io/snabble/sdk/ui/UIPersistence.kt | 36 +++++++ .../sdk/ui/cart/ShoppingCartFragment.kt | 5 +- .../main/res/layout/snabble_fragment_base.xml | 22 +++++ utils/build.gradle | 2 - 16 files changed, 225 insertions(+), 122 deletions(-) create mode 100644 core/src/main/java/io/snabble/sdk/InitializationState.kt create mode 100644 ui/src/main/java/io/snabble/sdk/ui/SnabbleBaseFragment.kt create mode 100644 ui/src/main/java/io/snabble/sdk/ui/UIPersistence.kt create mode 100644 ui/src/main/res/layout/snabble_fragment_base.xml diff --git a/build.gradle b/build.gradle index 99db419245..ddaa93d001 100644 --- a/build.gradle +++ b/build.gradle @@ -11,7 +11,7 @@ buildscript { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.dokka:dokka-gradle-plugin:$kotlin_version" classpath "org.jetbrains.dokka:dokka-base:$kotlin_version" - classpath 'com.android.tools.build:gradle:7.0.4' + classpath 'com.android.tools.build:gradle:7.1.0' classpath 'gradle.plugin.com.github.jlouns:gradle-cross-platform-exec-plugin:0.5.0' classpath 'gradle.plugin.gmazzo:sqlite-plugin:0.2' } diff --git a/core/build.gradle b/core/build.gradle index a460b5ad03..fa42b1fa34 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -10,8 +10,6 @@ android { defaultConfig { minSdkVersion project.minSdkVersion targetSdkVersion project.targetSdkVersion - versionCode project.versionCode - versionName project.sdkVersion testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' consumerProguardFiles 'proguard-rules.pro' @@ -59,14 +57,15 @@ dependencies { implementation 'org.apache.commons:commons-lang3:3.12.0' implementation 'org.iban4j:iban4j:3.2.1' implementation 'com.caverock:androidsvg-aar:1.4' - implementation 'com.google.android.gms:play-services-wallet:18.1.3' - implementation 'androidx.appcompat:appcompat:1.3.1' - implementation 'androidx.biometric:biometric:1.2.0-alpha03' + implementation 'com.google.android.gms:play-services-wallet:19.1.0' + implementation 'androidx.appcompat:appcompat:1.4.1' + implementation 'androidx.biometric:biometric:1.2.0-alpha04' + implementation "androidx.startup:startup-runtime:1.1.0" api "com.squareup.okhttp3:okhttp:${project.okhttpVersion}" implementation "com.squareup.okhttp3:logging-interceptor:${project.okhttpVersion}" - api 'com.google.code.gson:gson:2.8.8' + api 'com.google.code.gson:gson:2.8.9' testImplementation 'junit:junit:4.13.2' testImplementation 'org.robolectric:robolectric:4.6.1' diff --git a/core/src/main/java/io/snabble/sdk/InitializationState.kt b/core/src/main/java/io/snabble/sdk/InitializationState.kt new file mode 100644 index 0000000000..6e0fb89072 --- /dev/null +++ b/core/src/main/java/io/snabble/sdk/InitializationState.kt @@ -0,0 +1,8 @@ +package io.snabble.sdk + +enum class InitializationState { + NONE, + INITIALIZING, + INITIALIZED, + ERROR, +} \ No newline at end of file diff --git a/core/src/main/java/io/snabble/sdk/Snabble.java b/core/src/main/java/io/snabble/sdk/Snabble.java index 8de8c3f23f..48a1d2cb20 100644 --- a/core/src/main/java/io/snabble/sdk/Snabble.java +++ b/core/src/main/java/io/snabble/sdk/Snabble.java @@ -12,6 +12,8 @@ import android.util.Base64; import androidx.annotation.NonNull; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; import com.google.gson.JsonArray; import com.google.gson.JsonElement; @@ -81,12 +83,15 @@ public class Snabble { private String createAppUserUrl; private OkHttpClient okHttpClient; private WeakReference currentActivity; + private MutableLiveData initializationState = new MutableLiveData(InitializationState.NONE); private Snabble() { } public void setup(Application app, Config config, final SetupCompletionListener setupCompletionListener) { + initializationState.postValue(InitializationState.INITIALIZING); + this.application = app; this.config = config; @@ -149,6 +154,7 @@ public void setup(Application app, Config config, final SetupCompletionListener if (config.bundledMetadataAssetPath != null) { readMetadata(); setupCompletionListener.onReady(); + initializationState.postValue(InitializationState.INITIALIZED); if (config.loadActiveShops) { loadActiveShops(); @@ -164,11 +170,13 @@ protected void onDataLoaded(boolean wasStillValid) { Token token = tokenRegistry.getToken(projects.get(0)); if (token == null) { setupCompletionListener.onError(Error.CONNECTION_TIMEOUT); + initializationState.postValue(InitializationState.ERROR); return; } } setupCompletionListener.onReady(); + initializationState.postValue(InitializationState.INITIALIZED); if (config.loadActiveShops) { loadActiveShops(); @@ -180,8 +188,10 @@ protected void onError() { if (metadataDownloader.hasData()) { readMetadata(); setupCompletionListener.onReady(); + initializationState.postValue(InitializationState.INITIALIZED); } else { setupCompletionListener.onError(Error.CONNECTION_TIMEOUT); + initializationState.postValue(InitializationState.ERROR); } } }); @@ -200,6 +210,10 @@ private void registerNetworkCallback(Application app) { networkCallback); } + public LiveData getInitializationState() { + return initializationState; + } + public String getVersionName() { return versionName; } diff --git a/firebase-detector/build.gradle b/firebase-detector/build.gradle index 1837e38818..91fd4c5f85 100644 --- a/firebase-detector/build.gradle +++ b/firebase-detector/build.gradle @@ -9,8 +9,6 @@ android { defaultConfig { minSdkVersion project.minSdkVersion targetSdkVersion project.targetSdkVersion - versionCode project.versionCode - versionName project.sdkVersion testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' } @@ -26,10 +24,7 @@ android { } } } - - lintOptions { - abortOnError false - } + compileOptions { coreLibraryDesugaringEnabled true @@ -41,6 +36,9 @@ android { freeCompilerArgs = ['-Xjvm-default=all'] jvmTarget = '1.8' } + lint { + abortOnError false + } } dependencies { diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 16f6a82548..7dcd28361b 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https://services.gradle.org/distributions/gradle-7.0.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip diff --git a/java-sample/src/main/java/io/snabble/testapp/App.java b/java-sample/src/main/java/io/snabble/testapp/App.java index 066cbf30db..d5acbba08a 100644 --- a/java-sample/src/main/java/io/snabble/testapp/App.java +++ b/java-sample/src/main/java/io/snabble/testapp/App.java @@ -33,27 +33,6 @@ public void onCreate() { instance = this; } - public void initBlocking() { - final CountDownLatch countDownLatch = new CountDownLatch(1); - init(new InitCallback() { - @Override - public void done() { - countDownLatch.countDown(); - } - - @Override - public void error(String text) { - countDownLatch.countDown(); - } - }); - - try { - countDownLatch.await(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - public void init(final InitCallback callback) { if(project != null){ callback.done(); diff --git a/java-sample/src/main/java/io/snabble/testapp/BaseActivity.java b/java-sample/src/main/java/io/snabble/testapp/BaseActivity.java index 2d100f5b02..e3fe4187a3 100644 --- a/java-sample/src/main/java/io/snabble/testapp/BaseActivity.java +++ b/java-sample/src/main/java/io/snabble/testapp/BaseActivity.java @@ -42,10 +42,6 @@ public abstract class BaseActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { - if(savedInstanceState != null) { - App.get().initBlocking(); - } - super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); @@ -53,29 +49,13 @@ protected void onCreate(Bundle savedInstanceState) { content = findViewById(R.id.content); sdkError = findViewById(R.id.sdk_error); - App.get().init(new App.InitCallback() { - @Override - public void done() { - runOnUiThread(() -> { - progressIndicator.setVisibility(View.GONE); - content.setVisibility(View.VISIBLE); - - getSupportFragmentManager() - .beginTransaction() - .replace(R.id.content, onCreateFragment()) - .commitAllowingStateLoss(); - }); - } - - @Override - public void error(final String text) { - runOnUiThread(() -> { - progressIndicator.setVisibility(View.GONE); - sdkError.setVisibility(View.VISIBLE); - sdkError.setText(text); - }); - } - }); + progressIndicator.setVisibility(View.GONE); + content.setVisibility(View.VISIBLE); + + getSupportFragmentManager() + .beginTransaction() + .replace(R.id.content, onCreateFragment()) + .commitAllowingStateLoss(); } @Override diff --git a/java-sample/src/main/java/io/snabble/testapp/HomeFragment.java b/java-sample/src/main/java/io/snabble/testapp/HomeFragment.java index bd2fe11411..361b699aa4 100644 --- a/java-sample/src/main/java/io/snabble/testapp/HomeFragment.java +++ b/java-sample/src/main/java/io/snabble/testapp/HomeFragment.java @@ -23,14 +23,58 @@ import io.snabble.sdk.Project; import io.snabble.sdk.Shop; import io.snabble.sdk.Snabble; +import io.snabble.sdk.ui.SnabbleBaseFragment; import io.snabble.sdk.ui.SnabbleUI; -public class HomeFragment extends Fragment { +public class HomeFragment extends SnabbleBaseFragment { + private void updateShops(View v) { + Project project = SnabbleUI.getProject(); + final List shopList = project.getShops(); + Spinner shops = v.findViewById(R.id.shops); + shops.setAdapter(new ArrayAdapter(requireContext(), R.layout.item_dropdown, shopList) { + @NonNull + @Override + public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { + TextView v = (TextView) super.getView(position, convertView, parent); + Shop shop = shopList.get(position); + v.setText(shop.getName() + " (" + shop.getId() + ")"); + return v; + } + + @Override + public View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { + TextView v = (TextView) super.getDropDownView(position, convertView, parent); + Shop shop = shopList.get(position); + v.setText(shop.getName() + " (" + shop.getId() + ")"); + return v; + } + }); + + for (int i=0; i parent, View view, int position, long id) { + Shop shop = shopList.get(position); + project.setCheckedInShop(shop); + } + + @Override + public void onNothingSelected(AdapterView parent) { + + } + }); + } + + @Nullable @Override - public View onCreateView(@NonNull LayoutInflater inflater, - @Nullable ViewGroup container, - @Nullable Bundle savedInstanceState) { + public View onCreateViewInternal(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View v = inflater.inflate(R.layout.fragment_home, container, false); v.findViewById(R.id.scanner).setOnClickListener(btn -> ((BaseActivity)getActivity()).showScanner()); @@ -110,50 +154,4 @@ public void onNothingSelected(AdapterView parent) { return v; } - - private void updateShops(View v) { - Project project = SnabbleUI.getProject(); - final List shopList = project.getShops(); - Spinner shops = v.findViewById(R.id.shops); - shops.setAdapter(new ArrayAdapter(requireContext(), R.layout.item_dropdown, shopList) { - @NonNull - @Override - public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { - TextView v = (TextView) super.getView(position, convertView, parent); - Shop shop = shopList.get(position); - v.setText(shop.getName() + " (" + shop.getId() + ")"); - return v; - } - - @Override - public View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { - TextView v = (TextView) super.getDropDownView(position, convertView, parent); - Shop shop = shopList.get(position); - v.setText(shop.getName() + " (" + shop.getId() + ")"); - return v; - } - }); - - for (int i=0; i parent, View view, int position, long id) { - Shop shop = shopList.get(position); - project.setCheckedInShop(shop); - } - - @Override - public void onNothingSelected(AdapterView parent) { - - } - }); - } - - } \ No newline at end of file diff --git a/ui/build.gradle b/ui/build.gradle index 2f8c5ee5e6..c4edb84e52 100644 --- a/ui/build.gradle +++ b/ui/build.gradle @@ -10,8 +10,6 @@ android { defaultConfig { minSdkVersion project.minSdkVersion targetSdkVersion project.targetSdkVersion - versionCode project.versionCode - versionName project.sdkVersion testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' } @@ -31,9 +29,6 @@ android { viewBinding = true } - lintOptions { - disable 'LabelFor', 'ContentDescription', 'MissingTranslation' - } compileOptions { coreLibraryDesugaringEnabled true @@ -45,6 +40,9 @@ android { freeCompilerArgs = ['-Xjvm-default=all'] jvmTarget = '1.8' } + lint { + disable 'LabelFor', 'ContentDescription', 'MissingTranslation' + } } dependencies { diff --git a/ui/src/main/java/io/snabble/sdk/ui/SnabbleBaseFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/SnabbleBaseFragment.kt new file mode 100644 index 0000000000..743875fc35 --- /dev/null +++ b/ui/src/main/java/io/snabble/sdk/ui/SnabbleBaseFragment.kt @@ -0,0 +1,71 @@ +package io.snabble.sdk.ui + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ProgressBar +import android.widget.TextView +import androidx.core.view.isVisible +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentContainerView +import io.snabble.sdk.InitializationState +import io.snabble.sdk.Snabble + +abstract class SnabbleBaseFragment : Fragment() { + private lateinit var sdkNotInitialized: TextView + private lateinit var progress: ProgressBar + private lateinit var fragmentContainer: FragmentContainerView + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + return inflater.inflate(R.layout.snabble_fragment_base, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + fragmentContainer = view.findViewById(R.id.fragment_container) + progress = view.findViewById(R.id.progress) + sdkNotInitialized = view.findViewById(R.id.sdk_not_initialized) + + Snabble.getInstance().initializationState.observe(viewLifecycleOwner) { + when(it) { + InitializationState.NONE -> { + // TODO init + observeProject(savedInstanceState) + } + InitializationState.INITIALIZED -> { + observeProject(savedInstanceState) + } + InitializationState.INITIALIZING -> { + observeProject(savedInstanceState) + } + InitializationState.ERROR -> { + progress.isVisible = false + sdkNotInitialized.isVisible = true + } + } + } + } + + private fun observeProject(savedInstanceState: Bundle?) { + SnabbleUI.projectAsLiveData.observe(viewLifecycleOwner) { + progress.isVisible = it == null + + if (it != null) { + val fragmentView = onCreateViewInternal(layoutInflater, fragmentContainer, savedInstanceState) + if (fragmentView != null) { + fragmentContainer.addView(fragmentView) + } + } + } + } + + abstract fun onCreateViewInternal( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle?) + : View? +} \ No newline at end of file diff --git a/ui/src/main/java/io/snabble/sdk/ui/SnabbleUI.kt b/ui/src/main/java/io/snabble/sdk/ui/SnabbleUI.kt index 3e9be6b7bf..9f8c37f331 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/SnabbleUI.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/SnabbleUI.kt @@ -50,8 +50,9 @@ object SnabbleUI { val action: Action ) - private val projectLiveData = MutableLiveData() private var actions = mutableMapOf() + + private val projectLiveData = MutableLiveData() private var nullableProject: Project? = null @JvmStatic diff --git a/ui/src/main/java/io/snabble/sdk/ui/UIPersistence.kt b/ui/src/main/java/io/snabble/sdk/ui/UIPersistence.kt new file mode 100644 index 0000000000..c5f543e4d3 --- /dev/null +++ b/ui/src/main/java/io/snabble/sdk/ui/UIPersistence.kt @@ -0,0 +1,36 @@ +package io.snabble.sdk.ui + +import android.app.Application +import android.content.Context +import android.content.SharedPreferences +import androidx.lifecycle.MutableLiveData +import io.snabble.sdk.Project +import io.snabble.sdk.Snabble + +object UIPersistence { + private var isInitialized = false + private var application: Application + private lateinit var sharedPreferences: SharedPreferences + private val snabble = Snabble.getInstance() + + private val projectLiveData = MutableLiveData() + private var nullableProject: Project? = null + + init { + application = snabble.application + snabble.addOnMetadataUpdateListener { + if (!isInitialized) { + isInitialized = true + sharedPreferences = application.getSharedPreferences("snabble_ui_persistence", Context.MODE_PRIVATE) + } + + update() + } + } + + fun update() { + nullableProject = snabble.projects.find { + it.id == sharedPreferences.getString("id", null) + } + } +} \ No newline at end of file diff --git a/ui/src/main/java/io/snabble/sdk/ui/cart/ShoppingCartFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/cart/ShoppingCartFragment.kt index b6e82b76ad..f5a9780036 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/cart/ShoppingCartFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/cart/ShoppingCartFragment.kt @@ -8,13 +8,14 @@ import android.view.* import androidx.appcompat.app.AlertDialog import androidx.core.view.MenuItemCompat import androidx.fragment.app.Fragment +import io.snabble.sdk.ui.SnabbleBaseFragment import io.snabble.sdk.ui.SnabbleUI -open class ShoppingCartFragment : Fragment() { +open class ShoppingCartFragment : SnabbleBaseFragment() { var shoppingCartView: ShoppingCartView? = null private set - override fun onCreateView( + override fun onCreateViewInternal( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? diff --git a/ui/src/main/res/layout/snabble_fragment_base.xml b/ui/src/main/res/layout/snabble_fragment_base.xml new file mode 100644 index 0000000000..e6de72e462 --- /dev/null +++ b/ui/src/main/res/layout/snabble_fragment_base.xml @@ -0,0 +1,22 @@ + + + + + + + + \ No newline at end of file diff --git a/utils/build.gradle b/utils/build.gradle index cda4c780bc..04b49442af 100644 --- a/utils/build.gradle +++ b/utils/build.gradle @@ -9,8 +9,6 @@ android { defaultConfig { minSdkVersion project.minSdkVersion targetSdkVersion project.targetSdkVersion - versionCode project.versionCode - versionName project.sdkVersion testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' } From c758eba6385f498bb762ec2025b846f45f1c9b57 Mon Sep 17 00:00:00 2001 From: Alexander Junggeburth Date: Mon, 7 Feb 2022 14:13:38 +0100 Subject: [PATCH 02/30] Rename .java to .kt --- core/src/main/java/io/snabble/sdk/{Snabble.java => Snabble.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename core/src/main/java/io/snabble/sdk/{Snabble.java => Snabble.kt} (100%) diff --git a/core/src/main/java/io/snabble/sdk/Snabble.java b/core/src/main/java/io/snabble/sdk/Snabble.kt similarity index 100% rename from core/src/main/java/io/snabble/sdk/Snabble.java rename to core/src/main/java/io/snabble/sdk/Snabble.kt From cad8177f16dad4d9e42f091ec9c615e7f4c54228 Mon Sep 17 00:00:00 2001 From: Alexander Junggeburth Date: Mon, 7 Feb 2022 14:13:39 +0100 Subject: [PATCH 03/30] convert Snabble to kotlin --- .../sdk/AcceptedLanguageInterceptor.kt | 3 +- core/src/main/java/io/snabble/sdk/Snabble.kt | 1055 ++++++++--------- .../io/snabble/sdk/checkin/CheckInManager.kt | 6 +- .../sdk/payment/PaymentCredentials.java | 16 +- kotlin-sample/build.gradle | 1 + .../io/snabble/sdk/sample/LoadingActivity.kt | 6 +- .../java/io/snabble/sdk/ui/UIPersistence.kt | 17 +- .../sdk/ui/payment/PaymentInputViewHelper.kt | 71 +- .../java/io/snabble/sdk/ui/payment/Payone.kt | 2 +- .../snabble/sdk/ui/payment/PayoneInputView.kt | 47 +- 10 files changed, 581 insertions(+), 643 deletions(-) diff --git a/core/src/main/java/io/snabble/sdk/AcceptedLanguageInterceptor.kt b/core/src/main/java/io/snabble/sdk/AcceptedLanguageInterceptor.kt index 321825f609..5e95ecc9c7 100644 --- a/core/src/main/java/io/snabble/sdk/AcceptedLanguageInterceptor.kt +++ b/core/src/main/java/io/snabble/sdk/AcceptedLanguageInterceptor.kt @@ -28,7 +28,8 @@ class AcceptedLanguageInterceptor : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { var request: Request = chain.request() val url = request.url.toString() - if (url.startsWith(Snabble.getInstance().endpointBaseUrl)) { + val baseUrl = Snabble.getInstance().endpointBaseUrl + if (baseUrl != null && url.startsWith(baseUrl)) { request = request.newBuilder() .addHeader("Accept-Language", acceptedLanguagesHeader) .build() diff --git a/core/src/main/java/io/snabble/sdk/Snabble.kt b/core/src/main/java/io/snabble/sdk/Snabble.kt index 48a1d2cb20..8ca881724f 100644 --- a/core/src/main/java/io/snabble/sdk/Snabble.kt +++ b/core/src/main/java/io/snabble/sdk/Snabble.kt @@ -1,790 +1,676 @@ -package io.snabble.sdk; - -import android.app.Activity; -import android.app.Application; -import android.content.Context; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.net.ConnectivityManager; -import android.net.Network; -import android.net.NetworkCapabilities; -import android.net.NetworkRequest; -import android.util.Base64; - -import androidx.annotation.NonNull; -import androidx.lifecycle.LiveData; -import androidx.lifecycle.MutableLiveData; - -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.InputStream; -import java.lang.ref.WeakReference; -import java.security.cert.CertificateException; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.X509TrustManager; - -import io.snabble.sdk.checkin.CheckInLocationManager; -import io.snabble.sdk.checkin.CheckInManager; -import io.snabble.sdk.auth.AppUser; -import io.snabble.sdk.auth.Token; -import io.snabble.sdk.auth.TokenRegistry; -import io.snabble.sdk.payment.PaymentCredentialsStore; -import io.snabble.sdk.utils.Downloader; -import io.snabble.sdk.utils.GsonHolder; -import io.snabble.sdk.utils.JsonUtils; -import io.snabble.sdk.utils.Logger; -import io.snabble.sdk.utils.SimpleActivityLifecycleCallbacks; -import okhttp3.OkHttpClient; - -public class Snabble { - private static final Snabble instance = new Snabble(); - - private Map brands; - private List projects; - private TokenRegistry tokenRegistry; - private Receipts receipts; - private Users users; - private Application application; - private MetadataDownloader metadataDownloader; - private UserPreferences userPreferences; - private PaymentCredentialsStore paymentCredentialsStore; - private CheckInLocationManager checkInLocationManager; - private CheckInManager checkInManager; - private File internalStorageDirectory; - private String metadataUrl; - private Config config; - private final List onMetaDataUpdateListeners = new CopyOnWriteArrayList<>(); - private String versionName; - private Environment environment; - private TermsOfService termsOfService; - private List paymentCertificates; - private String receiptsUrl; - private String usersUrl; - private String consentUrl; - private String telecashSecretUrl; - private String telecashPreAuthUrl; - private String paydirektAuthUrl; - private String createAppUserUrl; - private OkHttpClient okHttpClient; - private WeakReference currentActivity; - private MutableLiveData initializationState = new MutableLiveData(InitializationState.NONE); - - private Snabble() { +package io.snabble.sdk + +import io.snabble.sdk.Project +import io.snabble.sdk.auth.TokenRegistry +import io.snabble.sdk.Receipts +import io.snabble.sdk.Users +import io.snabble.sdk.MetadataDownloader +import io.snabble.sdk.UserPreferences +import io.snabble.sdk.payment.PaymentCredentialsStore +import io.snabble.sdk.checkin.CheckInLocationManager +import io.snabble.sdk.checkin.CheckInManager +import io.snabble.sdk.TermsOfService +import okhttp3.OkHttpClient +import android.app.Activity +import android.app.Application +import androidx.lifecycle.MutableLiveData +import io.snabble.sdk.InitializationState +import io.snabble.sdk.Snabble.SetupCompletionListener +import io.snabble.sdk.utils.Logger.ErrorEventHandler +import io.snabble.sdk.utils.Logger.LogEventHandler +import android.content.pm.PackageInfo +import android.content.pm.PackageManager +import io.snabble.sdk.OkHttpClientFactory +import io.snabble.sdk.auth.AppUser +import android.net.ConnectivityManager +import android.net.NetworkRequest +import android.net.NetworkCapabilities +import androidx.lifecycle.LiveData +import com.google.gson.JsonObject +import com.google.gson.JsonElement +import com.google.gson.JsonArray +import kotlin.Throws +import io.snabble.sdk.Snabble.SnabbleException +import android.app.Application.ActivityLifecycleCallbacks +import android.content.Context +import android.net.ConnectivityManager.NetworkCallback +import android.net.Network +import android.util.Base64 +import io.snabble.sdk.Snabble +import io.snabble.sdk.utils.* +import java.io.ByteArrayInputStream +import java.io.File +import java.io.InputStream +import java.lang.Exception +import java.lang.IllegalArgumentException +import java.lang.ref.WeakReference +import java.security.cert.CertificateException +import java.security.cert.CertificateFactory +import java.security.cert.X509Certificate +import java.util.* +import java.util.concurrent.CopyOnWriteArrayList +import java.util.concurrent.CountDownLatch +import java.util.concurrent.TimeUnit +import javax.net.ssl.SSLSocketFactory +import javax.net.ssl.X509TrustManager + +class Snabble private constructor() { + lateinit var okHttpClient: OkHttpClient + private set + + lateinit var tokenRegistry: TokenRegistry + private set + + lateinit var projects: List + private set + + var brands: Map? = null + private set + + lateinit var receipts: Receipts + private set + + lateinit var users: Users + private set + + lateinit var application: Application + private set + + lateinit var userPreferences: UserPreferences + private set + + lateinit var paymentCredentialsStore: PaymentCredentialsStore + private set + + lateinit var checkInLocationManager: CheckInLocationManager + private set + + lateinit var checkInManager: CheckInManager + private set + + lateinit var internalStorageDirectory: File + private set + + lateinit var termsOfService: TermsOfService + private set + + lateinit var config: Config + private set + + var versionName: String? = null + private set + + var environment: Environment? = null + private set + + var paymentCertificates: List? = null + private set + + var metadataUrl: String? = null + private set + + var receiptsUrl: String? = null + get() { + val url = receiptsUrl + val appUser = userPreferences.appUser + return if (appUser != null && url != null) { + url.replace("{appUserID}", appUser.id) + } else { + null + } + } + private set - } + var usersUrl: String? = null + private set + + var consentUrl: String? = null + private set + + var telecashSecretUrl: String? = null + private set - public void setup(Application app, Config config, final SetupCompletionListener setupCompletionListener) { - initializationState.postValue(InitializationState.INITIALIZING); + var telecashPreAuthUrl: String? = null + private set - this.application = app; - this.config = config; + var paydirektAuthUrl: String? = null + private set - Logger.setErrorEventHandler((message, args) -> Events.logErrorEvent(null, message, args)); - Logger.setLogEventHandler((message, args) -> Events.logErrorEvent(null, message, args)); + var createAppUserUrl: String? = null + private set + var initializationState = MutableLiveData(InitializationState.NONE) + private set + + private var currentActivity: WeakReference? = null + + private lateinit var metadataDownloader: MetadataDownloader + + private val onMetaDataUpdateListeners: MutableList = CopyOnWriteArrayList() + + fun setup(app: Application, config: Config, setupCompletionListener: SetupCompletionListener) { + initializationState.postValue(InitializationState.INITIALIZING) + + application = app + this.config = config + + Logger.setErrorEventHandler { message, args -> Events.logErrorEvent(null, message, *args) } + Logger.setLogEventHandler { message, args -> Events.logErrorEvent(null, message, *args) } + if (config.appId == null || config.secret == null) { - setupCompletionListener.onError(Error.CONFIG_PARAMETER_MISSING); - return; + setupCompletionListener.onError(Error.CONFIG_PARAMETER_MISSING) + return } - - String version = config.versionName; + + var version = config.versionName if (version == null) { - try { - PackageInfo pInfo = app.getPackageManager().getPackageInfo(app.getPackageName(), 0); + version = try { + val pInfo = app.packageManager.getPackageInfo(app.packageName, 0) if (pInfo != null && pInfo.versionName != null) { - version = pInfo.versionName.toLowerCase(Locale.ROOT).replace(" ", ""); + pInfo.versionName.toLowerCase(Locale.ROOT).replace(" ", "") } else { - version = "1.0"; + "1.0" } - } catch (PackageManager.NameNotFoundException e) { - version = "1.0"; + } catch (e: PackageManager.NameNotFoundException) { + "1.0" } } - - versionName = version; - - internalStorageDirectory = new File(application.getFilesDir(), "snabble/" + config.appId + "/"); - //noinspection ResultOfMethodCallIgnored - internalStorageDirectory.mkdirs(); - - okHttpClient = OkHttpClientFactory.createOkHttpClient(app); - userPreferences = new UserPreferences(app); - tokenRegistry = new TokenRegistry(okHttpClient, userPreferences, config.appId, config.secret); - receipts = new Receipts(); - users = new Users(userPreferences); - - brands = Collections.unmodifiableMap(new HashMap<>()); - projects = Collections.unmodifiableList(new ArrayList<>()); + versionName = version + + internalStorageDirectory = File(application.filesDir, "snabble/" + config.appId + "/") + internalStorageDirectory.mkdirs() + + okHttpClient = OkHttpClientFactory.createOkHttpClient(app) + userPreferences = UserPreferences(app) + tokenRegistry = TokenRegistry(okHttpClient, userPreferences, config.appId, config.secret) + receipts = Receipts() + users = Users(userPreferences) + brands = Collections.unmodifiableMap(HashMap()) + projects = Collections.unmodifiableList(ArrayList()) if (config.endpointBaseUrl == null) { - config.endpointBaseUrl = Environment.PRODUCTION.getBaseUrl(); - } else if (!config.endpointBaseUrl.startsWith("http://") && !config.endpointBaseUrl.startsWith("https://")) { - config.endpointBaseUrl = "https://" + config.endpointBaseUrl; - } - - environment = Environment.getEnvironmentByUrl(config.endpointBaseUrl); - metadataUrl = absoluteUrl("/metadata/app/" + config.appId + "/android/" + version); - paymentCredentialsStore = new PaymentCredentialsStore(); - checkInLocationManager = new CheckInLocationManager(application); - checkInManager = new CheckInManager(this, - checkInLocationManager, - config.checkInRadius, - config.checkOutRadius, - config.lastSeenThreshold - ); - - this.metadataDownloader = new MetadataDownloader(okHttpClient, config.bundledMetadataAssetPath); - + config.endpointBaseUrl = Environment.PRODUCTION.baseUrl + } else if (!config.endpointBaseUrl!!.startsWith("http://") && !config.endpointBaseUrl!!.startsWith("https://")) { + config.endpointBaseUrl = "https://" + config.endpointBaseUrl + } + + environment = Environment.getEnvironmentByUrl(config.endpointBaseUrl) + metadataUrl = absoluteUrl("/metadata/app/" + config.appId + "/android/" + version) + paymentCredentialsStore = PaymentCredentialsStore() + + checkInLocationManager = CheckInLocationManager(application) + checkInManager = CheckInManager(this, + checkInLocationManager, + config.checkInRadius, + config.checkOutRadius, + config.lastSeenThreshold + ) + + metadataDownloader = MetadataDownloader(okHttpClient, config.bundledMetadataAssetPath) + if (config.bundledMetadataAssetPath != null) { - readMetadata(); - setupCompletionListener.onReady(); - initializationState.postValue(InitializationState.INITIALIZED); - + readMetadata() + setupCompletionListener.onReady() + initializationState.postValue(InitializationState.INITIALIZED) if (config.loadActiveShops) { - loadActiveShops(); + loadActiveShops() } } else { - metadataDownloader.loadAsync(new Downloader.Callback() { - @Override - protected void onDataLoaded(boolean wasStillValid) { - readMetadata(); - - AppUser appUser = userPreferences.getAppUser(); - if (appUser == null && projects.size() > 0) { - Token token = tokenRegistry.getToken(projects.get(0)); + metadataDownloader.loadAsync(object : Downloader.Callback() { + override fun onDataLoaded(wasStillValid: Boolean) { + readMetadata() + val appUser = userPreferences.appUser + if (appUser == null && projects.size > 0) { + val token = tokenRegistry.getToken(projects.get(0)) if (token == null) { - setupCompletionListener.onError(Error.CONNECTION_TIMEOUT); - initializationState.postValue(InitializationState.ERROR); - return; + setupCompletionListener.onError(Error.CONNECTION_TIMEOUT) + initializationState.postValue(InitializationState.ERROR) + return } } - - setupCompletionListener.onReady(); - initializationState.postValue(InitializationState.INITIALIZED); - + setupCompletionListener.onReady() + initializationState.postValue(InitializationState.INITIALIZED) if (config.loadActiveShops) { - loadActiveShops(); + loadActiveShops() } } - @Override - protected void onError() { + override fun onError() { if (metadataDownloader.hasData()) { - readMetadata(); - setupCompletionListener.onReady(); - initializationState.postValue(InitializationState.INITIALIZED); + readMetadata() + setupCompletionListener.onReady() + initializationState.postValue(InitializationState.INITIALIZED) } else { - setupCompletionListener.onError(Error.CONNECTION_TIMEOUT); - initializationState.postValue(InitializationState.ERROR); + setupCompletionListener.onError(Error.CONNECTION_TIMEOUT) + initializationState.postValue(InitializationState.ERROR) } } - }); + }) } - - app.registerActivityLifecycleCallbacks(activityLifecycleCallbacks); - registerNetworkCallback(app); - } - - private void registerNetworkCallback(Application app) { - ConnectivityManager cm = (ConnectivityManager) app.getSystemService(Context.CONNECTIVITY_SERVICE); - - cm.registerNetworkCallback(new NetworkRequest.Builder() - .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) - .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR).build(), - networkCallback); + + app.registerActivityLifecycleCallbacks(activityLifecycleCallbacks) + registerNetworkCallback(app) } - public LiveData getInitializationState() { - return initializationState; + private fun registerNetworkCallback(app: Application) { + val cm = app.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager + cm.registerNetworkCallback(NetworkRequest.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR).build(), + networkCallback) } - public String getVersionName() { - return versionName; + fun getInitializationState(): LiveData { + return initializationState } /** * Returns true when the SDK is not compatible with the backend anymore and the app should * notify the user that it will not function anymore. */ - public boolean isOutdatedSDK() { - JsonObject jsonObject = getAdditionalMetadata(); - if (jsonObject != null) { - return JsonUtils.getBooleanOpt(jsonObject, "kill", false); + val isOutdatedSDK: Boolean + get() { + val jsonObject = additionalMetadata + return if (jsonObject != null) { + JsonUtils.getBooleanOpt(jsonObject, "kill", false) + } else false } - return false; - } - - /** Returns additional metadata that may be provided for apps unrelated to the SDK **/ - public JsonObject getAdditionalMetadata() { - JsonObject jsonObject = metadataDownloader.getJsonObject(); - - JsonElement jsonElement = jsonObject.get("metadata"); - if (jsonElement != null) { - return jsonElement.getAsJsonObject(); + /** Returns additional metadata that may be provided for apps unrelated to the SDK */ + val additionalMetadata: JsonObject? + get() { + val jsonObject = metadataDownloader.jsonObject + val jsonElement = jsonObject["metadata"] + return jsonElement?.asJsonObject } - return null; - } - - private synchronized void readMetadata() { - JsonObject jsonObject = metadataDownloader.getJsonObject(); + @Synchronized + private fun readMetadata() { + val jsonObject = metadataDownloader.jsonObject if (jsonObject != null) { - createAppUserUrl = getUrl(jsonObject, "createAppUser"); - telecashSecretUrl = getUrl(jsonObject, "telecashSecret"); - telecashPreAuthUrl = getUrl(jsonObject, "telecashPreauth"); - paydirektAuthUrl = getUrl(jsonObject, "paydirektCustomerAuthorization"); - + createAppUserUrl = getUrl(jsonObject, "createAppUser") + telecashSecretUrl = getUrl(jsonObject, "telecashSecret") + telecashPreAuthUrl = getUrl(jsonObject, "telecashPreauth") + paydirektAuthUrl = getUrl(jsonObject, "paydirektCustomerAuthorization") + if (jsonObject.has("brands")) { - parseBrands(jsonObject); + parseBrands(jsonObject) } - + if (jsonObject.has("projects")) { - parseProjects(jsonObject); + parseProjects(jsonObject) } - + if (jsonObject.has("gatewayCertificates")) { - parsePaymentCertificates(jsonObject); + parsePaymentCertificates(jsonObject) } - - receiptsUrl = getUrl(jsonObject, "appUserOrders"); - usersUrl = getUrl(jsonObject, "appUser"); - consentUrl = getUrl(jsonObject, "consents"); - + + receiptsUrl = getUrl(jsonObject, "appUserOrders") + usersUrl = getUrl(jsonObject, "appUser") + consentUrl = getUrl(jsonObject, "consents") if (jsonObject.has("terms")) { - termsOfService = GsonHolder.get().fromJson(jsonObject.get("terms"), TermsOfService.class); + termsOfService = + GsonHolder.get().fromJson(jsonObject["terms"], TermsOfService::class.java) } } - - paymentCredentialsStore.init(application, environment); - users.postPendingConsents(); - checkInManager.update(); + + paymentCredentialsStore.init(application, environment) + users.postPendingConsents() + checkInManager.update() } - private String getUrl(JsonObject jsonObject, String urlName) { - try { - return absoluteUrl(jsonObject.get("links").getAsJsonObject() - .get(urlName).getAsJsonObject() - .get("href").getAsString()); - } catch (Exception e) { - return null; + private fun getUrl(jsonObject: JsonObject, urlName: String): String? { + return try { + absoluteUrl(jsonObject["links"].asJsonObject[urlName].asJsonObject["href"].asString) + } catch (e: Exception) { + null } } - private void parseBrands(JsonObject jsonObject) { - Brand[] jsonBrands = GsonHolder.get().fromJson(jsonObject.get("brands"), Brand[].class); - HashMap map = new HashMap<>(); - for (Brand brand : jsonBrands) { - map.put(brand.getId(), brand); - } - brands = Collections.unmodifiableMap(map); + private fun parseBrands(jsonObject: JsonObject) { + val jsonBrands = GsonHolder.get().fromJson(jsonObject["brands"], Array::class.java) + val map = HashMap() + for (brand in jsonBrands) { + map[brand.id] = brand + } + brands = Collections.unmodifiableMap(map) } - private void parseProjects(JsonObject jsonObject) { - JsonArray jsonArray = jsonObject.get("projects").getAsJsonArray(); - List newProjects = new ArrayList<>(); - - for (int i = 0; i < jsonArray.size(); i++) { - JsonObject jsonProject = jsonArray.get(i).getAsJsonObject(); + private fun parseProjects(jsonObject: JsonObject) { + val jsonArray = jsonObject["projects"].asJsonArray + val newProjects: MutableList = ArrayList() + for (i in 0 until jsonArray.size()) { + val jsonProject = jsonArray[i].asJsonObject // first try to find an already existing project and update it, so that // the object reference can be stored somewhere and still be up to date - boolean updated = false; + var updated = false if (jsonProject.has("id")) { - for (Project p : projects) { - if (p.getId().equals(jsonProject.get("id").getAsString())) { + for (p in projects) { + if (p.id == jsonProject["id"].asString) { try { - p.parse(jsonProject); - newProjects.add(p); - } catch (IllegalArgumentException e) { + p.parse(jsonProject) + newProjects.add(p) + } catch (e: IllegalArgumentException) { // malformed project, do nothing } - - updated = true; - break; + updated = true + break } } // if it does not exist, add it if (!updated) { try { - Project project = new Project(jsonProject); - newProjects.add(project); - } catch (IllegalArgumentException e) { - Logger.d(e.getMessage()); + val project = Project(jsonProject) + newProjects.add(project) + } catch (e: IllegalArgumentException) { + Logger.d(e.message) // malformed project, do nothing } } } } - - projects = Collections.unmodifiableList(newProjects); + + projects = Collections.unmodifiableList(newProjects) } - private void parsePaymentCertificates(JsonObject jsonObject) { - List certificates = new ArrayList<>(); - - JsonArray certs = jsonObject.get("gatewayCertificates").getAsJsonArray(); - for (int i=0; i = ArrayList() + val certs = jsonObject["gatewayCertificates"].asJsonArray + for (i in 0 until certs.size()) { + val jsonElement = certs[i] + if (jsonElement.isJsonObject) { + val cert = jsonElement.asJsonObject + val value = cert["value"] if (value != null) { - byte[] bytes = Base64.decode(value.getAsString(), Base64.DEFAULT); - InputStream is = new ByteArrayInputStream(bytes); - + val bytes = Base64.decode(value.asString, Base64.DEFAULT) + val `is`: InputStream = ByteArrayInputStream(bytes) try { - CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); - X509Certificate certificate = (X509Certificate) certificateFactory.generateCertificate(is); - certificates.add(certificate); - } catch (CertificateException e) { - e.printStackTrace(); + val certificateFactory = CertificateFactory.getInstance("X.509") + val certificate = + certificateFactory.generateCertificate(`is`) as X509Certificate + certificates.add(certificate) + } catch (e: CertificateException) { + e.printStackTrace() } } } } - - paymentCertificates = Collections.unmodifiableList(certificates); - } - - public String absoluteUrl(String url) { - if (url == null) { - return null; - } - - if (url.startsWith("http")) { - return url; - } else { - return getEndpointBaseUrl() + url; - } - } - - public String getEndpointBaseUrl() { - return config.endpointBaseUrl; - } - - public String getMetadataUrl() { - return metadataUrl; + + paymentCertificates = Collections.unmodifiableList(certificates) } - public String getReceiptsUrl() { - AppUser appUser = userPreferences.getAppUser(); - if (appUser != null && receiptsUrl != null) { - return receiptsUrl.replace("{appUserID}", userPreferences.getAppUser().id); + fun absoluteUrl(url: String): String { + return if (url.startsWith("http")) { + url } else { - return null; + endpointBaseUrl + url } } - public String getTelecashSecretUrl() { - return telecashSecretUrl; - } - - public String getTelecashPreAuthUrl() { - return telecashPreAuthUrl; - } - - public String getPaydirektAuthUrl() { - return paydirektAuthUrl; - } - - public String getCreateAppUserUrl() { - return createAppUserUrl; - } - - public String getUsersUrl() { - return usersUrl; - } - - public String getConsentUrl() { - return consentUrl; - } - - public File getInternalStorageDirectory() { - return internalStorageDirectory; - } - - public Application getApplication() { - return application; - } - - public OkHttpClient getOkHttpClient() { - return okHttpClient; - } - - public TokenRegistry getTokenRegistry() { - return tokenRegistry; - } - - public Receipts getReceipts() { - return receipts; - } - - public Users getUsers() { - return users; - } - - public TermsOfService getTermsOfService() { - return termsOfService; - } - - public CheckInLocationManager getCheckInLocationManager() { - return checkInLocationManager; - } - - public CheckInManager getCheckInManager() { - return checkInManager; - } - - public Map getBrands() { - return brands; - } - - public List getProjects() { - return projects; - } - - public Project getProjectById(String projectId) { - if (projects == null) { - return null; - } + val endpointBaseUrl: String? + get() = config.endpointBaseUrl - for (Project project : projects) { - if (project.getId().equals(projectId)) { - return project; + fun getProjectById(projectId: String): Project? { + for (project in projects) { + if (project.id == projectId) { + return project } } - - return null; - } - - public List getPaymentSigningCertificates() { - return Collections.unmodifiableList(paymentCertificates); + return null } /** - * The blocking version of {@link #setup(Application, Config, SetupCompletionListener)} - *

+ * The blocking version of [.setup] + * + * * Blocks until every initialization is completed, that includes waiting for necessary * network calls if bundled data is not provided. - *

- * If all needed bundled data is provided (See {@link Config}), initialization requires + * + * + * If all needed bundled data is provided (See [Config]), initialization requires * no network calls. * * @throws SnabbleException If an error occurs while initializing the sdk. */ - public void setupBlocking(Application app, Config config) throws SnabbleException { - final CountDownLatch countDownLatch = new CountDownLatch(1); - final Error[] snabbleError = new Error[1]; - - setup(app, config, new SetupCompletionListener() { - @Override - public void onReady() { - countDownLatch.countDown(); + @Throws(SnabbleException::class) + fun setupBlocking(app: Application, config: Config) { + val countDownLatch = CountDownLatch(1) + val snabbleError = arrayOfNulls(1) + setup(app, config, object : SetupCompletionListener { + override fun onReady() { + countDownLatch.countDown() } - @Override - public void onError(Error error) { - snabbleError[0] = error; - countDownLatch.countDown(); + override fun onError(error: Error?) { + snabbleError[0] = error + countDownLatch.countDown() } - }); - + }) try { - countDownLatch.await(); - } catch (InterruptedException e) { - throw new SnabbleException(Error.UNSPECIFIED_ERROR); + countDownLatch.await() + } catch (e: InterruptedException) { + throw SnabbleException(Error.UNSPECIFIED_ERROR) } - if (snabbleError[0] != null) { - throw new SnabbleException(snabbleError[0]); + throw SnabbleException(snabbleError[0]) } } - public static String getVersion() { - return BuildConfig.VERSION_NAME; - } - - private void updateMetadata() { - metadataDownloader.setUrl(getMetadataUrl()); - metadataDownloader.loadAsync(new Downloader.Callback() { - @Override - protected void onDataLoaded(boolean wasStillValid) { + private fun updateMetadata() { + metadataDownloader.url = metadataUrl + metadataDownloader.loadAsync(object : Downloader.Callback() { + override fun onDataLoaded(wasStillValid: Boolean) { if (!wasStillValid) { - readMetadata(); - notifyMetadataUpdated(); + readMetadata() + notifyMetadataUpdated() } - if (config.loadActiveShops) { - loadActiveShops(); + loadActiveShops() } } - }); + }) } - private void loadActiveShops() { - for (Project project : projects) { - project.loadActiveShops(this::notifyMetadataUpdated); + private fun loadActiveShops() { + for (project in projects) { + project.loadActiveShops { notifyMetadataUpdated() } } } - private void notifyMetadataUpdated() { - for (OnMetadataUpdateListener listener : onMetaDataUpdateListeners) { - listener.onMetaDataUpdated(); + private fun notifyMetadataUpdated() { + for (listener in onMetaDataUpdateListeners) { + listener.onMetaDataUpdated() } } - private void checkCartTimeouts() { - for (Project project : projects) { - project.getShoppingCart().checkForTimeout(); + private fun checkCartTimeouts() { + for (project in projects) { + project.shoppingCart.checkForTimeout() } } - private void processPendingCheckouts() { - for (Project project : projects) { - project.getCheckout().processPendingCheckouts(); + private fun processPendingCheckouts() { + for (project in projects) { + project.checkout.processPendingCheckouts() } } /** * Adds a listener that gets called every time the metadata updates */ - public void addOnMetadataUpdateListener(OnMetadataUpdateListener onMetaDataUpdateListener) { - onMetaDataUpdateListeners.add(onMetaDataUpdateListener); + fun addOnMetadataUpdateListener(onMetaDataUpdateListener: OnMetadataUpdateListener) { + onMetaDataUpdateListeners.add(onMetaDataUpdateListener) } /** * Removes an already added listener */ - public void removeOnMetadataUpdateListener(OnMetadataUpdateListener onMetaDataUpdateListener) { - onMetaDataUpdateListeners.remove(onMetaDataUpdateListener); + fun removeOnMetadataUpdateListener(onMetaDataUpdateListener: OnMetadataUpdateListener) { + onMetaDataUpdateListeners.remove(onMetaDataUpdateListener) } - public interface OnMetadataUpdateListener { - void onMetaDataUpdated(); + interface OnMetadataUpdateListener { + fun onMetaDataUpdated() } - private final Application.ActivityLifecycleCallbacks activityLifecycleCallbacks = new SimpleActivityLifecycleCallbacks() { - - @Override - public void onActivityStarted(Activity activity) { - if (currentActivity != null) { - currentActivity.clear(); - currentActivity = null; + private val activityLifecycleCallbacks: ActivityLifecycleCallbacks = + object : SimpleActivityLifecycleCallbacks() { + override fun onActivityStarted(activity: Activity) { + currentActivity?.clear() + currentActivity = null + currentActivity = WeakReference(activity) + updateMetadata() + checkCartTimeouts() + processPendingCheckouts() } - currentActivity = new WeakReference<>(activity); - updateMetadata(); - checkCartTimeouts(); - processPendingCheckouts(); - } - - @Override - public void onActivityStopped(Activity activity) { - if (currentActivity != null) { - if (currentActivity.get() == activity) { - currentActivity.clear(); - currentActivity = null; + override fun onActivityStopped(activity: Activity) { + if (currentActivity?.get() === activity) { + currentActivity?.clear() + currentActivity = null } } } - }; - - - private final ConnectivityManager.NetworkCallback networkCallback = new ConnectivityManager.NetworkCallback() { - @Override - public void onAvailable(@NonNull Network network) { - onConnectionStateChanged(true); + private val networkCallback: NetworkCallback = object : NetworkCallback() { + override fun onAvailable(network: Network) { + onConnectionStateChanged(true) } - @Override - public void onLost(@NonNull Network network) { - onConnectionStateChanged(false); + override fun onLost(network: Network) { + onConnectionStateChanged(false) } - @Override - public void onUnavailable() { - onConnectionStateChanged(false); + override fun onUnavailable() { + onConnectionStateChanged(false) } - }; + } - private void onConnectionStateChanged(boolean isConnected) { + private fun onConnectionStateChanged(isConnected: Boolean) { if (isConnected) { - processPendingCheckouts(); + processPendingCheckouts() } - - for (Project project : projects) { - project.getShoppingCart().updatePrices(false); + for (project in projects) { + project.shoppingCart.updatePrices(false) } } - /** - * Enables debug logging. - */ - public static void setDebugLoggingEnabled(boolean enabled) { - Logger.setEnabled(enabled); - } - - public Config getConfig() { - return config; - } - /** * Unique identifier, different over device installations */ - public String getClientId() { - return userPreferences.getClientId(); - } - - public Environment getEnvironment() { - return environment; - } - - public UserPreferences getUserPreferences() { - return userPreferences; - } + val clientId: String + get() = userPreferences.clientId - public PaymentCredentialsStore getPaymentCredentialsStore() { - return paymentCredentialsStore; + interface SetupCompletionListener { + fun onReady() + fun onError(error: Error?) } - public static Snabble getInstance() { - return instance; - } - - public Activity getCurrentActivity() { - if (currentActivity != null) { - return currentActivity.get(); - } - - return null; - } - - public interface SetupCompletionListener { - void onReady(); - - void onError(Error error); - } - - public static class SnabbleException extends Exception { - private final Error error; - - SnabbleException(Error error) { - this.error = error; - } - - public Error getError() { - return error; - } - - @NonNull - @Override - public String toString() { + class SnabbleException internal constructor(val error: Error?) : Exception() { + override fun toString(): String { return "SnabbleException{" + "error=" + error + - '}'; + '}' } } - public enum Error { - UNSPECIFIED_ERROR, - CONFIG_PARAMETER_MISSING, - CONNECTION_TIMEOUT, - INVALID_METADATA_FORMAT, - INTERNAL_STORAGE_FULL + enum class Error { + UNSPECIFIED_ERROR, CONFIG_PARAMETER_MISSING, CONNECTION_TIMEOUT, INVALID_METADATA_FORMAT, INTERNAL_STORAGE_FULL } - public static class Config { + class Config { /** * The endpoint url of the snabble backend. For example "snabble.io" for the Production environment. * * If null points to the Production Environment */ - public String endpointBaseUrl; + @JvmField + var endpointBaseUrl: String? = null /** * Relative path from the assets folder which points to a bundled file which contains the metadata - *

+ * + * * This file gets initially used to initialize the sdk before network requests are made, * or be able to use the sdk in the case of no network connection. - *

+ * + * * Optional. If no file is specified every time the sdk is initialized we wait for a network response * from the backend. - *

+ * + * * It is HIGHLY recommended to provide bundled metadata to allow the sdk to function * without having a network connection. */ - public String bundledMetadataAssetPath; + @JvmField + var bundledMetadataAssetPath: String? = null /** * The project identifier, which is used in the communication with the backend. */ - public String appId; + @JvmField + var appId: String? = null /** * The secret needed for Totp token generation */ - public String secret; + @JvmField + var secret: String? = null + /** * Optional. Used to override the versionName appended to the metadata url. - *

+ * + * * Defaults to the versionName in the app package. - *

+ * + * * Must be in the format %d.%d */ - public String versionName; + @JvmField + var versionName: String? = null /** * Optional SSLSocketFactory that gets used for HTTPS requests. - *

+ * + * * Requires also x509TrustManager to be set. */ - public SSLSocketFactory sslSocketFactory = null; + @JvmField + var sslSocketFactory: SSLSocketFactory? = null /** * Optional X509TrustManager that gets used for HTTPS requests. - *

+ * + * * Requires also sslSocketFactory to be set. */ - public X509TrustManager x509TrustManager = null; + @JvmField + var x509TrustManager: X509TrustManager? = null /** * If set to true, creates an full text index to support searching in the product database * using findByName or searchByName. - *

+ * + * * Note that this increases setup time of the ProductDatabase, and it may not be * immediately available offline. */ - public boolean generateSearchIndex; + @JvmField + var generateSearchIndex = false /** * The time that the database is allowed to be out of date. After the specified time in * milliseconds the database only uses online requests for asynchronous requests. * - * Successfully calling {@link ProductDatabase#update()} resets the timer. + * Successfully calling [ProductDatabase.update] resets the timer. * * The time is specified in milliseconds. * * The default value is 1 hour. */ - public long maxProductDatabaseAge = TimeUnit.HOURS.toMillis(1); + @JvmField + var maxProductDatabaseAge = TimeUnit.HOURS.toMillis(1) /** * The time that the shopping cart is allowed to be alive after the last modification. @@ -793,34 +679,41 @@ public class Snabble { * * The default value is 4 hours. */ - public long maxShoppingCartAge = TimeUnit.HOURS.toMillis(4); + @JvmField + var maxShoppingCartAge = TimeUnit.HOURS.toMillis(4) - /** If set to true, disables certificate pinning **/ - public boolean disableCertificatePinning; + /** If set to true, disables certificate pinning */ + @JvmField + var disableCertificatePinning = false - /** SQL queries that will get executed in order on the product database **/ - public String[] initialSQL = null; + /** SQL queries that will get executed in order on the product database */ + @JvmField + var initialSQL: Array? = null - /** Vibrate while adding a product to the cart, by default false */ - public boolean vibrateToConfirmCartFilled = false; + /** Vibrate while adding a product to the cart, by default false */ + @JvmField + var vibrateToConfirmCartFilled = false /** Set to true, to load shops that are marked as pre launch - * and are not part of the original metadata in the backend - * (for example for testing shops in production before a go-live) **/ - public boolean loadActiveShops = false; + * and are not part of the original metadata in the backend + * (for example for testing shops in production before a go-live) */ + @JvmField + var loadActiveShops = false /** * The radius in which the CheckInManager tries to check in a shop. * * In meters. */ - public float checkInRadius = 500.0f; + @JvmField + var checkInRadius = 500.0f /** * The radius in which the CheckInManager tries to stay in a shop, if already in it. * If outside of this radius and the lastSeenThreshold, you will be checked out. */ - public float checkOutRadius = 1000.0f; + @JvmField + var checkOutRadius = 1000.0f /** * The time in milliseconds which we keep you checked in at a shop. @@ -828,6 +721,28 @@ public class Snabble { * The timer will be refreshed while you are still inside the shop * and only begins to run if you are not inside the checkOutRadius anymore. */ - public long lastSeenThreshold = TimeUnit.MINUTES.toMillis(15); + @JvmField + var lastSeenThreshold = TimeUnit.MINUTES.toMillis(15) + } + + companion object { + private val _instance = Snabble() + + @JvmStatic + fun getInstance() : Snabble { + return _instance + } + + @JvmStatic + val version: String + get() = BuildConfig.VERSION_NAME + + /** + * Enables debug logging. + */ + @JvmStatic + fun setDebugLoggingEnabled(enabled: Boolean) { + Logger.setEnabled(enabled) + } } } \ No newline at end of file diff --git a/core/src/main/java/io/snabble/sdk/checkin/CheckInManager.kt b/core/src/main/java/io/snabble/sdk/checkin/CheckInManager.kt index 4b9e7ef182..9657997019 100644 --- a/core/src/main/java/io/snabble/sdk/checkin/CheckInManager.kt +++ b/core/src/main/java/io/snabble/sdk/checkin/CheckInManager.kt @@ -108,8 +108,10 @@ class CheckInManager(val snabble: Snabble, update() } - private val metadataListener = Snabble.OnMetadataUpdateListener { - update() + private val metadataListener = object : Snabble.OnMetadataUpdateListener { + override fun onMetaDataUpdated() { + update() + } } fun update() { diff --git a/core/src/main/java/io/snabble/sdk/payment/PaymentCredentials.java b/core/src/main/java/io/snabble/sdk/payment/PaymentCredentials.java index 3dc1feff94..0396dcda20 100644 --- a/core/src/main/java/io/snabble/sdk/payment/PaymentCredentials.java +++ b/core/src/main/java/io/snabble/sdk/payment/PaymentCredentials.java @@ -181,7 +181,7 @@ public static PaymentCredentials fromSEPA(String name, String iban) { pc.generateId(); pc.type = Type.SEPA; - List certificates = Snabble.getInstance().getPaymentSigningCertificates(); + List certificates = Snabble.getInstance().getPaymentCertificates(); if (certificates.size() == 0) { return null; } @@ -227,7 +227,7 @@ public static PaymentCredentials fromCreditCardData(String name, pc.generateId(); pc.type = Type.CREDIT_CARD_PSD2; - List certificates = Snabble.getInstance().getPaymentSigningCertificates(); + List certificates = Snabble.getInstance().getPaymentCertificates(); if (certificates.size() == 0) { return null; } @@ -312,7 +312,7 @@ public static PaymentCredentials fromPaydirekt(PaydirektAuthorizationData author pc.generateId(); pc.type = Type.PAYDIREKT; - List certificates = Snabble.getInstance().getPaymentSigningCertificates(); + List certificates = Snabble.getInstance().getPaymentCertificates(); if (certificates.size() == 0) { return null; } @@ -359,7 +359,7 @@ public static PaymentCredentials fromDatatrans(String token, Brand brand, String } pc.projectId = projectId; - List certificates = Snabble.getInstance().getPaymentSigningCertificates(); + List certificates = Snabble.getInstance().getPaymentCertificates(); if (certificates.size() == 0) { return null; } @@ -411,7 +411,7 @@ public static PaymentCredentials fromPayone(String pseudocardpan, } pc.projectId = projectId; - List certificates = Snabble.getInstance().getPaymentSigningCertificates(); + List certificates = Snabble.getInstance().getPaymentCertificates(); if (certificates.size() == 0) { return null; } @@ -446,7 +446,7 @@ public static PaymentCredentials fromTegutEmployeeCard(String obfuscatedId, Stri pc.generateId(); pc.type = Type.TEGUT_EMPLOYEE_CARD; - List certificates = Snabble.getInstance().getPaymentSigningCertificates(); + List certificates = Snabble.getInstance().getPaymentCertificates(); if (certificates.size() == 0) { return null; } @@ -481,7 +481,7 @@ public static PaymentCredentials fromLeinweberCustomerId(String obfuscatedId, St pc.generateId(); pc.type = Type.LEINWEBER_CUSTOMER_ID; - List certificates = Snabble.getInstance().getPaymentSigningCertificates(); + List certificates = Snabble.getInstance().getPaymentCertificates(); if (certificates.size() == 0) { return null; } @@ -671,7 +671,7 @@ public boolean validate() { return false; } - List certificates = Snabble.getInstance().getPaymentSigningCertificates(); + List certificates = Snabble.getInstance().getPaymentCertificates(); for (X509Certificate cert : certificates) { if (sha256Signature(cert).equals(signature)) { return true; diff --git a/kotlin-sample/build.gradle b/kotlin-sample/build.gradle index f8b6817db1..3acf5c5066 100644 --- a/kotlin-sample/build.gradle +++ b/kotlin-sample/build.gradle @@ -43,6 +43,7 @@ android { targetCompatibility JavaVersion.VERSION_1_8 } kotlinOptions { + freeCompilerArgs = ['-Xjvm-default=all'] jvmTarget = '1.8' } } diff --git a/kotlin-sample/src/main/java/io/snabble/sdk/sample/LoadingActivity.kt b/kotlin-sample/src/main/java/io/snabble/sdk/sample/LoadingActivity.kt index bda0f15c78..fdd4ddd839 100644 --- a/kotlin-sample/src/main/java/io/snabble/sdk/sample/LoadingActivity.kt +++ b/kotlin-sample/src/main/java/io/snabble/sdk/sample/LoadingActivity.kt @@ -27,8 +27,6 @@ class LoadingActivity : AppCompatActivity() { val snabble = Snabble.getInstance() snabble.setup(application, config, object : Snabble.SetupCompletionListener { override fun onReady() { - //snabble.userPreferences.setRequireKeyguardAuthenticationForPayment(true) - // an application can have multiple projects val project = snabble.projects.first() SnabbleUI.project = project @@ -43,10 +41,10 @@ class LoadingActivity : AppCompatActivity() { } } - override fun onError(error: Snabble.Error) { + override fun onError(error: Snabble.Error?) { runOnUiThread { AlertDialog.Builder(this@LoadingActivity) - .setMessage(error.name) + .setMessage(error?.name) .setPositiveButton("Retry") { _, _ -> initSdk() } diff --git a/ui/src/main/java/io/snabble/sdk/ui/UIPersistence.kt b/ui/src/main/java/io/snabble/sdk/ui/UIPersistence.kt index c5f543e4d3..032c5dece5 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/UIPersistence.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/UIPersistence.kt @@ -18,14 +18,17 @@ object UIPersistence { init { application = snabble.application - snabble.addOnMetadataUpdateListener { - if (!isInitialized) { - isInitialized = true - sharedPreferences = application.getSharedPreferences("snabble_ui_persistence", Context.MODE_PRIVATE) - } - update() - } + snabble.addOnMetadataUpdateListener(object : Snabble.OnMetadataUpdateListener { + override fun onMetaDataUpdated() { + if (!isInitialized) { + isInitialized = true + sharedPreferences = application.getSharedPreferences("snabble_ui_persistence", Context.MODE_PRIVATE) + } + + update() + } + }) } fun update() { diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentInputViewHelper.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentInputViewHelper.kt index ca8ca7fdf7..badb72912e 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentInputViewHelper.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentInputViewHelper.kt @@ -16,7 +16,7 @@ import io.snabble.sdk.utils.Logger object PaymentInputViewHelper { @JvmStatic - fun openPaymentInputView(context: Context, paymentMethod: PaymentMethod?, projectId: String?) { + fun openPaymentInputView(context: Context, paymentMethod: PaymentMethod?, projectId: String) { if (KeyguardUtils.isDeviceSecure()) { val project = Snabble.getInstance().getProjectById(projectId) val acceptedOriginTypes = project?.paymentMethodDescriptors @@ -27,35 +27,46 @@ object PaymentInputViewHelper { val activity = UIUtils.getHostFragmentActivity(context) val args = Bundle() - if (useDatatrans && paymentMethod != null) { - Datatrans.registerCard(activity, project, paymentMethod) - } else if (usePayone && paymentMethod != null) { - Payone.registerCard(activity, project, paymentMethod) - } else { - when (paymentMethod) { - PaymentMethod.VISA -> { - args.putString(CreditCardInputView.ARG_PROJECT_ID, projectId) - args.putSerializable(CreditCardInputView.ARG_PAYMENT_TYPE, PaymentMethod.VISA) - SnabbleUI.executeAction(context, SnabbleUI.Event.SHOW_CREDIT_CARD_INPUT, args) - } - PaymentMethod.AMEX -> { - args.putString(CreditCardInputView.ARG_PROJECT_ID, projectId) - args.putSerializable(CreditCardInputView.ARG_PAYMENT_TYPE, PaymentMethod.AMEX) - SnabbleUI.executeAction(context, SnabbleUI.Event.SHOW_CREDIT_CARD_INPUT, args) - } - PaymentMethod.MASTERCARD -> { - args.putString(CreditCardInputView.ARG_PROJECT_ID, projectId) - args.putSerializable(CreditCardInputView.ARG_PAYMENT_TYPE, PaymentMethod.MASTERCARD) - SnabbleUI.executeAction(context, SnabbleUI.Event.SHOW_CREDIT_CARD_INPUT, args) - } - PaymentMethod.PAYDIREKT -> { - SnabbleUI.executeAction(context, SnabbleUI.Event.SHOW_PAYDIREKT_INPUT) - } - PaymentMethod.DE_DIRECT_DEBIT -> { - SnabbleUI.executeAction(context, SnabbleUI.Event.SHOW_SEPA_CARD_INPUT) - } - else -> { - Logger.e("Payment method requires no credentials or is unsupported") + if (project != null) { + if (useDatatrans && paymentMethod != null) { + Datatrans.registerCard(activity, project, paymentMethod) + } else if (usePayone && paymentMethod != null) { + Payone.registerCard(activity, project, paymentMethod) + } else { + when (paymentMethod) { + PaymentMethod.VISA -> { + args.putString(CreditCardInputView.ARG_PROJECT_ID, projectId) + args.putSerializable(CreditCardInputView.ARG_PAYMENT_TYPE, + PaymentMethod.VISA) + SnabbleUI.executeAction(context, + SnabbleUI.Event.SHOW_CREDIT_CARD_INPUT, + args) + } + PaymentMethod.AMEX -> { + args.putString(CreditCardInputView.ARG_PROJECT_ID, projectId) + args.putSerializable(CreditCardInputView.ARG_PAYMENT_TYPE, + PaymentMethod.AMEX) + SnabbleUI.executeAction(context, + SnabbleUI.Event.SHOW_CREDIT_CARD_INPUT, + args) + } + PaymentMethod.MASTERCARD -> { + args.putString(CreditCardInputView.ARG_PROJECT_ID, projectId) + args.putSerializable(CreditCardInputView.ARG_PAYMENT_TYPE, + PaymentMethod.MASTERCARD) + SnabbleUI.executeAction(context, + SnabbleUI.Event.SHOW_CREDIT_CARD_INPUT, + args) + } + PaymentMethod.PAYDIREKT -> { + SnabbleUI.executeAction(context, SnabbleUI.Event.SHOW_PAYDIREKT_INPUT) + } + PaymentMethod.DE_DIRECT_DEBIT -> { + SnabbleUI.executeAction(context, SnabbleUI.Event.SHOW_SEPA_CARD_INPUT) + } + else -> { + Logger.e("Payment method requires no credentials or is unsupported") + } } } } diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/Payone.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/Payone.kt index d3316ba7b1..055c535846 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/Payone.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/Payone.kt @@ -36,7 +36,7 @@ object Payone { @Parcelize data class Link( - val href: String? + val href: String ) : Parcelable data class PreAuthRequest( diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/PayoneInputView.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/PayoneInputView.kt index a8b876145f..cf9ff99412 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/PayoneInputView.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/PayoneInputView.kt @@ -242,29 +242,36 @@ class PayoneInputView @JvmOverloads constructor(context: Context, attrs: Attribu private fun authenticate(creditCardInfo: CreditCardInfo) { val req = Payone.PreAuthRequest(creditCardInfo.pseudocardpan, creditCardInfo.lastname) - val request = Request.Builder() - .url(Snabble.getInstance().absoluteUrl(Snabble.getInstance().absoluteUrl(tokenizationData.links["preAuth"]?.href))) + val link = tokenizationData.links["preAuth"] + if (link != null) { + val request = Request.Builder() + .url(Snabble.getInstance().absoluteUrl(Snabble.getInstance().absoluteUrl(link.href))) .post(req.toJsonRequest()) - .build() - - project.okHttpClient.newCall(request).enqueue(object : SimpleJsonCallback(Payone.PreAuthResponse::class.java), Callback { - override fun success(response: Payone.PreAuthResponse?) { - response?.let { - lastPreAuthResponse = it - response.links["scaChallenge"]?.href?.let { url -> - Dispatch.mainThread { - threeDHint.isVisible = false - webView.loadUrl(url) - } + .build() + + project.okHttpClient.newCall(request).enqueue(object : + SimpleJsonCallback(Payone.PreAuthResponse::class.java), + Callback { + override fun success(response: Payone.PreAuthResponse?) { + response?.let { + lastPreAuthResponse = it + response.links["scaChallenge"]?.href?.let { url -> + Dispatch.mainThread { + threeDHint.isVisible = false + webView.loadUrl(url) + } + } ?: error(null) } ?: error(null) - } ?: error(null) - } + } - override fun error(t: Throwable?) { - t?.printStackTrace() - Dispatch.mainThread { finishWithError() } - } - }) + override fun error(t: Throwable?) { + t?.printStackTrace() + Dispatch.mainThread { finishWithError() } + } + }) + } else { + Dispatch.mainThread { finishWithError() } + } } From 88267704c9eae3e9f8249a4cde0a9cd25064da4c Mon Sep 17 00:00:00 2001 From: Alexander Junggeburth Date: Mon, 7 Feb 2022 17:00:36 +0100 Subject: [PATCH 04/30] make every fragment depend on BaseFragment --- core/src/main/java/io/snabble/sdk/Snabble.kt | 2 +- .../src/main/java/io/snabble/testapp/App.java | 15 +----------- .../java/io/snabble/testapp/HomeFragment.java | 5 ++-- ...SnabbleBaseFragment.kt => BaseFragment.kt} | 17 ++++++------- .../sdk/ui/cart/PaymentSelectionHelper.java | 24 ++++++++++--------- .../sdk/ui/cart/ShoppingCartFragment.kt | 8 ++----- .../checkout/CheckoutCustomerCardFragment.kt | 5 ++-- .../ui/checkout/CheckoutOfflineFragment.kt | 5 ++-- .../sdk/ui/checkout/CheckoutPOSFragment.kt | 5 ++-- .../sdk/ui/checkout/PaymentStatusFragment.kt | 5 ++-- .../RoutingTargetGatekeeperFragment.kt | 5 ++-- .../RoutingTargetSupervisorFragment.kt | 5 ++-- .../payment/AgeVerificationInputFragment.kt | 5 ++-- .../sdk/ui/payment/CreditCardInputFragment.kt | 5 ++-- .../sdk/ui/payment/PaydirektInputFragment.kt | 5 ++-- .../payment/PaymentCredentialsListFragment.kt | 5 ++-- .../sdk/ui/payment/PaymentOptionsFragment.kt | 5 ++-- .../sdk/ui/payment/PayoneInputFragment.kt | 5 ++-- .../payment/ProjectPaymentOptionsFragment.kt | 5 ++-- .../sdk/ui/payment/SEPACardInputFragment.kt | 5 ++-- .../sdk/ui/search/ProductSearchFragment.kt | 5 ++-- .../main/res/layout/snabble_fragment_base.xml | 2 +- 22 files changed, 74 insertions(+), 74 deletions(-) rename ui/src/main/java/io/snabble/sdk/ui/{SnabbleBaseFragment.kt => BaseFragment.kt} (81%) diff --git a/core/src/main/java/io/snabble/sdk/Snabble.kt b/core/src/main/java/io/snabble/sdk/Snabble.kt index 8ca881724f..3be8aa538a 100644 --- a/core/src/main/java/io/snabble/sdk/Snabble.kt +++ b/core/src/main/java/io/snabble/sdk/Snabble.kt @@ -111,7 +111,7 @@ class Snabble private constructor() { var receiptsUrl: String? = null get() { - val url = receiptsUrl + val url = field val appUser = userPreferences.appUser return if (appUser != null && url != null) { url.replace("{appUserID}", appUser.id) diff --git a/java-sample/src/main/java/io/snabble/testapp/App.java b/java-sample/src/main/java/io/snabble/testapp/App.java index d5acbba08a..3342a56c46 100644 --- a/java-sample/src/main/java/io/snabble/testapp/App.java +++ b/java-sample/src/main/java/io/snabble/testapp/App.java @@ -31,13 +31,6 @@ public interface InitCallback { public void onCreate() { super.onCreate(); instance = this; - } - - public void init(final InitCallback callback) { - if(project != null){ - callback.done(); - return; - } //you may enable debug logging to see requests made by the sdk, and other various logs Snabble.setDebugLoggingEnabled(true); @@ -73,17 +66,11 @@ public void onReady() { // optional: preload assets project.getAssets().update(); - - callback.done(); } @Override public void onError(Snabble.Error error) { - if(config.appId.equals("") || config.secret.equals("")) { - callback.error("SdkError: You did not setup any secrets yet.\nSee README.md for more details."); - } else { - callback.error("SdkError: " + error.toString()); - } + } }); diff --git a/java-sample/src/main/java/io/snabble/testapp/HomeFragment.java b/java-sample/src/main/java/io/snabble/testapp/HomeFragment.java index 361b699aa4..41b4f73052 100644 --- a/java-sample/src/main/java/io/snabble/testapp/HomeFragment.java +++ b/java-sample/src/main/java/io/snabble/testapp/HomeFragment.java @@ -13,7 +13,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.fragment.app.Fragment; import org.apache.commons.io.FileUtils; @@ -23,10 +22,10 @@ import io.snabble.sdk.Project; import io.snabble.sdk.Shop; import io.snabble.sdk.Snabble; -import io.snabble.sdk.ui.SnabbleBaseFragment; +import io.snabble.sdk.ui.BaseFragment; import io.snabble.sdk.ui.SnabbleUI; -public class HomeFragment extends SnabbleBaseFragment { +public class HomeFragment extends BaseFragment { private void updateShops(View v) { Project project = SnabbleUI.getProject(); final List shopList = project.getShops(); diff --git a/ui/src/main/java/io/snabble/sdk/ui/SnabbleBaseFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/BaseFragment.kt similarity index 81% rename from ui/src/main/java/io/snabble/sdk/ui/SnabbleBaseFragment.kt rename to ui/src/main/java/io/snabble/sdk/ui/BaseFragment.kt index 743875fc35..e576f9b36b 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/SnabbleBaseFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/BaseFragment.kt @@ -8,14 +8,13 @@ import android.widget.ProgressBar import android.widget.TextView import androidx.core.view.isVisible import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentContainerView import io.snabble.sdk.InitializationState import io.snabble.sdk.Snabble -abstract class SnabbleBaseFragment : Fragment() { +abstract class BaseFragment : Fragment() { private lateinit var sdkNotInitialized: TextView private lateinit var progress: ProgressBar - private lateinit var fragmentContainer: FragmentContainerView + private lateinit var fragmentContainer: ViewGroup override fun onCreateView( inflater: LayoutInflater, @@ -34,13 +33,13 @@ abstract class SnabbleBaseFragment : Fragment() { when(it) { InitializationState.NONE -> { // TODO init - observeProject(savedInstanceState) + waitForProjectAndAdd(savedInstanceState) } InitializationState.INITIALIZED -> { - observeProject(savedInstanceState) + waitForProjectAndAdd(savedInstanceState) } InitializationState.INITIALIZING -> { - observeProject(savedInstanceState) + waitForProjectAndAdd(savedInstanceState) } InitializationState.ERROR -> { progress.isVisible = false @@ -50,11 +49,13 @@ abstract class SnabbleBaseFragment : Fragment() { } } - private fun observeProject(savedInstanceState: Bundle?) { + private fun waitForProjectAndAdd(savedInstanceState: Bundle?) { + sdkNotInitialized.isVisible = false + SnabbleUI.projectAsLiveData.observe(viewLifecycleOwner) { progress.isVisible = it == null - if (it != null) { + if (it != null && fragmentContainer.childCount == 0) { val fragmentView = onCreateViewInternal(layoutInflater, fragmentContainer, savedInstanceState) if (fragmentView != null) { fragmentContainer.addView(fragmentView) diff --git a/ui/src/main/java/io/snabble/sdk/ui/cart/PaymentSelectionHelper.java b/ui/src/main/java/io/snabble/sdk/ui/cart/PaymentSelectionHelper.java index 330afc4742..5b0150bede 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/cart/PaymentSelectionHelper.java +++ b/ui/src/main/java/io/snabble/sdk/ui/cart/PaymentSelectionHelper.java @@ -132,22 +132,24 @@ private PaymentSelectionHelper() { sharedPreferences = Snabble.getInstance().getApplication() .getSharedPreferences("snabble_cart", Context.MODE_PRIVATE); + setProject(SnabbleUI.getProjectAsLiveData().getValue()); + SnabbleUI.getProjectAsLiveData().observeForever(this::setProject); update(); + } - SnabbleUI.getProjectAsLiveData().observeForever(project -> { - if (project != null) { - PaymentSelectionHelper.this.project = project; + private void setProject(Project project) { + if (project != null) { + PaymentSelectionHelper.this.project = project; - if (cart != null) { - cart.removeListener(shoppingCartListener); - } + if (cart != null) { + cart.removeListener(shoppingCartListener); + } - cart = project.getShoppingCart(); - cart.addListener(shoppingCartListener); + cart = project.getShoppingCart(); + cart.addListener(shoppingCartListener); - update(); - } - }); + update(); + } } private void update() { diff --git a/ui/src/main/java/io/snabble/sdk/ui/cart/ShoppingCartFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/cart/ShoppingCartFragment.kt index f5a9780036..d1887630df 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/cart/ShoppingCartFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/cart/ShoppingCartFragment.kt @@ -2,16 +2,12 @@ package io.snabble.sdk.ui.cart import android.os.Bundle import io.snabble.sdk.ui.R -import io.snabble.sdk.ui.utils.UIUtils -import android.content.res.ColorStateList import android.view.* import androidx.appcompat.app.AlertDialog -import androidx.core.view.MenuItemCompat -import androidx.fragment.app.Fragment -import io.snabble.sdk.ui.SnabbleBaseFragment +import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.SnabbleUI -open class ShoppingCartFragment : SnabbleBaseFragment() { +open class ShoppingCartFragment : BaseFragment() { var shoppingCartView: ShoppingCartView? = null private set diff --git a/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutCustomerCardFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutCustomerCardFragment.kt index afc0e3246e..aa6b169165 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutCustomerCardFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutCustomerCardFragment.kt @@ -5,10 +5,11 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment +import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R -open class CheckoutCustomerCardFragment : Fragment() { - override fun onCreateView( +open class CheckoutCustomerCardFragment : BaseFragment() { + override fun onCreateViewInternal( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? diff --git a/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutOfflineFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutOfflineFragment.kt index cc4ae83cd3..a100e2036f 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutOfflineFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutOfflineFragment.kt @@ -5,10 +5,11 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment +import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R -open class CheckoutOfflineFragment : Fragment() { - override fun onCreateView( +open class CheckoutOfflineFragment : BaseFragment() { + override fun onCreateViewInternal( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? diff --git a/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutPOSFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutPOSFragment.kt index 750b103533..405989b6da 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutPOSFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutPOSFragment.kt @@ -5,10 +5,11 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment +import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R -open class CheckoutPOSFragment : Fragment() { - override fun onCreateView( +open class CheckoutPOSFragment : BaseFragment() { + override fun onCreateViewInternal( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? diff --git a/ui/src/main/java/io/snabble/sdk/ui/checkout/PaymentStatusFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/checkout/PaymentStatusFragment.kt index 88945de4f5..b3a2052dc1 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/checkout/PaymentStatusFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/checkout/PaymentStatusFragment.kt @@ -5,10 +5,11 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment +import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R -open class PaymentStatusFragment : Fragment() { - override fun onCreateView( +open class PaymentStatusFragment : BaseFragment() { + override fun onCreateViewInternal( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? diff --git a/ui/src/main/java/io/snabble/sdk/ui/checkout/routingtargets/RoutingTargetGatekeeperFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/checkout/routingtargets/RoutingTargetGatekeeperFragment.kt index c3b8e5f85c..226fac80ea 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/checkout/routingtargets/RoutingTargetGatekeeperFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/checkout/routingtargets/RoutingTargetGatekeeperFragment.kt @@ -5,10 +5,11 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment +import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R -open class RoutingTargetGatekeeperFragment : Fragment() { - override fun onCreateView( +open class RoutingTargetGatekeeperFragment : BaseFragment() { + override fun onCreateViewInternal( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? diff --git a/ui/src/main/java/io/snabble/sdk/ui/checkout/routingtargets/RoutingTargetSupervisorFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/checkout/routingtargets/RoutingTargetSupervisorFragment.kt index f60b633821..729aefa048 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/checkout/routingtargets/RoutingTargetSupervisorFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/checkout/routingtargets/RoutingTargetSupervisorFragment.kt @@ -5,10 +5,11 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment +import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R -open class RoutingTargetSupervisorFragment : Fragment() { - override fun onCreateView( +open class RoutingTargetSupervisorFragment : BaseFragment() { + override fun onCreateViewInternal( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/AgeVerificationInputFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/AgeVerificationInputFragment.kt index 10336afc13..7b999ff994 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/AgeVerificationInputFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/AgeVerificationInputFragment.kt @@ -5,10 +5,11 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment +import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R -open class AgeVerificationInputFragment : Fragment() { - override fun onCreateView( +open class AgeVerificationInputFragment : BaseFragment() { + override fun onCreateViewInternal( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/CreditCardInputFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/CreditCardInputFragment.kt index 1dd0f0c6a9..4993adbead 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/CreditCardInputFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/CreditCardInputFragment.kt @@ -6,9 +6,10 @@ import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment import io.snabble.sdk.PaymentMethod +import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R -open class CreditCardInputFragment : Fragment() { +open class CreditCardInputFragment : BaseFragment() { companion object { const val ARG_PROJECT_ID = CreditCardInputView.ARG_PROJECT_ID const val ARG_PAYMENT_TYPE = CreditCardInputView.ARG_PAYMENT_TYPE @@ -24,7 +25,7 @@ open class CreditCardInputFragment : Fragment() { paymentMethod = arguments?.getSerializable(ARG_PAYMENT_TYPE) as PaymentMethod? } - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + override fun onCreateViewInternal(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { val v = inflater.inflate(R.layout.snabble_fragment_cardinput_creditcard, container, false) as CreditCardInputView v.load(projectId, paymentMethod) return v diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/PaydirektInputFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/PaydirektInputFragment.kt index a26ca93d71..6b4e9f4577 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/PaydirektInputFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/PaydirektInputFragment.kt @@ -5,10 +5,11 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment +import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R -open class PaydirektInputFragment : Fragment() { - override fun onCreateView( +open class PaydirektInputFragment : BaseFragment() { + override fun onCreateViewInternal( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentCredentialsListFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentCredentialsListFragment.kt index f37886b693..072c6d0ed4 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentCredentialsListFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentCredentialsListFragment.kt @@ -8,10 +8,11 @@ import androidx.fragment.app.Fragment import io.snabble.sdk.Project import io.snabble.sdk.Snabble import io.snabble.sdk.payment.PaymentCredentials +import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R import java.util.ArrayList -open class PaymentCredentialsListFragment : Fragment() { +open class PaymentCredentialsListFragment : BaseFragment() { companion object { const val ARG_PAYMENT_TYPE = PaymentCredentialsListView.ARG_PAYMENT_TYPE const val ARG_PROJECT_ID = PaymentCredentialsListView.ARG_PROJECT_ID @@ -27,7 +28,7 @@ open class PaymentCredentialsListFragment : Fragment() { project = Snabble.getInstance().projects.firstOrNull { it.id == projectId } } - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + override fun onCreateViewInternal(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { val v = inflater.inflate(R.layout.snabble_fragment_payment_credentials_list, container, false) as PaymentCredentialsListView type?.let { v.show(it, project) } return v diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentOptionsFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentOptionsFragment.kt index f97aa7e6b2..7b418367f4 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentOptionsFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentOptionsFragment.kt @@ -5,10 +5,11 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment +import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R -open class PaymentOptionsFragment : Fragment() { - override fun onCreateView( +open class PaymentOptionsFragment : BaseFragment() { + override fun onCreateViewInternal( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/PayoneInputFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/PayoneInputFragment.kt index 4e44224608..ca04f1747a 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/PayoneInputFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/PayoneInputFragment.kt @@ -6,9 +6,10 @@ import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment import io.snabble.sdk.PaymentMethod +import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R -open class PayoneInputFragment : Fragment() { +open class PayoneInputFragment : BaseFragment() { companion object { const val ARG_PROJECT_ID = PayoneInputView.ARG_PROJECT_ID const val ARG_PAYMENT_TYPE = PayoneInputView.ARG_PAYMENT_TYPE @@ -27,7 +28,7 @@ open class PayoneInputFragment : Fragment() { tokenizationData = requireNotNull(arguments?.getParcelable(ARG_TOKEN_DATA)) } - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View = + override fun onCreateViewInternal(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View = inflater.inflate(R.layout.snabble_fragment_cardinput_payone, container, false).apply { findViewById(R.id.user_payment_method_view).load(projectId, paymentMethod, tokenizationData) } diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/ProjectPaymentOptionsFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/ProjectPaymentOptionsFragment.kt index f2f87e94e3..2ef02ee328 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/ProjectPaymentOptionsFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/ProjectPaymentOptionsFragment.kt @@ -7,9 +7,10 @@ import android.view.ViewGroup import androidx.fragment.app.Fragment import io.snabble.sdk.Project import io.snabble.sdk.Snabble +import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R -open class ProjectPaymentOptionsFragment : Fragment() { +open class ProjectPaymentOptionsFragment : BaseFragment() { companion object { const val ARG_BRAND = ProjectPaymentOptionsView.ARG_BRAND } @@ -24,7 +25,7 @@ open class ProjectPaymentOptionsFragment : Fragment() { } } - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + override fun onCreateViewInternal(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { val v = inflater.inflate( R.layout.snabble_fragment_select_payment_project, container, diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/SEPACardInputFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/SEPACardInputFragment.kt index 57c866b115..feacd3656f 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/SEPACardInputFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/SEPACardInputFragment.kt @@ -7,9 +7,10 @@ import android.view.ViewGroup import androidx.fragment.app.Fragment import io.snabble.sdk.PaymentMethod import io.snabble.sdk.PaymentOriginCandidateHelper +import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R -open class SEPACardInputFragment : Fragment() { +open class SEPACardInputFragment : BaseFragment() { companion object { const val ARG_PAYMENT_ORIGIN_CANDIDATE = "paymentOriginCandidate" } @@ -23,7 +24,7 @@ open class SEPACardInputFragment : Fragment() { as? PaymentOriginCandidateHelper.PaymentOriginCandidate } - override fun onCreateView( + override fun onCreateViewInternal( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? diff --git a/ui/src/main/java/io/snabble/sdk/ui/search/ProductSearchFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/search/ProductSearchFragment.kt index 7d14148740..797f147009 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/search/ProductSearchFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/search/ProductSearchFragment.kt @@ -5,10 +5,11 @@ import android.view.ViewGroup import android.os.Bundle import android.view.View import androidx.fragment.app.Fragment +import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R -open class ProductSearchFragment : Fragment() { - override fun onCreateView( +open class ProductSearchFragment : BaseFragment() { + override fun onCreateViewInternal( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? diff --git a/ui/src/main/res/layout/snabble_fragment_base.xml b/ui/src/main/res/layout/snabble_fragment_base.xml index e6de72e462..1af08e6fb5 100644 --- a/ui/src/main/res/layout/snabble_fragment_base.xml +++ b/ui/src/main/res/layout/snabble_fragment_base.xml @@ -15,7 +15,7 @@ android:layout_gravity="center" android:text="The snabble SDK is not initialized."/> - From cca817d8d73446acaa490486f6bca27ab17ce0ee Mon Sep 17 00:00:00 2001 From: Alexander Junggeburth Date: Tue, 8 Feb 2022 15:42:06 +0100 Subject: [PATCH 05/30] persist config and project --- core/src/main/java/io/snabble/sdk/Config.kt | 154 ++++++++++ .../io/snabble/sdk/OkHttpClientFactory.java | 8 +- .../java/io/snabble/sdk/ProductDatabase.java | 8 +- core/src/main/java/io/snabble/sdk/Snabble.kt | 273 ++++-------------- .../java/io/snabble/sdk/UserPreferences.java | 8 +- .../src/main/java/io/snabble/testapp/App.java | 3 +- .../java/io/snabble/testapp/HomeFragment.java | 89 +++--- .../java/io/snabble/sdk/ui/BaseFragment.kt | 15 +- .../main/java/io/snabble/sdk/ui/SnabbleUI.kt | 10 +- .../java/io/snabble/sdk/ui/UIPersistence.kt | 39 --- .../io/snabble/sdk/ui/UIPersistenceStore.kt | 38 +++ 11 files changed, 316 insertions(+), 329 deletions(-) create mode 100644 core/src/main/java/io/snabble/sdk/Config.kt delete mode 100644 ui/src/main/java/io/snabble/sdk/ui/UIPersistence.kt create mode 100644 ui/src/main/java/io/snabble/sdk/ui/UIPersistenceStore.kt diff --git a/core/src/main/java/io/snabble/sdk/Config.kt b/core/src/main/java/io/snabble/sdk/Config.kt new file mode 100644 index 0000000000..a23322c64c --- /dev/null +++ b/core/src/main/java/io/snabble/sdk/Config.kt @@ -0,0 +1,154 @@ +package io.snabble.sdk + +import android.content.Context +import io.snabble.sdk.utils.GsonHolder +import org.apache.commons.io.IOUtils +import java.io.File +import java.io.FileInputStream +import java.io.FileOutputStream +import java.nio.charset.Charset +import java.util.concurrent.TimeUnit +import javax.net.ssl.SSLSocketFactory +import javax.net.ssl.X509TrustManager + +data class Config ( + /** + * The endpoint url of the snabble backend. For example "https://api.snabble.io" for the Production environment. + */ + @JvmField + var endpointBaseUrl: String = Environment.PRODUCTION.baseUrl, + + /** + * The project identifier, which is used in the communication with the backend. + */ + @JvmField + var appId: String? = null, + + /** + * The secret needed for Totp token generation + */ + @JvmField + var secret: String? = null, + + /** + * Relative path from the assets folder which points to a bundled file which contains the metadata + * + * + * This file gets initially used to initialize the sdk before network requests are made, + * or be able to use the sdk in the case of no network connection. + * + * Optional. If no file is specified every time the sdk is initialized we wait for a network response + * from the backend. + * + * It is HIGHLY recommended to provide bundled metadata to allow the sdk to function + * without having a network connection. + */ + @JvmField + var bundledMetadataAssetPath: String? = null, + + /** + * Optional. Used to override the versionName appended to the metadata url. + * + * Defaults to the versionName in the app package. + * + * Must be in the format %d.%d + */ + @JvmField + var versionName: String? = null, + + /** + * If set to true, creates an full text index to support searching in the product database + * using findByName or searchByName. + * + * Note that this increases setup time of the ProductDatabase, and it may not be + * immediately available offline. + */ + @JvmField + var generateSearchIndex: Boolean = false, + + /** + * The time that the database is allowed to be out of date. After the specified time in + * milliseconds the database only uses online requests for asynchronous requests. + * + * Successfully calling [ProductDatabase.update] resets the timer. + * + * The time is specified in milliseconds. + * + * The default value is 1 hour. + */ + @JvmField + var maxProductDatabaseAge: Long = TimeUnit.HOURS.toMillis(1), + + /** + * The time that the shopping cart is allowed to be alive after the last modification. + * + * The time is specified in milliseconds. + * + * The default value is 4 hours. + */ + @JvmField + var maxShoppingCartAge: Long = TimeUnit.HOURS.toMillis(4), + + /** If set to true, disables certificate pinning */ + @JvmField + var disableCertificatePinning: Boolean = false, + + /** SQL queries that will get executed in order on the product database */ + @JvmField + var initialSQL: List = emptyList(), + + /** Vibrate while adding a product to the cart, by default false */ + @JvmField + var vibrateToConfirmCartFilled: Boolean = false, + + /** Set to true, to load shops that are marked as pre launch + * and are not part of the original metadata in the backend + * (for example for testing shops in production before a go-live) */ + @JvmField + var loadActiveShops: Boolean = false, + + /** + * The radius in which the CheckInManager tries to check in a shop. + * + * In meters. + */ + @JvmField + var checkInRadius: Float = 500.0f, + + /** + * The radius in which the CheckInManager tries to stay in a shop, if already in it. + * If outside of this radius and the lastSeenThreshold, you will be checked out. + */ + @JvmField + var checkOutRadius: Float = 1000.0f, + + /** + * The time in milliseconds which we keep you checked in at a shop. + * + * The timer will be refreshed while you are still inside the shop + * and only begins to run if you are not inside the checkOutRadius anymore. + */ + @JvmField + var lastSeenThreshold: Long = TimeUnit.MINUTES.toMillis(15), +) { + companion object { + fun store(config: Config) { + try { + val snabble = Snabble.getInstance() + val file = File(snabble.internalStorageDirectory, "config.json") + IOUtils.write(GsonHolder.get().toJson(config), FileOutputStream(file), Charset.forName("UTF-8")) + } catch (ignored: Exception) {} + } + + fun load(): Config? { + try { + val snabble = Snabble.getInstance() + val file = File(snabble.internalStorageDirectory, "config.json") + val content = IOUtils.toString(FileInputStream(file), Charset.forName("UTF-8")) + return GsonHolder.get().fromJson(content, Config::class.java) + } catch (e: Exception) { + return null + } + } + } +} \ No newline at end of file diff --git a/core/src/main/java/io/snabble/sdk/OkHttpClientFactory.java b/core/src/main/java/io/snabble/sdk/OkHttpClientFactory.java index d0afed65d4..49ba388421 100644 --- a/core/src/main/java/io/snabble/sdk/OkHttpClientFactory.java +++ b/core/src/main/java/io/snabble/sdk/OkHttpClientFactory.java @@ -42,7 +42,7 @@ static OkHttpClient createOkHttpClient(Application application) { logging.setLevel(HttpLoggingInterceptor.Level.BASIC); builder.addInterceptor(logging); - Snabble.Config config = Snabble.getInstance().getConfig(); + Config config = Snabble.getInstance().getConfig(); builder.addInterceptor(new UserAgentInterceptor(application)); if (!Snabble.getInstance().getConfig().disableCertificatePinning) { @@ -56,11 +56,7 @@ static OkHttpClient createOkHttpClient(Application application) { builder.certificatePinner(certificatePinnerBuilder.build()); } - if (config.sslSocketFactory != null && config.x509TrustManager != null) { - builder.sslSocketFactory(config.sslSocketFactory, config.x509TrustManager); - } else { - LetsEncryptCertHelper.addLetsEncryptCertificatesForMarshmallowOrEarlier(builder); - } + LetsEncryptCertHelper.addLetsEncryptCertificatesForMarshmallowOrEarlier(builder); return builder.build(); } diff --git a/core/src/main/java/io/snabble/sdk/ProductDatabase.java b/core/src/main/java/io/snabble/sdk/ProductDatabase.java index 95489271af..876a129b96 100644 --- a/core/src/main/java/io/snabble/sdk/ProductDatabase.java +++ b/core/src/main/java/io/snabble/sdk/ProductDatabase.java @@ -74,11 +74,9 @@ public class ProductDatabase { this.productApi = new ProductApi(project); if (open()) { - String[] initialSQL = Snabble.getInstance().getConfig().initialSQL; - if (initialSQL != null) { - for (String sql : initialSQL) { - exec(sql); - } + List initialSQL = Snabble.getInstance().getConfig().initialSQL; + for (String sql : initialSQL) { + exec(sql); } } else { Logger.i("Product database is missing. Offline products are not available."); diff --git a/core/src/main/java/io/snabble/sdk/Snabble.kt b/core/src/main/java/io/snabble/sdk/Snabble.kt index 3be8aa538a..1ef11e6b18 100644 --- a/core/src/main/java/io/snabble/sdk/Snabble.kt +++ b/core/src/main/java/io/snabble/sdk/Snabble.kt @@ -1,42 +1,25 @@ package io.snabble.sdk -import io.snabble.sdk.Project import io.snabble.sdk.auth.TokenRegistry -import io.snabble.sdk.Receipts -import io.snabble.sdk.Users -import io.snabble.sdk.MetadataDownloader -import io.snabble.sdk.UserPreferences import io.snabble.sdk.payment.PaymentCredentialsStore import io.snabble.sdk.checkin.CheckInLocationManager import io.snabble.sdk.checkin.CheckInManager -import io.snabble.sdk.TermsOfService import okhttp3.OkHttpClient import android.app.Activity import android.app.Application import androidx.lifecycle.MutableLiveData -import io.snabble.sdk.InitializationState -import io.snabble.sdk.Snabble.SetupCompletionListener -import io.snabble.sdk.utils.Logger.ErrorEventHandler -import io.snabble.sdk.utils.Logger.LogEventHandler -import android.content.pm.PackageInfo import android.content.pm.PackageManager -import io.snabble.sdk.OkHttpClientFactory -import io.snabble.sdk.auth.AppUser import android.net.ConnectivityManager import android.net.NetworkRequest import android.net.NetworkCapabilities import androidx.lifecycle.LiveData import com.google.gson.JsonObject -import com.google.gson.JsonElement -import com.google.gson.JsonArray import kotlin.Throws -import io.snabble.sdk.Snabble.SnabbleException import android.app.Application.ActivityLifecycleCallbacks import android.content.Context import android.net.ConnectivityManager.NetworkCallback import android.net.Network import android.util.Base64 -import io.snabble.sdk.Snabble import io.snabble.sdk.utils.* import java.io.ByteArrayInputStream import java.io.File @@ -50,9 +33,7 @@ import java.security.cert.X509Certificate import java.util.* import java.util.concurrent.CopyOnWriteArrayList import java.util.concurrent.CountDownLatch -import java.util.concurrent.TimeUnit -import javax.net.ssl.SSLSocketFactory -import javax.net.ssl.X509TrustManager +import java.util.concurrent.atomic.AtomicBoolean class Snabble private constructor() { lateinit var okHttpClient: OkHttpClient @@ -148,7 +129,14 @@ class Snabble private constructor() { private val onMetaDataUpdateListeners: MutableList = CopyOnWriteArrayList() + private val isInitializing = AtomicBoolean(false) + fun setup(app: Application, config: Config, setupCompletionListener: SetupCompletionListener) { + if (isInitializing.get()) { + return + } + + isInitializing.set(true) initializationState.postValue(InitializationState.INITIALIZING) application = app @@ -156,12 +144,13 @@ class Snabble private constructor() { Logger.setErrorEventHandler { message, args -> Events.logErrorEvent(null, message, *args) } Logger.setLogEventHandler { message, args -> Events.logErrorEvent(null, message, *args) } - - if (config.appId == null || config.secret == null) { - setupCompletionListener.onError(Error.CONFIG_PARAMETER_MISSING) + + if (!config.endpointBaseUrl.startsWith("http://") + && !config.endpointBaseUrl.startsWith("https://")) { + setupCompletionListener.onError(Error.CONFIG_ERROR) return } - + var version = config.versionName if (version == null) { version = try { @@ -179,6 +168,8 @@ class Snabble private constructor() { internalStorageDirectory = File(application.filesDir, "snabble/" + config.appId + "/") internalStorageDirectory.mkdirs() + + Config.store(config) okHttpClient = OkHttpClientFactory.createOkHttpClient(app) userPreferences = UserPreferences(app) @@ -188,12 +179,6 @@ class Snabble private constructor() { brands = Collections.unmodifiableMap(HashMap()) projects = Collections.unmodifiableList(ArrayList()) - if (config.endpointBaseUrl == null) { - config.endpointBaseUrl = Environment.PRODUCTION.baseUrl - } else if (!config.endpointBaseUrl!!.startsWith("http://") && !config.endpointBaseUrl!!.startsWith("https://")) { - config.endpointBaseUrl = "https://" + config.endpointBaseUrl - } - environment = Environment.getEnvironmentByUrl(config.endpointBaseUrl) metadataUrl = absoluteUrl("/metadata/app/" + config.appId + "/android/" + version) paymentCredentialsStore = PaymentCredentialsStore() @@ -212,6 +197,7 @@ class Snabble private constructor() { readMetadata() setupCompletionListener.onReady() initializationState.postValue(InitializationState.INITIALIZED) + isInitializing.set(false) if (config.loadActiveShops) { loadActiveShops() } @@ -225,11 +211,13 @@ class Snabble private constructor() { if (token == null) { setupCompletionListener.onError(Error.CONNECTION_TIMEOUT) initializationState.postValue(InitializationState.ERROR) + isInitializing.set(false) return } } setupCompletionListener.onReady() initializationState.postValue(InitializationState.INITIALIZED) + isInitializing.set(false) if (config.loadActiveShops) { loadActiveShops() } @@ -240,9 +228,11 @@ class Snabble private constructor() { readMetadata() setupCompletionListener.onReady() initializationState.postValue(InitializationState.INITIALIZED) + isInitializing.set(false) } else { setupCompletionListener.onError(Error.CONNECTION_TIMEOUT) initializationState.postValue(InitializationState.ERROR) + isInitializing.set(false) } } }) @@ -252,6 +242,41 @@ class Snabble private constructor() { registerNetworkCallback(app) } + /** + * The blocking version of [.setup] + * + * Blocks until every initialization is completed, that includes waiting for necessary + * network calls if bundled data is not provided. + * + * If all needed bundled data is provided (See [Config]), initialization requires + * no network calls. + * + * @throws SnabbleException If an error occurs while initializing the sdk. + */ + @Throws(SnabbleException::class) + fun setupBlocking(app: Application, config: Config) { + val countDownLatch = CountDownLatch(1) + val snabbleError = arrayOfNulls(1) + setup(app, config, object : SetupCompletionListener { + override fun onReady() { + countDownLatch.countDown() + } + + override fun onError(error: Error?) { + snabbleError[0] = error + countDownLatch.countDown() + } + }) + try { + countDownLatch.await() + } catch (e: InterruptedException) { + throw SnabbleException(Error.UNSPECIFIED_ERROR) + } + if (snabbleError[0] != null) { + throw SnabbleException(snabbleError[0]) + } + } + private fun registerNetworkCallback(app: Application) { val cm = app.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager cm.registerNetworkCallback(NetworkRequest.Builder() @@ -388,8 +413,7 @@ class Snabble private constructor() { val `is`: InputStream = ByteArrayInputStream(bytes) try { val certificateFactory = CertificateFactory.getInstance("X.509") - val certificate = - certificateFactory.generateCertificate(`is`) as X509Certificate + val certificate = certificateFactory.generateCertificate(`is`) as X509Certificate certificates.add(certificate) } catch (e: CertificateException) { e.printStackTrace() @@ -421,43 +445,6 @@ class Snabble private constructor() { return null } - /** - * The blocking version of [.setup] - * - * - * Blocks until every initialization is completed, that includes waiting for necessary - * network calls if bundled data is not provided. - * - * - * If all needed bundled data is provided (See [Config]), initialization requires - * no network calls. - * - * @throws SnabbleException If an error occurs while initializing the sdk. - */ - @Throws(SnabbleException::class) - fun setupBlocking(app: Application, config: Config) { - val countDownLatch = CountDownLatch(1) - val snabbleError = arrayOfNulls(1) - setup(app, config, object : SetupCompletionListener { - override fun onReady() { - countDownLatch.countDown() - } - - override fun onError(error: Error?) { - snabbleError[0] = error - countDownLatch.countDown() - } - }) - try { - countDownLatch.await() - } catch (e: InterruptedException) { - throw SnabbleException(Error.UNSPECIFIED_ERROR) - } - if (snabbleError[0] != null) { - throw SnabbleException(snabbleError[0]) - } - } - private fun updateMetadata() { metadataDownloader.url = metadataUrl metadataDownloader.loadAsync(object : Downloader.Callback() { @@ -576,153 +563,7 @@ class Snabble private constructor() { } enum class Error { - UNSPECIFIED_ERROR, CONFIG_PARAMETER_MISSING, CONNECTION_TIMEOUT, INVALID_METADATA_FORMAT, INTERNAL_STORAGE_FULL - } - - class Config { - /** - * The endpoint url of the snabble backend. For example "snabble.io" for the Production environment. - * - * If null points to the Production Environment - */ - @JvmField - var endpointBaseUrl: String? = null - - /** - * Relative path from the assets folder which points to a bundled file which contains the metadata - * - * - * This file gets initially used to initialize the sdk before network requests are made, - * or be able to use the sdk in the case of no network connection. - * - * - * Optional. If no file is specified every time the sdk is initialized we wait for a network response - * from the backend. - * - * - * It is HIGHLY recommended to provide bundled metadata to allow the sdk to function - * without having a network connection. - */ - @JvmField - var bundledMetadataAssetPath: String? = null - - /** - * The project identifier, which is used in the communication with the backend. - */ - @JvmField - var appId: String? = null - - /** - * The secret needed for Totp token generation - */ - @JvmField - var secret: String? = null - - /** - * Optional. Used to override the versionName appended to the metadata url. - * - * - * Defaults to the versionName in the app package. - * - * - * Must be in the format %d.%d - */ - @JvmField - var versionName: String? = null - - /** - * Optional SSLSocketFactory that gets used for HTTPS requests. - * - * - * Requires also x509TrustManager to be set. - */ - @JvmField - var sslSocketFactory: SSLSocketFactory? = null - - /** - * Optional X509TrustManager that gets used for HTTPS requests. - * - * - * Requires also sslSocketFactory to be set. - */ - @JvmField - var x509TrustManager: X509TrustManager? = null - - /** - * If set to true, creates an full text index to support searching in the product database - * using findByName or searchByName. - * - * - * Note that this increases setup time of the ProductDatabase, and it may not be - * immediately available offline. - */ - @JvmField - var generateSearchIndex = false - - /** - * The time that the database is allowed to be out of date. After the specified time in - * milliseconds the database only uses online requests for asynchronous requests. - * - * Successfully calling [ProductDatabase.update] resets the timer. - * - * The time is specified in milliseconds. - * - * The default value is 1 hour. - */ - @JvmField - var maxProductDatabaseAge = TimeUnit.HOURS.toMillis(1) - - /** - * The time that the shopping cart is allowed to be alive after the last modification. - * - * The time is specified in milliseconds. - * - * The default value is 4 hours. - */ - @JvmField - var maxShoppingCartAge = TimeUnit.HOURS.toMillis(4) - - /** If set to true, disables certificate pinning */ - @JvmField - var disableCertificatePinning = false - - /** SQL queries that will get executed in order on the product database */ - @JvmField - var initialSQL: Array? = null - - /** Vibrate while adding a product to the cart, by default false */ - @JvmField - var vibrateToConfirmCartFilled = false - - /** Set to true, to load shops that are marked as pre launch - * and are not part of the original metadata in the backend - * (for example for testing shops in production before a go-live) */ - @JvmField - var loadActiveShops = false - - /** - * The radius in which the CheckInManager tries to check in a shop. - * - * In meters. - */ - @JvmField - var checkInRadius = 500.0f - - /** - * The radius in which the CheckInManager tries to stay in a shop, if already in it. - * If outside of this radius and the lastSeenThreshold, you will be checked out. - */ - @JvmField - var checkOutRadius = 1000.0f - - /** - * The time in milliseconds which we keep you checked in at a shop. - * - * The timer will be refreshed while you are still inside the shop - * and only begins to run if you are not inside the checkOutRadius anymore. - */ - @JvmField - var lastSeenThreshold = TimeUnit.MINUTES.toMillis(15) + UNSPECIFIED_ERROR, CONFIG_ERROR, CONNECTION_TIMEOUT, INVALID_METADATA_FORMAT, INTERNAL_STORAGE_FULL } companion object { diff --git a/core/src/main/java/io/snabble/sdk/UserPreferences.java b/core/src/main/java/io/snabble/sdk/UserPreferences.java index e49156e2f0..3ea22a6b6f 100644 --- a/core/src/main/java/io/snabble/sdk/UserPreferences.java +++ b/core/src/main/java/io/snabble/sdk/UserPreferences.java @@ -65,19 +65,17 @@ private String getEnvironmentKey() { } private String getAppUserIdKey() { - Snabble.Config config = Snabble.getInstance().getConfig(); - - + Config config = Snabble.getInstance().getConfig(); return SHARED_PREFERENCES_APPUSER_ID + "_" + getEnvironmentKey() + config.appId; } private String getAppUserIdSecret() { - Snabble.Config config = Snabble.getInstance().getConfig(); + Config config = Snabble.getInstance().getConfig(); return SHARED_PREFERENCES_APPUSER_SECRET + "_" + getEnvironmentKey() + config.appId; } public AppUser getAppUser() { - Snabble.Config config = Snabble.getInstance().getConfig(); + Config config = Snabble.getInstance().getConfig(); if (config == null) { return null; } diff --git a/java-sample/src/main/java/io/snabble/testapp/App.java b/java-sample/src/main/java/io/snabble/testapp/App.java index 3342a56c46..3d30a5d132 100644 --- a/java-sample/src/main/java/io/snabble/testapp/App.java +++ b/java-sample/src/main/java/io/snabble/testapp/App.java @@ -11,6 +11,7 @@ import java.nio.charset.Charset; import java.util.concurrent.CountDownLatch; +import io.snabble.sdk.Config; import io.snabble.sdk.Project; import io.snabble.sdk.Snabble; import io.snabble.sdk.ui.SnabbleUI; @@ -36,7 +37,7 @@ public void onCreate() { Snabble.setDebugLoggingEnabled(true); // config { - Snabble.Config config = new Snabble.Config(); + Config config = new Config(); config.endpointBaseUrl = getString(R.string.endpoint); config.secret = getString(R.string.secret); config.appId = getString(R.string.app_id); diff --git a/java-sample/src/main/java/io/snabble/testapp/HomeFragment.java b/java-sample/src/main/java/io/snabble/testapp/HomeFragment.java index 41b4f73052..5bc327e24d 100644 --- a/java-sample/src/main/java/io/snabble/testapp/HomeFragment.java +++ b/java-sample/src/main/java/io/snabble/testapp/HomeFragment.java @@ -26,51 +26,6 @@ import io.snabble.sdk.ui.SnabbleUI; public class HomeFragment extends BaseFragment { - private void updateShops(View v) { - Project project = SnabbleUI.getProject(); - final List shopList = project.getShops(); - Spinner shops = v.findViewById(R.id.shops); - shops.setAdapter(new ArrayAdapter(requireContext(), R.layout.item_dropdown, shopList) { - @NonNull - @Override - public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { - TextView v = (TextView) super.getView(position, convertView, parent); - Shop shop = shopList.get(position); - v.setText(shop.getName() + " (" + shop.getId() + ")"); - return v; - } - - @Override - public View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { - TextView v = (TextView) super.getDropDownView(position, convertView, parent); - Shop shop = shopList.get(position); - v.setText(shop.getName() + " (" + shop.getId() + ")"); - return v; - } - }); - - for (int i=0; i parent, View view, int position, long id) { - Shop shop = shopList.get(position); - project.setCheckedInShop(shop); - } - - @Override - public void onNothingSelected(AdapterView parent) { - - } - }); - } - - @Nullable @Override public View onCreateViewInternal(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { @@ -153,4 +108,48 @@ public void onNothingSelected(AdapterView parent) { return v; } + + private void updateShops(View v) { + Project project = SnabbleUI.getProject(); + final List shopList = project.getShops(); + Spinner shops = v.findViewById(R.id.shops); + shops.setAdapter(new ArrayAdapter(requireContext(), R.layout.item_dropdown, shopList) { + @NonNull + @Override + public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { + TextView v = (TextView) super.getView(position, convertView, parent); + Shop shop = shopList.get(position); + v.setText(shop.getName() + " (" + shop.getId() + ")"); + return v; + } + + @Override + public View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { + TextView v = (TextView) super.getDropDownView(position, convertView, parent); + Shop shop = shopList.get(position); + v.setText(shop.getName() + " (" + shop.getId() + ")"); + return v; + } + }); + + for (int i=0; i parent, View view, int position, long id) { + Shop shop = shopList.get(position); + project.setCheckedInShop(shop); + } + + @Override + public void onNothingSelected(AdapterView parent) { + + } + }); + } } \ No newline at end of file diff --git a/ui/src/main/java/io/snabble/sdk/ui/BaseFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/BaseFragment.kt index e576f9b36b..f6518b7d2a 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/BaseFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/BaseFragment.kt @@ -8,6 +8,7 @@ import android.widget.ProgressBar import android.widget.TextView import androidx.core.view.isVisible import androidx.fragment.app.Fragment +import io.snabble.sdk.Config import io.snabble.sdk.InitializationState import io.snabble.sdk.Snabble @@ -32,7 +33,6 @@ abstract class BaseFragment : Fragment() { Snabble.getInstance().initializationState.observe(viewLifecycleOwner) { when(it) { InitializationState.NONE -> { - // TODO init waitForProjectAndAdd(savedInstanceState) } InitializationState.INITIALIZED -> { @@ -55,11 +55,16 @@ abstract class BaseFragment : Fragment() { SnabbleUI.projectAsLiveData.observe(viewLifecycleOwner) { progress.isVisible = it == null - if (it != null && fragmentContainer.childCount == 0) { - val fragmentView = onCreateViewInternal(layoutInflater, fragmentContainer, savedInstanceState) - if (fragmentView != null) { - fragmentContainer.addView(fragmentView) + if (it != null) { + if (fragmentContainer.childCount == 0) { + val fragmentView = + onCreateViewInternal(layoutInflater, fragmentContainer, savedInstanceState) + if (fragmentView != null) { + fragmentContainer.addView(fragmentView) + } } + } else { + fragmentContainer.removeAllViews() } } } diff --git a/ui/src/main/java/io/snabble/sdk/ui/SnabbleUI.kt b/ui/src/main/java/io/snabble/sdk/ui/SnabbleUI.kt index 9f8c37f331..7c966db273 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/SnabbleUI.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/SnabbleUI.kt @@ -52,22 +52,18 @@ object SnabbleUI { private var actions = mutableMapOf() - private val projectLiveData = MutableLiveData() - private var nullableProject: Project? = null - @JvmStatic var project: Project get() { - return requireNotNull(nullableProject) + return requireNotNull(UIPersistenceStore.project.value) } set(value) { - nullableProject = value - projectLiveData.postValue(value) + UIPersistenceStore.updateProject(value) } @JvmStatic val projectAsLiveData: LiveData - get() = projectLiveData + get() = UIPersistenceStore.project /** * Sets an action handler for custom implementations of events. diff --git a/ui/src/main/java/io/snabble/sdk/ui/UIPersistence.kt b/ui/src/main/java/io/snabble/sdk/ui/UIPersistence.kt deleted file mode 100644 index 032c5dece5..0000000000 --- a/ui/src/main/java/io/snabble/sdk/ui/UIPersistence.kt +++ /dev/null @@ -1,39 +0,0 @@ -package io.snabble.sdk.ui - -import android.app.Application -import android.content.Context -import android.content.SharedPreferences -import androidx.lifecycle.MutableLiveData -import io.snabble.sdk.Project -import io.snabble.sdk.Snabble - -object UIPersistence { - private var isInitialized = false - private var application: Application - private lateinit var sharedPreferences: SharedPreferences - private val snabble = Snabble.getInstance() - - private val projectLiveData = MutableLiveData() - private var nullableProject: Project? = null - - init { - application = snabble.application - - snabble.addOnMetadataUpdateListener(object : Snabble.OnMetadataUpdateListener { - override fun onMetaDataUpdated() { - if (!isInitialized) { - isInitialized = true - sharedPreferences = application.getSharedPreferences("snabble_ui_persistence", Context.MODE_PRIVATE) - } - - update() - } - }) - } - - fun update() { - nullableProject = snabble.projects.find { - it.id == sharedPreferences.getString("id", null) - } - } -} \ No newline at end of file diff --git a/ui/src/main/java/io/snabble/sdk/ui/UIPersistenceStore.kt b/ui/src/main/java/io/snabble/sdk/ui/UIPersistenceStore.kt new file mode 100644 index 0000000000..9048884a4e --- /dev/null +++ b/ui/src/main/java/io/snabble/sdk/ui/UIPersistenceStore.kt @@ -0,0 +1,38 @@ +package io.snabble.sdk.ui + +import android.annotation.SuppressLint +import android.app.Application +import android.content.Context +import android.content.SharedPreferences +import androidx.lifecycle.MutableLiveData +import io.snabble.sdk.Project +import io.snabble.sdk.Snabble +import java.util.concurrent.atomic.AtomicBoolean + +internal object UIPersistenceStore { + + private val snabble = Snabble.getInstance() + private var application = snabble.application + private val sharedPreferences: SharedPreferences = application.getSharedPreferences("snabble_ui_persistence", Context.MODE_PRIVATE) + + val project = MutableLiveData() + + init { + snabble.addOnMetadataUpdateListener(object : Snabble.OnMetadataUpdateListener { + override fun onMetaDataUpdated() { + update() + } + }) + } + + internal fun updateProject(p: Project?) { + project.postValue(p) + sharedPreferences.edit().putString("id", null).apply() + } + + private fun update() { + project.postValue(snabble.projects.find { + it.id == sharedPreferences.getString("id", null) + }) + } +} \ No newline at end of file From faa9b1fc606a5b910ab8f0c8b50e1fb0ce1c1c88 Mon Sep 17 00:00:00 2001 From: Alexander Junggeburth Date: Tue, 8 Feb 2022 16:40:58 +0100 Subject: [PATCH 06/30] fix crash --- .../io/snabble/sdk/sample/LoadingActivity.kt | 10 ++++++---- .../main/java/io/snabble/sdk/ui/SnabbleUI.kt | 6 +++--- ...PersistenceStore.kt => UIProjectManager.kt} | 18 ++++++++++++------ 3 files changed, 21 insertions(+), 13 deletions(-) rename ui/src/main/java/io/snabble/sdk/ui/{UIPersistenceStore.kt => UIProjectManager.kt} (67%) diff --git a/kotlin-sample/src/main/java/io/snabble/sdk/sample/LoadingActivity.kt b/kotlin-sample/src/main/java/io/snabble/sdk/sample/LoadingActivity.kt index fdd4ddd839..ea71d15316 100644 --- a/kotlin-sample/src/main/java/io/snabble/sdk/sample/LoadingActivity.kt +++ b/kotlin-sample/src/main/java/io/snabble/sdk/sample/LoadingActivity.kt @@ -4,6 +4,7 @@ import android.content.Intent import android.os.Bundle import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity +import io.snabble.sdk.Config import io.snabble.sdk.Snabble import io.snabble.sdk.ui.SnabbleUI @@ -16,10 +17,11 @@ class LoadingActivity : AppCompatActivity() { fun initSdk() { // config { - val config = Snabble.Config() - config.endpointBaseUrl = getString(R.string.endpoint) - config.secret = getString(R.string.secret) - config.appId = getString(R.string.app_id) + val config = Config( + endpointBaseUrl = getString(R.string.endpoint), + appId = getString(R.string.app_id), + secret = getString(R.string.secret), + ) //} Snabble.setDebugLoggingEnabled(BuildConfig.DEBUG) diff --git a/ui/src/main/java/io/snabble/sdk/ui/SnabbleUI.kt b/ui/src/main/java/io/snabble/sdk/ui/SnabbleUI.kt index 7c966db273..68f14e3e81 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/SnabbleUI.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/SnabbleUI.kt @@ -55,15 +55,15 @@ object SnabbleUI { @JvmStatic var project: Project get() { - return requireNotNull(UIPersistenceStore.project.value) + return requireNotNull(UIProjectManager.project.value) } set(value) { - UIPersistenceStore.updateProject(value) + UIProjectManager.updateProject(value) } @JvmStatic val projectAsLiveData: LiveData - get() = UIPersistenceStore.project + get() = UIProjectManager.project /** * Sets an action handler for custom implementations of events. diff --git a/ui/src/main/java/io/snabble/sdk/ui/UIPersistenceStore.kt b/ui/src/main/java/io/snabble/sdk/ui/UIProjectManager.kt similarity index 67% rename from ui/src/main/java/io/snabble/sdk/ui/UIPersistenceStore.kt rename to ui/src/main/java/io/snabble/sdk/ui/UIProjectManager.kt index 9048884a4e..bd083e0159 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/UIPersistenceStore.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/UIProjectManager.kt @@ -7,10 +7,10 @@ import android.content.SharedPreferences import androidx.lifecycle.MutableLiveData import io.snabble.sdk.Project import io.snabble.sdk.Snabble +import io.snabble.sdk.utils.Dispatch import java.util.concurrent.atomic.AtomicBoolean -internal object UIPersistenceStore { - +internal object UIProjectManager { private val snabble = Snabble.getInstance() private var application = snabble.application private val sharedPreferences: SharedPreferences = application.getSharedPreferences("snabble_ui_persistence", Context.MODE_PRIVATE) @@ -18,16 +18,22 @@ internal object UIPersistenceStore { val project = MutableLiveData() init { - snabble.addOnMetadataUpdateListener(object : Snabble.OnMetadataUpdateListener { - override fun onMetaDataUpdated() { + Dispatch.mainThread { + snabble.initializationState.observeForever { update() } - }) + + snabble.addOnMetadataUpdateListener(object : Snabble.OnMetadataUpdateListener { + override fun onMetaDataUpdated() { + update() + } + }) + } } internal fun updateProject(p: Project?) { project.postValue(p) - sharedPreferences.edit().putString("id", null).apply() + sharedPreferences.edit().putString("id", p?.id).apply() } private fun update() { From f0bfc67c210ddc6a0d944d6254ee21448ea473a7 Mon Sep 17 00:00:00 2001 From: Alexander Junggeburth Date: Thu, 10 Feb 2022 14:59:38 +0100 Subject: [PATCH 07/30] wait for initialization state in CheckoutActivity --- .../sdk/ui/checkout/CheckoutActivity.kt | 61 +++++++++++-------- 1 file changed, 34 insertions(+), 27 deletions(-) diff --git a/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutActivity.kt b/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutActivity.kt index 265459b3b3..c2aa45b70e 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutActivity.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutActivity.kt @@ -50,37 +50,44 @@ class CheckoutActivity : FragmentActivity() { navGraph = graphInflater.inflate(R.navigation.snabble_nav_checkout) navController = navHostFragment.navController - val projectId = intent.getStringExtra(ARG_PROJECT_ID) - if (projectId == null) { - finishWithError("No project id set") - return - } + Snabble.getInstance().initializationState.observe(this) { + when(it) { + InitializationState.INITIALIZED -> { + val projectId = intent.getStringExtra(ARG_PROJECT_ID) + if (projectId == null) { + finishWithError("No project id set") + return@observe + } - val project = Snabble.getInstance().getProjectById(projectId) - if (project == null) { - finishWithError("Project with id $projectId not found") - return - } + val project = Snabble.getInstance().getProjectById(projectId) + if (project == null) { + finishWithError("Project with id $projectId not found") + return@observe + } - val checkout = project.checkout - if (!checkout.state.isCheckoutState) { - finishWithError("Unexpected checkout state ${checkout.state.name}") - return - } - this.checkout = checkout - - val startDestinationId = getNavigationId() - if (startDestinationId == null) { - finish() - return - } else { - navGraph.startDestination = startDestinationId - } + val checkout = project.checkout + if (!checkout.state.isCheckoutState) { + finishWithError("Unexpected checkout state ${checkout.state.name}") + return@observe + } + this.checkout = checkout + + val startDestinationId = getNavigationId() + if (startDestinationId == null) { + finish() + return@observe + } else { + navGraph.startDestination = startDestinationId + } - navController.graph = navGraph + navController.graph = navGraph - checkout.checkoutState.observe(this) { - onStateChanged() + checkout.checkoutState.observe(this) { + onStateChanged() + } + } + else -> {} + } } } From 6a0794d3c10d82c5a26184f2e5df9834d4c51b54 Mon Sep 17 00:00:00 2001 From: Alexander Junggeburth Date: Thu, 10 Feb 2022 15:04:50 +0100 Subject: [PATCH 08/30] remove config persistence --- core/src/main/java/io/snabble/sdk/Config.kt | 23 +------------------- core/src/main/java/io/snabble/sdk/Snabble.kt | 2 -- 2 files changed, 1 insertion(+), 24 deletions(-) diff --git a/core/src/main/java/io/snabble/sdk/Config.kt b/core/src/main/java/io/snabble/sdk/Config.kt index a23322c64c..132d96e4b3 100644 --- a/core/src/main/java/io/snabble/sdk/Config.kt +++ b/core/src/main/java/io/snabble/sdk/Config.kt @@ -130,25 +130,4 @@ data class Config ( */ @JvmField var lastSeenThreshold: Long = TimeUnit.MINUTES.toMillis(15), -) { - companion object { - fun store(config: Config) { - try { - val snabble = Snabble.getInstance() - val file = File(snabble.internalStorageDirectory, "config.json") - IOUtils.write(GsonHolder.get().toJson(config), FileOutputStream(file), Charset.forName("UTF-8")) - } catch (ignored: Exception) {} - } - - fun load(): Config? { - try { - val snabble = Snabble.getInstance() - val file = File(snabble.internalStorageDirectory, "config.json") - val content = IOUtils.toString(FileInputStream(file), Charset.forName("UTF-8")) - return GsonHolder.get().fromJson(content, Config::class.java) - } catch (e: Exception) { - return null - } - } - } -} \ No newline at end of file +) \ No newline at end of file diff --git a/core/src/main/java/io/snabble/sdk/Snabble.kt b/core/src/main/java/io/snabble/sdk/Snabble.kt index 1ef11e6b18..4c79088f25 100644 --- a/core/src/main/java/io/snabble/sdk/Snabble.kt +++ b/core/src/main/java/io/snabble/sdk/Snabble.kt @@ -169,8 +169,6 @@ class Snabble private constructor() { internalStorageDirectory = File(application.filesDir, "snabble/" + config.appId + "/") internalStorageDirectory.mkdirs() - Config.store(config) - okHttpClient = OkHttpClientFactory.createOkHttpClient(app) userPreferences = UserPreferences(app) tokenRegistry = TokenRegistry(okHttpClient, userPreferences, config.appId, config.secret) From 2ed52a9b500363c4e619eb6660fce0eeb36db164 Mon Sep 17 00:00:00 2001 From: Alexander Junggeburth Date: Thu, 10 Feb 2022 16:43:49 +0100 Subject: [PATCH 09/30] Rename .java to .kt --- .../io/snabble/sdk/{UserPreferences.java => UserPreferences.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename core/src/main/java/io/snabble/sdk/{UserPreferences.java => UserPreferences.kt} (100%) diff --git a/core/src/main/java/io/snabble/sdk/UserPreferences.java b/core/src/main/java/io/snabble/sdk/UserPreferences.kt similarity index 100% rename from core/src/main/java/io/snabble/sdk/UserPreferences.java rename to core/src/main/java/io/snabble/sdk/UserPreferences.kt From ae8393b4d3736406503396927efaa0f63c18ea3c Mon Sep 17 00:00:00 2001 From: Alexander Junggeburth Date: Thu, 10 Feb 2022 16:43:49 +0100 Subject: [PATCH 10/30] persist shop, bugfixes and cleanup of initialization --- .../src/main/java/io/snabble/sdk/Project.java | 1 + core/src/main/java/io/snabble/sdk/Snabble.kt | 85 +++-- .../java/io/snabble/sdk/UserPreferences.kt | 331 +++++++++--------- .../src/main/java/io/snabble/testapp/App.java | 21 +- .../java/io/snabble/testapp/HomeFragment.java | 3 + ...rojectManager.kt => ProjectPersistence.kt} | 16 +- .../main/java/io/snabble/sdk/ui/SnabbleUI.kt | 11 +- 7 files changed, 232 insertions(+), 236 deletions(-) rename ui/src/main/java/io/snabble/sdk/ui/{UIProjectManager.kt => ProjectPersistence.kt} (77%) diff --git a/core/src/main/java/io/snabble/sdk/Project.java b/core/src/main/java/io/snabble/sdk/Project.java index d3cef66405..fde15035f5 100644 --- a/core/src/main/java/io/snabble/sdk/Project.java +++ b/core/src/main/java/io/snabble/sdk/Project.java @@ -496,6 +496,7 @@ public void setCheckedInShop(Shop checkedInShop) { if (!currentShopId.equals(newShopId)) { this.checkedInShop = checkedInShop; + snabble.getUserPreferences().setLastCheckedInShopId(checkedInShop.getId()); events.updateShop(checkedInShop); getShoppingCart().updatePrices(false); } diff --git a/core/src/main/java/io/snabble/sdk/Snabble.kt b/core/src/main/java/io/snabble/sdk/Snabble.kt index 4c79088f25..95cbd9f09a 100644 --- a/core/src/main/java/io/snabble/sdk/Snabble.kt +++ b/core/src/main/java/io/snabble/sdk/Snabble.kt @@ -192,45 +192,18 @@ class Snabble private constructor() { metadataDownloader = MetadataDownloader(okHttpClient, config.bundledMetadataAssetPath) if (config.bundledMetadataAssetPath != null) { - readMetadata() - setupCompletionListener.onReady() - initializationState.postValue(InitializationState.INITIALIZED) - isInitializing.set(false) - if (config.loadActiveShops) { - loadActiveShops() - } + dispatchOnReady(setupCompletionListener) } else { metadataDownloader.loadAsync(object : Downloader.Callback() { override fun onDataLoaded(wasStillValid: Boolean) { - readMetadata() - val appUser = userPreferences.appUser - if (appUser == null && projects.size > 0) { - val token = tokenRegistry.getToken(projects.get(0)) - if (token == null) { - setupCompletionListener.onError(Error.CONNECTION_TIMEOUT) - initializationState.postValue(InitializationState.ERROR) - isInitializing.set(false) - return - } - } - setupCompletionListener.onReady() - initializationState.postValue(InitializationState.INITIALIZED) - isInitializing.set(false) - if (config.loadActiveShops) { - loadActiveShops() - } + dispatchOnReady(setupCompletionListener) } override fun onError() { if (metadataDownloader.hasData()) { - readMetadata() - setupCompletionListener.onReady() - initializationState.postValue(InitializationState.INITIALIZED) - isInitializing.set(false) + dispatchOnReady(setupCompletionListener) } else { - setupCompletionListener.onError(Error.CONNECTION_TIMEOUT) - initializationState.postValue(InitializationState.ERROR) - isInitializing.set(false) + dispatchError(setupCompletionListener) } } }) @@ -240,6 +213,36 @@ class Snabble private constructor() { registerNetworkCallback(app) } + fun dispatchOnReady(setupCompletionListener: SetupCompletionListener) { + Dispatch.mainThread { + readMetadata() + val appUser = userPreferences.appUser + if (appUser == null && projects.size > 0) { + val token = tokenRegistry.getToken(projects.get(0)) + if (token == null) { + setupCompletionListener.onError(Error.CONNECTION_TIMEOUT) + initializationState.postValue(InitializationState.ERROR) + isInitializing.set(false) + return@mainThread + } + } + initializationState.postValue(InitializationState.INITIALIZED) + isInitializing.set(false) + setupCompletionListener.onReady() + if (config.loadActiveShops) { + loadActiveShops() + } + } + } + + fun dispatchError(setupCompletionListener: SetupCompletionListener) { + Dispatch.mainThread { + initializationState.postValue(InitializationState.ERROR) + setupCompletionListener.onError(Error.CONNECTION_TIMEOUT) + isInitializing.set(false) + } + } + /** * The blocking version of [.setup] * @@ -336,12 +339,28 @@ class Snabble private constructor() { GsonHolder.get().fromJson(jsonObject["terms"], TermsOfService::class.java) } } - + restoreCheckedInShop() paymentCredentialsStore.init(application, environment) users.postPendingConsents() checkInManager.update() } + private fun restoreCheckedInShop() { + val lastCheckedInShopId = userPreferences.lastCheckedInShopId + if (lastCheckedInShopId != null) { + for (project in projects) { + val shop = project.shops.find { + shop -> shop.id == lastCheckedInShopId + } + if (shop != null) { + Logger.d("Restoring last checked in shop " + shop?.id + ", " + shop?.name) + project.checkedInShop = shop + break; + } + } + } + } + private fun getUrl(jsonObject: JsonObject, urlName: String): String? { return try { absoluteUrl(jsonObject["links"].asJsonObject[urlName].asJsonObject["href"].asString) @@ -544,7 +563,7 @@ class Snabble private constructor() { /** * Unique identifier, different over device installations */ - val clientId: String + val clientId: String? get() = userPreferences.clientId interface SetupCompletionListener { diff --git a/core/src/main/java/io/snabble/sdk/UserPreferences.kt b/core/src/main/java/io/snabble/sdk/UserPreferences.kt index 3ea22a6b6f..b629e7a102 100644 --- a/core/src/main/java/io/snabble/sdk/UserPreferences.kt +++ b/core/src/main/java/io/snabble/sdk/UserPreferences.kt @@ -1,225 +1,208 @@ -package io.snabble.sdk; - -import android.content.Context; -import android.content.SharedPreferences; -import android.util.Base64; - -import java.io.UnsupportedEncodingException; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.List; -import java.util.Locale; -import java.util.UUID; -import java.util.concurrent.CopyOnWriteArrayList; - -import io.snabble.sdk.auth.AppUser; -import io.snabble.sdk.utils.Logger; - -public class UserPreferences { - enum ConsentStatus { +package io.snabble.sdk + +import android.annotation.SuppressLint +import android.content.Context +import io.snabble.sdk.Snabble.Companion.getInstance +import android.util.Base64 +import io.snabble.sdk.auth.AppUser +import io.snabble.sdk.utils.Logger +import java.io.UnsupportedEncodingException +import java.lang.Exception +import java.text.ParseException +import java.text.SimpleDateFormat +import java.util.* +import java.util.concurrent.CopyOnWriteArrayList + +class UserPreferences internal constructor(context: Context) { + enum class ConsentStatus { UNDECIDED, TRANSMITTING, TRANSMIT_FAILED, ACCEPTED } - private static final String SHARED_PREFERENCES_TAG = "snabble_prefs"; - private static final String SHARED_PREFERENCES_CLIENT_ID = "Client-ID"; - private static final String SHARED_PREFERENCES_APPUSER_ID = "AppUser-ID"; - private static final String SHARED_PREFERENCES_APPUSER_SECRET = "AppUser-Secret"; - private static final String SHARED_PREFERENCES_BIRTHDAY = "Birthday_v2"; - private static final String SHARED_PREFERENCES_CONSENT_STATUS = "ConsentStatus"; - private static final String SHARED_PREFERENCES_CONSENT_VERSION = "ConsentVersion"; - private static final String SHARED_PREFERENCES_USE_KEYGUARD = "useKeyguard"; + companion object { + private const val SHARED_PREFERENCES_TAG = "snabble_prefs" + private const val SHARED_PREFERENCES_CLIENT_ID = "Client-ID" + private const val SHARED_PREFERENCES_APPUSER_ID = "AppUser-ID" + private const val SHARED_PREFERENCES_APPUSER_SECRET = "AppUser-Secret" + private const val SHARED_PREFERENCES_BIRTHDAY = "Birthday_v2" + private const val SHARED_PREFERENCES_CONSENT_STATUS = "ConsentStatus" + private const val SHARED_PREFERENCES_CONSENT_VERSION = "ConsentVersion" + private const val SHARED_PREFERENCES_USE_KEYGUARD = "useKeyguard" + private const val SHARED_PREFERENCES_LAST_CHECKED_IN_SHOP = "lastShop" - private static final SimpleDateFormat BIRTHDAY_FORMAT = new SimpleDateFormat("yyyy/MM/dd"); - - private final SharedPreferences sharedPreferences; - private final List onNewAppUserListeners; - - UserPreferences(Context context) { - this.sharedPreferences = context.getSharedPreferences(SHARED_PREFERENCES_TAG, Context.MODE_PRIVATE); - this.onNewAppUserListeners = new CopyOnWriteArrayList<>(); - - if (getClientId() == null) { - generateClientId(); - } + @SuppressLint("SimpleDateFormat") + private val BIRTHDAY_FORMAT = SimpleDateFormat("yyyy/MM/dd") } - private void generateClientId() { - String clientId = UUID.randomUUID().toString() - .replace("-", "") - .toLowerCase(Locale.ROOT); + private val sharedPreferences = context.getSharedPreferences(SHARED_PREFERENCES_TAG, Context.MODE_PRIVATE) + private val onNewAppUserListeners: MutableList = CopyOnWriteArrayList() - setClientId(clientId); - } - - private String getEnvironmentKey() { - Environment environment = Snabble.getInstance().getEnvironment(); - if (environment != null) { - return environment.name(); - } else { - return "UNKNOWN"; + init { + if (clientId == null) { + generateClientId() } } - private String getAppUserIdKey() { - Config config = Snabble.getInstance().getConfig(); - return SHARED_PREFERENCES_APPUSER_ID + "_" + getEnvironmentKey() + config.appId; + private fun generateClientId() { + clientId = UUID.randomUUID().toString() + .replace("-", "") + .lowercase(Locale.ROOT) } - private String getAppUserIdSecret() { - Config config = Snabble.getInstance().getConfig(); - return SHARED_PREFERENCES_APPUSER_SECRET + "_" + getEnvironmentKey() + config.appId; - } - - public AppUser getAppUser() { - Config config = Snabble.getInstance().getConfig(); - if (config == null) { - return null; + private val environmentKey: String + get() { + val environment = getInstance().environment + return environment?.name ?: "UNKNOWN" } - String appUserId = sharedPreferences.getString(getAppUserIdKey(), null); - String appUserSecret = sharedPreferences.getString(getAppUserIdSecret(), null); - - if (appUserId != null && appUserSecret != null) { - return new AppUser(appUserId, appUserSecret); - } else { - return null; + private val appUserIdKey: String + get() { + val (_, appId) = getInstance().config + return SHARED_PREFERENCES_APPUSER_ID + "_" + environmentKey + appId } - } - public void setAppUser(AppUser appUser) { - if (appUser == null) { - sharedPreferences.edit() - .putString(getAppUserIdKey(), null) - .putString(getAppUserIdSecret(), null) - .apply(); - - Logger.d("Clearing app user"); - notifyOnNewAppUser(null); - return; + private val appUserIdSecret: String + get() { + val (_, appId) = getInstance().config + return SHARED_PREFERENCES_APPUSER_SECRET + "_" + environmentKey + appId } - if (appUser.id != null && appUser.secret != null) { - sharedPreferences.edit() - .putString(getAppUserIdKey(), appUser.id) - .putString(getAppUserIdSecret(), appUser.secret) - .apply(); + var appUser: AppUser? + get() { + val appUserId = sharedPreferences.getString(appUserIdKey, null) + val appUserSecret = sharedPreferences.getString(appUserIdSecret, null) - Logger.d("Setting app user to %s", appUser.id); - notifyOnNewAppUser(appUser); + return if (appUserId != null && appUserSecret != null) { + AppUser(appUserId, appUserSecret) + } else { + null + } } - } - - public String getAppUserBase64() { - AppUser appUser = getAppUser(); - if (appUser != null) { - String content = appUser.id + ":" + appUser.secret; - - try { - return Base64.encodeToString(content.getBytes("UTF-8"), Base64.NO_WRAP); - } catch (UnsupportedEncodingException e) { - return null; + set(appUser) { + if (appUser == null) { + sharedPreferences.edit() + .putString(appUserIdKey, null) + .putString(appUserIdSecret, null) + .apply() + Logger.d("Clearing app user") + notifyOnNewAppUser(null) + return + } + if (appUser.id != null && appUser.secret != null) { + sharedPreferences.edit() + .putString(appUserIdKey, appUser.id) + .putString(appUserIdSecret, appUser.secret) + .apply() + Logger.d("Setting app user to %s", appUser.id) + notifyOnNewAppUser(appUser) } } - return null; - } - - public void setAppUserBase64(String appUserBase64) { - if (appUserBase64 == null) { - setAppUser(null); - return; + var appUserBase64: String? + get() { + val appUser = appUser + if (appUser != null) { + val content = appUser.id + ":" + appUser.secret + return try { + Base64.encodeToString(content.toByteArray(charset("UTF-8")), Base64.NO_WRAP) + } catch (e: UnsupportedEncodingException) { + null + } + } + return null } - - String appUser = new String(Base64.decode(appUserBase64, Base64.DEFAULT)); - String[] split = appUser.split(":"); - - if (split.length == 2) { - String appUserId = split[0]; - String appUserSecret = split[1]; - - if (appUserId.length() > 0 && appUserSecret.length() > 0) { - setAppUser(new AppUser(appUserId, appUserSecret)); + set(appUserBase64) { + if (appUserBase64 == null) { + appUser = null + return + } + var appUserString = String(Base64.decode(appUserBase64, Base64.DEFAULT)) + val split = appUserString.split(":").toTypedArray() + if (split.size == 2) { + val appUserId = split[0] + val appUserSecret = split[1] + if (appUserId.length > 0 && appUserSecret.length > 0) { + appUser = AppUser(appUserId, appUserSecret) + } } } - } - - private void setClientId(String clientId) { - sharedPreferences.edit().putString(SHARED_PREFERENCES_CLIENT_ID, clientId).apply(); - } - public String getClientId() { - return sharedPreferences.getString(SHARED_PREFERENCES_CLIENT_ID, null); - } - - public void setBirthday(Date date) { - sharedPreferences.edit() - .putString(SHARED_PREFERENCES_BIRTHDAY, BIRTHDAY_FORMAT.format(date)) - .apply(); - } - - public Date getBirthday() { - String s = sharedPreferences.getString(SHARED_PREFERENCES_BIRTHDAY, null); - if (s == null) { - return null; + var clientId: String? + get() = + sharedPreferences.getString(SHARED_PREFERENCES_CLIENT_ID, null) + set(clientId) { + sharedPreferences.edit() + .putString(SHARED_PREFERENCES_CLIENT_ID, clientId) + .apply() } - try { - return BIRTHDAY_FORMAT.parse(s); - } catch (ParseException e) { - return null; + var lastCheckedInShopId: String? + get() = + sharedPreferences.getString(SHARED_PREFERENCES_LAST_CHECKED_IN_SHOP, null) + set(shopId) { + sharedPreferences.edit() + .putString(SHARED_PREFERENCES_LAST_CHECKED_IN_SHOP, shopId) + .apply() } - } - - public void setConsentStatus(ConsentStatus consent) { - sharedPreferences.edit() - .putString(SHARED_PREFERENCES_CONSENT_STATUS, consent.name()) - .apply(); - } - public ConsentStatus getConsentStatus() { - String s = sharedPreferences.getString(SHARED_PREFERENCES_BIRTHDAY, null); - if (s == null) { - return ConsentStatus.UNDECIDED; + var birthday: Date? + get() { + val s = sharedPreferences.getString(SHARED_PREFERENCES_BIRTHDAY, null) + ?: return null + return try { + BIRTHDAY_FORMAT.parse(s) + } catch (e: ParseException) { + null + } + } + set(date) { + sharedPreferences.edit() + .putString(SHARED_PREFERENCES_BIRTHDAY, BIRTHDAY_FORMAT.format(date)) + .apply() } - try { - return ConsentStatus.valueOf(s); - } catch (Exception e) { - return null; + var consentStatus: ConsentStatus + get() { + val s = sharedPreferences.getString(SHARED_PREFERENCES_BIRTHDAY, null) + ?: return ConsentStatus.UNDECIDED + return try { + ConsentStatus.valueOf(s) + } catch (e: Exception) { + return ConsentStatus.UNDECIDED + } } - } + set(consent) = + sharedPreferences.edit() + .putString(SHARED_PREFERENCES_CONSENT_STATUS, consent.name) + .apply() - public void setConsentVersion(String version) { - sharedPreferences.edit() + var consentVersion: String? + get() = sharedPreferences.getString(SHARED_PREFERENCES_CONSENT_VERSION, null) + set(version) { + sharedPreferences.edit() .putString(SHARED_PREFERENCES_CONSENT_VERSION, version) - .apply(); - } - - public String getConsentVersion() { - return sharedPreferences.getString(SHARED_PREFERENCES_CONSENT_VERSION, null); - } + .apply() + } - public void addOnNewAppUserListener(OnNewAppUserListener onNewAppUserListener) { + fun addOnNewAppUserListener(onNewAppUserListener: OnNewAppUserListener) { if (!onNewAppUserListeners.contains(onNewAppUserListener)) { - onNewAppUserListeners.add(onNewAppUserListener); + onNewAppUserListeners.add(onNewAppUserListener) } } - public void removeOnNewAppUserListener(OnNewAppUserListener onNewAppUserListener) { - onNewAppUserListeners.remove(onNewAppUserListener); + fun removeOnNewAppUserListener(onNewAppUserListener: OnNewAppUserListener) { + onNewAppUserListeners.remove(onNewAppUserListener) } - private void notifyOnNewAppUser(AppUser appUser) { - for (OnNewAppUserListener listener : onNewAppUserListeners) { - listener.onNewAppUser(appUser); + private fun notifyOnNewAppUser(appUser: AppUser?) { + for (listener in onNewAppUserListeners) { + listener.onNewAppUser(appUser) } } - public interface OnNewAppUserListener { - void onNewAppUser(AppUser appUser); + interface OnNewAppUserListener { + fun onNewAppUser(appUser: AppUser?) } } \ No newline at end of file diff --git a/java-sample/src/main/java/io/snabble/testapp/App.java b/java-sample/src/main/java/io/snabble/testapp/App.java index 3d30a5d132..9ba827b32f 100644 --- a/java-sample/src/main/java/io/snabble/testapp/App.java +++ b/java-sample/src/main/java/io/snabble/testapp/App.java @@ -47,26 +47,7 @@ public void onCreate() { snabble.setup(this, config, new Snabble.SetupCompletionListener() { @Override public void onReady() { - project = snabble.getProjects().get(0); - - // registers this project globally for use with ui components - SnabbleUI.setProject(project); - - // select the first shop for demo purposes - if (project.getShops().size() > 0) { - project.setCheckedInShop(project.getShops().get(0)); - } - - // you can update the local database asynchronously, you can still query - // the database while this is running - // project.getProductDatabase().update(); - - // optionally set a loyalty card id for identification, for demo purposes - // we invent one here - project.setCustomerCardId("2206467131013"); - - // optional: preload assets - project.getAssets().update(); + } @Override diff --git a/java-sample/src/main/java/io/snabble/testapp/HomeFragment.java b/java-sample/src/main/java/io/snabble/testapp/HomeFragment.java index 5bc327e24d..de18950cfa 100644 --- a/java-sample/src/main/java/io/snabble/testapp/HomeFragment.java +++ b/java-sample/src/main/java/io/snabble/testapp/HomeFragment.java @@ -3,6 +3,8 @@ import android.app.ActivityManager; import android.content.Context; import android.os.Bundle; +import android.util.Log; +import android.util.TimingLogger; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -134,6 +136,7 @@ public View getDropDownView(int position, @Nullable View convertView, @NonNull V for (int i=0; i() + val projectAsLiveData = MutableLiveData() + var project: Project? = null init { Dispatch.mainThread { @@ -31,14 +32,17 @@ internal object UIProjectManager { } } - internal fun updateProject(p: Project?) { - project.postValue(p) + internal fun post(p: Project?) { + project = p + projectAsLiveData.postValue(p) sharedPreferences.edit().putString("id", p?.id).apply() } private fun update() { - project.postValue(snabble.projects.find { + val p = snabble.projects.find { it.id == sharedPreferences.getString("id", null) - }) + } + project = p + projectAsLiveData.postValue(p) } } \ No newline at end of file diff --git a/ui/src/main/java/io/snabble/sdk/ui/SnabbleUI.kt b/ui/src/main/java/io/snabble/sdk/ui/SnabbleUI.kt index 68f14e3e81..66b8efe74c 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/SnabbleUI.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/SnabbleUI.kt @@ -55,15 +55,20 @@ object SnabbleUI { @JvmStatic var project: Project get() { - return requireNotNull(UIProjectManager.project.value) + return requireNotNull(ProjectPersistence.project) } set(value) { - UIProjectManager.updateProject(value) + ProjectPersistence.post(value) } @JvmStatic val projectAsLiveData: LiveData - get() = UIProjectManager.project + get() = ProjectPersistence.projectAsLiveData + + @JvmStatic + fun hasProject(): Boolean { + return ProjectPersistence.project != null + } /** * Sets an action handler for custom implementations of events. From 7c0364625891c5d8b7d8e0e40249f9e0b8554397 Mon Sep 17 00:00:00 2001 From: Alexander Junggeburth Date: Fri, 11 Feb 2022 12:35:37 +0100 Subject: [PATCH 11/30] cleanup and bugfixes --- build.gradle | 2 +- .../src/main/java/io/snabble/sdk/Project.java | 9 ++- core/src/main/java/io/snabble/sdk/Snabble.kt | 76 ++++++++++--------- .../io/snabble/sdk/checkin/CheckInManager.kt | 6 +- 4 files changed, 50 insertions(+), 43 deletions(-) diff --git a/build.gradle b/build.gradle index ddaa93d001..a85a9effc0 100644 --- a/build.gradle +++ b/build.gradle @@ -11,7 +11,7 @@ buildscript { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.dokka:dokka-gradle-plugin:$kotlin_version" classpath "org.jetbrains.dokka:dokka-base:$kotlin_version" - classpath 'com.android.tools.build:gradle:7.1.0' + classpath 'com.android.tools.build:gradle:7.1.1' classpath 'gradle.plugin.com.github.jlouns:gradle-cross-platform-exec-plugin:0.5.0' classpath 'gradle.plugin.gmazzo:sqlite-plugin:0.2' } diff --git a/core/src/main/java/io/snabble/sdk/Project.java b/core/src/main/java/io/snabble/sdk/Project.java index fde15035f5..3695f2e1bf 100644 --- a/core/src/main/java/io/snabble/sdk/Project.java +++ b/core/src/main/java/io/snabble/sdk/Project.java @@ -62,6 +62,7 @@ public class Project { private RoundingMode roundingMode; private BarcodeFormat[] supportedBarcodeFormats; + @Nullable private Shop checkedInShop; private CustomerCardInfo[] acceptedCustomerCardInfos; private CustomerCardInfo requiredCustomerCardInfo; @@ -490,13 +491,17 @@ public String getText(String key, String defaultValue) { * Sets the shop used for receiving store specific prices and identification in the * payment process. */ - public void setCheckedInShop(Shop checkedInShop) { + public void setCheckedInShop(@Nullable Shop checkedInShop) { String currentShopId = this.checkedInShop != null ? this.checkedInShop.getId() : ""; String newShopId = checkedInShop != null ? checkedInShop.getId() : ""; if (!currentShopId.equals(newShopId)) { this.checkedInShop = checkedInShop; - snabble.getUserPreferences().setLastCheckedInShopId(checkedInShop.getId()); + if (newShopId.equals("")) { + snabble.getUserPreferences().setLastCheckedInShopId(null); + } else { + snabble.getUserPreferences().setLastCheckedInShopId(newShopId); + } events.updateShop(checkedInShop); getShoppingCart().updatePrices(false); } diff --git a/core/src/main/java/io/snabble/sdk/Snabble.kt b/core/src/main/java/io/snabble/sdk/Snabble.kt index 95cbd9f09a..9cd34ef172 100644 --- a/core/src/main/java/io/snabble/sdk/Snabble.kt +++ b/core/src/main/java/io/snabble/sdk/Snabble.kt @@ -19,6 +19,7 @@ import android.app.Application.ActivityLifecycleCallbacks import android.content.Context import android.net.ConnectivityManager.NetworkCallback import android.net.Network +import android.os.Debug import android.util.Base64 import io.snabble.sdk.utils.* import java.io.ByteArrayInputStream @@ -123,7 +124,13 @@ class Snabble private constructor() { var initializationState = MutableLiveData(InitializationState.NONE) private set - private var currentActivity: WeakReference? = null + var currentActivity: WeakReference? = null + + /** + * Unique identifier, different over device installations + */ + val clientId: String? + get() = userPreferences.clientId private lateinit var metadataDownloader: MetadataDownloader @@ -155,11 +162,7 @@ class Snabble private constructor() { if (version == null) { version = try { val pInfo = app.packageManager.getPackageInfo(app.packageName, 0) - if (pInfo != null && pInfo.versionName != null) { - pInfo.versionName.toLowerCase(Locale.ROOT).replace(" ", "") - } else { - "1.0" - } + pInfo?.versionName?.lowercase(Locale.ROOT)?.replace(" ", "") ?: "1.0" } catch (e: PackageManager.NameNotFoundException) { "1.0" } @@ -213,31 +216,36 @@ class Snabble private constructor() { registerNetworkCallback(app) } - fun dispatchOnReady(setupCompletionListener: SetupCompletionListener) { - Dispatch.mainThread { + private fun dispatchOnReady(setupCompletionListener: SetupCompletionListener) { + Dispatch.background { readMetadata() val appUser = userPreferences.appUser - if (appUser == null && projects.size > 0) { - val token = tokenRegistry.getToken(projects.get(0)) + if (appUser == null && projects.isNotEmpty()) { + val token = tokenRegistry.getToken(projects[0]) if (token == null) { - setupCompletionListener.onError(Error.CONNECTION_TIMEOUT) - initializationState.postValue(InitializationState.ERROR) - isInitializing.set(false) - return@mainThread + Dispatch.mainThread { + setupCompletionListener.onError(Error.CONNECTION_TIMEOUT) + initializationState.value = InitializationState.ERROR + isInitializing.set(false) + } + return@background } } - initializationState.postValue(InitializationState.INITIALIZED) - isInitializing.set(false) - setupCompletionListener.onReady() - if (config.loadActiveShops) { - loadActiveShops() + + Dispatch.mainThread { + initializationState.value = InitializationState.INITIALIZED + isInitializing.set(false) + setupCompletionListener.onReady() + if (config.loadActiveShops) { + loadActiveShops() + } } } } - fun dispatchError(setupCompletionListener: SetupCompletionListener) { + private fun dispatchError(setupCompletionListener: SetupCompletionListener) { Dispatch.mainThread { - initializationState.postValue(InitializationState.ERROR) + initializationState.value = InitializationState.ERROR setupCompletionListener.onError(Error.CONNECTION_TIMEOUT) isInitializing.set(false) } @@ -353,7 +361,7 @@ class Snabble private constructor() { shop -> shop.id == lastCheckedInShopId } if (shop != null) { - Logger.d("Restoring last checked in shop " + shop?.id + ", " + shop?.name) + Logger.d("Restoring last checked in shop " + shop.id + ", " + shop.name) project.checkedInShop = shop break; } @@ -483,12 +491,6 @@ class Snabble private constructor() { } } - private fun notifyMetadataUpdated() { - for (listener in onMetaDataUpdateListeners) { - listener.onMetaDataUpdated() - } - } - private fun checkCartTimeouts() { for (project in projects) { project.shoppingCart.checkForTimeout() @@ -501,6 +503,12 @@ class Snabble private constructor() { } } + private fun notifyMetadataUpdated() { + for (listener in onMetaDataUpdateListeners) { + listener.onMetaDataUpdated() + } + } + /** * Adds a listener that gets called every time the metadata updates */ @@ -515,7 +523,7 @@ class Snabble private constructor() { onMetaDataUpdateListeners.remove(onMetaDataUpdateListener) } - interface OnMetadataUpdateListener { + fun interface OnMetadataUpdateListener { fun onMetaDataUpdated() } @@ -560,12 +568,6 @@ class Snabble private constructor() { } } - /** - * Unique identifier, different over device installations - */ - val clientId: String? - get() = userPreferences.clientId - interface SetupCompletionListener { fun onReady() fun onError(error: Error?) @@ -580,7 +582,9 @@ class Snabble private constructor() { } enum class Error { - UNSPECIFIED_ERROR, CONFIG_ERROR, CONNECTION_TIMEOUT, INVALID_METADATA_FORMAT, INTERNAL_STORAGE_FULL + UNSPECIFIED_ERROR, + CONFIG_ERROR, + CONNECTION_TIMEOUT } companion object { diff --git a/core/src/main/java/io/snabble/sdk/checkin/CheckInManager.kt b/core/src/main/java/io/snabble/sdk/checkin/CheckInManager.kt index 9657997019..4b9e7ef182 100644 --- a/core/src/main/java/io/snabble/sdk/checkin/CheckInManager.kt +++ b/core/src/main/java/io/snabble/sdk/checkin/CheckInManager.kt @@ -108,10 +108,8 @@ class CheckInManager(val snabble: Snabble, update() } - private val metadataListener = object : Snabble.OnMetadataUpdateListener { - override fun onMetaDataUpdated() { - update() - } + private val metadataListener = Snabble.OnMetadataUpdateListener { + update() } fun update() { From 8ae11826d69d84fcf9e86725ca36d6017532ce41 Mon Sep 17 00:00:00 2001 From: Alexander Junggeburth Date: Fri, 11 Feb 2022 12:47:37 +0100 Subject: [PATCH 12/30] only log keyguard error when it actually removed keys --- core/src/main/java/io/snabble/sdk/Snabble.kt | 2 +- .../java/io/snabble/sdk/payment/PaymentCredentialsStore.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/io/snabble/sdk/Snabble.kt b/core/src/main/java/io/snabble/sdk/Snabble.kt index 9cd34ef172..4f5029031d 100644 --- a/core/src/main/java/io/snabble/sdk/Snabble.kt +++ b/core/src/main/java/io/snabble/sdk/Snabble.kt @@ -461,7 +461,7 @@ class Snabble private constructor() { val endpointBaseUrl: String? get() = config.endpointBaseUrl - fun getProjectById(projectId: String): Project? { + fun getProjectById(projectId: String?): Project? { for (project in projects) { if (project.id == projectId) { return project diff --git a/core/src/main/java/io/snabble/sdk/payment/PaymentCredentialsStore.java b/core/src/main/java/io/snabble/sdk/payment/PaymentCredentialsStore.java index d650db704e..8fba0e53f8 100644 --- a/core/src/main/java/io/snabble/sdk/payment/PaymentCredentialsStore.java +++ b/core/src/main/java/io/snabble/sdk/payment/PaymentCredentialsStore.java @@ -80,7 +80,6 @@ private void ensureKeyStoreIsAccessible() { if (!id.equals(data.id)) { data.id = keyStoreCipher.id(); data.isKeyguarded = true; - Logger.errorEvent("Removing payment credentials, because key store id differs"); removeInvalidCredentials(); } } @@ -163,6 +162,8 @@ public synchronized void removeInvalidCredentials() { return; } + Logger.errorEvent("Removing payment credentials, because key store id differs"); + List removals = new ArrayList<>(); for (PaymentCredentials credentials : data.credentialsList) { if (!credentials.canBypassKeyStore()) { From 9e5c8cce87843ce6b975496b145d6fd16bf28d5c Mon Sep 17 00:00:00 2001 From: Alexander Junggeburth Date: Fri, 11 Feb 2022 15:34:13 +0100 Subject: [PATCH 13/30] fix self scanning view --- .../main/java/io/snabble/sdk/ui/BaseFragment.kt | 6 +++++- .../sdk/ui/scanner/SelfScanningFragment.kt | 16 +++++++++------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/ui/src/main/java/io/snabble/sdk/ui/BaseFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/BaseFragment.kt index f6518b7d2a..dee38a066d 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/BaseFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/BaseFragment.kt @@ -8,7 +8,6 @@ import android.widget.ProgressBar import android.widget.TextView import androidx.core.view.isVisible import androidx.fragment.app.Fragment -import io.snabble.sdk.Config import io.snabble.sdk.InitializationState import io.snabble.sdk.Snabble @@ -17,6 +16,8 @@ abstract class BaseFragment : Fragment() { private lateinit var progress: ProgressBar private lateinit var fragmentContainer: ViewGroup + var isReady = false + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -61,10 +62,13 @@ abstract class BaseFragment : Fragment() { onCreateViewInternal(layoutInflater, fragmentContainer, savedInstanceState) if (fragmentView != null) { fragmentContainer.addView(fragmentView) + isReady = true } } } else { + isReady = false fragmentContainer.removeAllViews() + sdkNotInitialized.isVisible = true } } } diff --git a/ui/src/main/java/io/snabble/sdk/ui/scanner/SelfScanningFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/scanner/SelfScanningFragment.kt index 4b76b28cb0..3c84766d27 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/scanner/SelfScanningFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/scanner/SelfScanningFragment.kt @@ -13,13 +13,14 @@ import androidx.core.content.ContextCompat import androidx.core.content.res.ResourcesCompat import androidx.fragment.app.Fragment import io.snabble.sdk.codes.ScannedCode +import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R import io.snabble.sdk.ui.SnabbleUI import io.snabble.sdk.ui.payment.PayoneInputView import io.snabble.sdk.ui.search.SearchHelper import io.snabble.sdk.ui.utils.setOneShotClickListener -open class SelfScanningFragment : Fragment() { +open class SelfScanningFragment : BaseFragment() { companion object { const val ARG_SHOW_PRODUCT_CODE = "showProductCode" } @@ -35,18 +36,15 @@ open class SelfScanningFragment : Fragment() { val hasSelfScanningView get() = selfScanningView != null - override fun onCreateView( + override fun onCreateViewInternal( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { setHasOptionsMenu(false) - return inflater.inflate(R.layout.snabble_fragment_selfscanning, container, false) - } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - rootView = view as ViewGroup + rootView = inflater.inflate(R.layout.snabble_fragment_selfscanning, container, false) as ViewGroup + selfScanningView = null permissionContainer = rootView.findViewById(R.id.permission_denied_container) askForPermission = rootView.findViewById(R.id.open_settings) @@ -54,6 +52,8 @@ open class SelfScanningFragment : Fragment() { if (isPermissionGranted) { createSelfScanningView() } + + return rootView } override fun onStart() { @@ -78,6 +78,8 @@ open class SelfScanningFragment : Fragment() { } private fun createSelfScanningView() { + if (!isReady) return + if (selfScanningView == null) { selfScanningView = SelfScanningView(context).apply { setAllowShowingHints(allowShowingHints) From d1d4136f9cd16876e13ed80ef31dd3ed8e42f492 Mon Sep 17 00:00:00 2001 From: Alexander Junggeburth Date: Mon, 14 Feb 2022 17:08:16 +0100 Subject: [PATCH 14/30] use object for Snabble and fix tests --- core/build.gradle | 3 +- .../src/main/java/io/snabble/sdk/Project.java | 4 - core/src/main/java/io/snabble/sdk/Snabble.kt | 92 ++++++++----------- .../java/io/snabble/sdk/UserPreferences.kt | 7 +- .../java/io/snabble/sdk/CheckInManagerTest.kt | 2 +- .../sdk/EncodedCodesGeneratorTest.java | 3 +- .../io/snabble/sdk/ProductDatabaseTest.java | 5 +- .../java/io/snabble/sdk/SnabbleSdkTest.java | 23 ++++- gradle/wrapper/gradle-wrapper.properties | 2 +- .../java/io/snabble/sdk/utils/Dispatch.java | 15 +++ .../snabble/sdk/utils/StringDownloader.java | 5 +- 11 files changed, 86 insertions(+), 75 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index fa42b1fa34..d28d95f314 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -60,7 +60,6 @@ dependencies { implementation 'com.google.android.gms:play-services-wallet:19.1.0' implementation 'androidx.appcompat:appcompat:1.4.1' implementation 'androidx.biometric:biometric:1.2.0-alpha04' - implementation "androidx.startup:startup-runtime:1.1.0" api "com.squareup.okhttp3:okhttp:${project.okhttpVersion}" implementation "com.squareup.okhttp3:logging-interceptor:${project.okhttpVersion}" @@ -68,7 +67,7 @@ dependencies { api 'com.google.code.gson:gson:2.8.9' testImplementation 'junit:junit:4.13.2' - testImplementation 'org.robolectric:robolectric:4.6.1' + testImplementation 'org.robolectric:robolectric:4.7.3' testImplementation "com.squareup.okhttp3:mockwebserver:${project.okhttpVersion}" androidTestImplementation 'androidx.test:rules:1.4.0' diff --git a/core/src/main/java/io/snabble/sdk/Project.java b/core/src/main/java/io/snabble/sdk/Project.java index 3695f2e1bf..5f0f535ba3 100644 --- a/core/src/main/java/io/snabble/sdk/Project.java +++ b/core/src/main/java/io/snabble/sdk/Project.java @@ -96,13 +96,10 @@ public class Project { .addInterceptor(new SnabbleAuthorizationInterceptor(this)) .addInterceptor(new AcceptedLanguageInterceptor()) .build(); - parse(jsonObject); - internalStorageDirectory = new File(snabble.getInternalStorageDirectory(), id + "/"); boolean generateSearchIndex = snabble.getConfig().generateSearchIndex; - productDatabase = new ProductDatabase(this, id + ".sqlite3", generateSearchIndex); shoppingCartStorage = new ShoppingCartStorage(this); checkout = new Checkout(this); @@ -321,7 +318,6 @@ void parse(JsonObject jsonObject) { coupons.setInternalProjectCoupons(couponList); } coupons.update(); - notifyUpdate(); } diff --git a/core/src/main/java/io/snabble/sdk/Snabble.kt b/core/src/main/java/io/snabble/sdk/Snabble.kt index 4f5029031d..c4450ea9ee 100644 --- a/core/src/main/java/io/snabble/sdk/Snabble.kt +++ b/core/src/main/java/io/snabble/sdk/Snabble.kt @@ -1,32 +1,28 @@ package io.snabble.sdk -import io.snabble.sdk.auth.TokenRegistry -import io.snabble.sdk.payment.PaymentCredentialsStore -import io.snabble.sdk.checkin.CheckInLocationManager -import io.snabble.sdk.checkin.CheckInManager -import okhttp3.OkHttpClient import android.app.Activity import android.app.Application -import androidx.lifecycle.MutableLiveData -import android.content.pm.PackageManager -import android.net.ConnectivityManager -import android.net.NetworkRequest -import android.net.NetworkCapabilities -import androidx.lifecycle.LiveData -import com.google.gson.JsonObject -import kotlin.Throws import android.app.Application.ActivityLifecycleCallbacks import android.content.Context +import android.content.pm.PackageManager +import android.net.ConnectivityManager import android.net.ConnectivityManager.NetworkCallback import android.net.Network -import android.os.Debug +import android.net.NetworkCapabilities +import android.net.NetworkRequest import android.util.Base64 +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import com.google.gson.JsonObject +import io.snabble.sdk.auth.TokenRegistry +import io.snabble.sdk.checkin.CheckInLocationManager +import io.snabble.sdk.checkin.CheckInManager +import io.snabble.sdk.payment.PaymentCredentialsStore import io.snabble.sdk.utils.* +import okhttp3.OkHttpClient import java.io.ByteArrayInputStream import java.io.File import java.io.InputStream -import java.lang.Exception -import java.lang.IllegalArgumentException import java.lang.ref.WeakReference import java.security.cert.CertificateException import java.security.cert.CertificateFactory @@ -36,7 +32,16 @@ import java.util.concurrent.CopyOnWriteArrayList import java.util.concurrent.CountDownLatch import java.util.concurrent.atomic.AtomicBoolean -class Snabble private constructor() { +object Snabble { + @JvmStatic + fun getInstance() : Snabble { + return this + } + + @JvmStatic + val version: String + get() = BuildConfig.VERSION_NAME + lateinit var okHttpClient: OkHttpClient private set @@ -144,7 +149,7 @@ class Snabble private constructor() { } isInitializing.set(true) - initializationState.postValue(InitializationState.INITIALIZING) + initializationState.value = InitializationState.INITIALIZING application = app this.config = config @@ -223,31 +228,33 @@ class Snabble private constructor() { if (appUser == null && projects.isNotEmpty()) { val token = tokenRegistry.getToken(projects[0]) if (token == null) { + isInitializing.set(false) + initializationState.postValue(InitializationState.ERROR) + Dispatch.mainThread { setupCompletionListener.onError(Error.CONNECTION_TIMEOUT) - initializationState.value = InitializationState.ERROR - isInitializing.set(false) } return@background } } + isInitializing.set(false) + initializationState.postValue(InitializationState.INITIALIZED) Dispatch.mainThread { - initializationState.value = InitializationState.INITIALIZED - isInitializing.set(false) setupCompletionListener.onReady() - if (config.loadActiveShops) { - loadActiveShops() - } + } + if (config.loadActiveShops) { + loadActiveShops() } } } private fun dispatchError(setupCompletionListener: SetupCompletionListener) { + isInitializing.set(false) + initializationState.postValue(InitializationState.ERROR) + Dispatch.mainThread { - initializationState.value = InitializationState.ERROR setupCompletionListener.onError(Error.CONNECTION_TIMEOUT) - isInitializing.set(false) } } @@ -326,19 +333,15 @@ class Snabble private constructor() { telecashSecretUrl = getUrl(jsonObject, "telecashSecret") telecashPreAuthUrl = getUrl(jsonObject, "telecashPreauth") paydirektAuthUrl = getUrl(jsonObject, "paydirektCustomerAuthorization") - if (jsonObject.has("brands")) { parseBrands(jsonObject) } - if (jsonObject.has("projects")) { parseProjects(jsonObject) } - if (jsonObject.has("gatewayCertificates")) { parsePaymentCertificates(jsonObject) } - receiptsUrl = getUrl(jsonObject, "appUserOrders") usersUrl = getUrl(jsonObject, "appUser") consentUrl = getUrl(jsonObject, "consents") @@ -408,7 +411,6 @@ class Snabble private constructor() { break } } - // if it does not exist, add it if (!updated) { try { @@ -421,7 +423,6 @@ class Snabble private constructor() { } } } - projects = Collections.unmodifiableList(newProjects) } @@ -587,24 +588,11 @@ class Snabble private constructor() { CONNECTION_TIMEOUT } - companion object { - private val _instance = Snabble() - - @JvmStatic - fun getInstance() : Snabble { - return _instance - } - - @JvmStatic - val version: String - get() = BuildConfig.VERSION_NAME - - /** - * Enables debug logging. - */ - @JvmStatic - fun setDebugLoggingEnabled(enabled: Boolean) { - Logger.setEnabled(enabled) - } + /** + * Enables debug logging. + */ + @JvmStatic + fun setDebugLoggingEnabled(enabled: Boolean) { + Logger.setEnabled(enabled) } } \ No newline at end of file diff --git a/core/src/main/java/io/snabble/sdk/UserPreferences.kt b/core/src/main/java/io/snabble/sdk/UserPreferences.kt index b629e7a102..dc1386d6f8 100644 --- a/core/src/main/java/io/snabble/sdk/UserPreferences.kt +++ b/core/src/main/java/io/snabble/sdk/UserPreferences.kt @@ -2,7 +2,6 @@ package io.snabble.sdk import android.annotation.SuppressLint import android.content.Context -import io.snabble.sdk.Snabble.Companion.getInstance import android.util.Base64 import io.snabble.sdk.auth.AppUser import io.snabble.sdk.utils.Logger @@ -53,19 +52,19 @@ class UserPreferences internal constructor(context: Context) { private val environmentKey: String get() { - val environment = getInstance().environment + val environment = Snabble.environment return environment?.name ?: "UNKNOWN" } private val appUserIdKey: String get() { - val (_, appId) = getInstance().config + val (_, appId) = Snabble.config return SHARED_PREFERENCES_APPUSER_ID + "_" + environmentKey + appId } private val appUserIdSecret: String get() { - val (_, appId) = getInstance().config + val (_, appId) = Snabble.config return SHARED_PREFERENCES_APPUSER_SECRET + "_" + environmentKey + appId } diff --git a/core/src/test/java/io/snabble/sdk/CheckInManagerTest.kt b/core/src/test/java/io/snabble/sdk/CheckInManagerTest.kt index 1b5f2e6cd6..b687b928c1 100644 --- a/core/src/test/java/io/snabble/sdk/CheckInManagerTest.kt +++ b/core/src/test/java/io/snabble/sdk/CheckInManagerTest.kt @@ -33,7 +33,7 @@ class CheckInManagerTest : SnabbleSdkTest() { time = System.currentTimeMillis() } - override fun onApplyConfig(config: Snabble.Config) { + override fun onApplyConfig(config: Config) { super.onApplyConfig(config) config.checkInRadius = 500.0f; diff --git a/core/src/test/java/io/snabble/sdk/EncodedCodesGeneratorTest.java b/core/src/test/java/io/snabble/sdk/EncodedCodesGeneratorTest.java index 17119a701f..df182ae6a6 100644 --- a/core/src/test/java/io/snabble/sdk/EncodedCodesGeneratorTest.java +++ b/core/src/test/java/io/snabble/sdk/EncodedCodesGeneratorTest.java @@ -8,6 +8,7 @@ import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -467,7 +468,7 @@ public void testFinalCodeWithManualDiscountsAndFinalCode() { @Test public void testTransmissionTemplates() throws IOException, Snabble.SnabbleException { String[] sql = loadSql("transmission_template").split("\n"); - withDb("test_1_25.sqlite3", false, sql); + withDb("test_1_25.sqlite3", false, Arrays.asList(sql)); EncodedCodesOptions options = new EncodedCodesOptions.Builder(project) .prefix("") diff --git a/core/src/test/java/io/snabble/sdk/ProductDatabaseTest.java b/core/src/test/java/io/snabble/sdk/ProductDatabaseTest.java index 639ee68fee..ce72d46453 100644 --- a/core/src/test/java/io/snabble/sdk/ProductDatabaseTest.java +++ b/core/src/test/java/io/snabble/sdk/ProductDatabaseTest.java @@ -17,6 +17,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.util.Arrays; import java.util.HashSet; import java.util.Set; import java.util.concurrent.CountDownLatch; @@ -42,7 +43,6 @@ public void testAllPromotionsQuery() { @Test public void testTextSearchNoFTS() throws IOException, Snabble.SnabbleException { withDb("test_1_25.sqlite3", true, null); - ProductDatabase productDatabase = project.getProductDatabase(); Cursor cursor = productDatabase.searchByFoldedName("gold", null); cursor.moveToFirst(); @@ -50,7 +50,6 @@ public void testTextSearchNoFTS() throws IOException, Snabble.SnabbleException { assertEquals(product.getSku(), "31"); assertEquals(product.getName(), "Goldbären 200g"); cursor.close(); - cursor = productDatabase.searchByFoldedName("foo", null); assertEquals(0, cursor.getCount()); cursor.close(); @@ -447,7 +446,7 @@ public void testMultiplePricingCategories() throws IOException, Snabble.SnabbleE @Test public void testTransmissionTemplates() throws IOException, Snabble.SnabbleException { String[] sql = loadSql("transmission_template").split("\n"); - withDb("test_1_25.sqlite3", false, sql); + withDb("test_1_25.sqlite3", false, Arrays.asList(sql)); ProductDatabase productDatabase = project.getProductDatabase(); Product product = productDatabase.findBySku("34-tt"); diff --git a/core/src/test/java/io/snabble/sdk/SnabbleSdkTest.java b/core/src/test/java/io/snabble/sdk/SnabbleSdkTest.java index 0bad826c4b..33dfe92b63 100644 --- a/core/src/test/java/io/snabble/sdk/SnabbleSdkTest.java +++ b/core/src/test/java/io/snabble/sdk/SnabbleSdkTest.java @@ -2,6 +2,8 @@ import android.app.Application; import android.content.Context; +import android.os.Handler; +import android.os.Looper; import android.os.StrictMode; import androidx.annotation.NonNull; @@ -15,18 +17,24 @@ import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; +import org.robolectric.Robolectric; import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.LooperMode; +import org.robolectric.shadows.ShadowLooper; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import io.snabble.sdk.auth.AppUser; import io.snabble.sdk.auth.AppUserAndToken; import io.snabble.sdk.auth.Token; +import io.snabble.sdk.utils.Dispatch; import io.snabble.sdk.utils.GsonHolder; import okhttp3.mockwebserver.Dispatcher; import okhttp3.mockwebserver.MockResponse; @@ -35,6 +43,7 @@ import okio.Buffer; @RunWith(RobolectricTestRunner.class) +@LooperMode(LooperMode.Mode.LEGACY) public class SnabbleSdkTest { protected Project project; protected Context context; @@ -135,6 +144,8 @@ public static void closeMockWebServer() throws IOException { @Before public void setupSdk() throws Snabble.SnabbleException, IOException { + Dispatch.setMainThreadHandler(Runnable::run); + // Disable close guard warnings StrictMode.enableDefaults(); @@ -146,7 +157,7 @@ public void withDb(String testDbName) throws IOException, Snabble.SnabbleExcepti withDb(testDbName, false, null); } - public void withDb(String testDbName, boolean generateSearchIndex, String[] initialSQL) throws IOException, Snabble.SnabbleException { + public void withDb(String testDbName, boolean generateSearchIndex, List initialSQL) throws IOException, Snabble.SnabbleException { StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); StrictMode.setThreadPolicy(policy); @@ -154,18 +165,20 @@ public void withDb(String testDbName, boolean generateSearchIndex, String[] init prepareUpdateDb(testDbName); - final Snabble.Config config = new Snabble.Config(); + final Config config = new Config(); config.appId = "test"; config.endpointBaseUrl = "http://" + mockWebServer.getHostName() + ":" + mockWebServer.getPort(); config.secret = "asdf"; config.generateSearchIndex = generateSearchIndex; - config.initialSQL = initialSQL; + + if (initialSQL != null) { + config.initialSQL = initialSQL; + } onApplyConfig(config); Snabble snabble = Snabble.getInstance(); snabble.setupBlocking((Application) context.getApplicationContext(), config); - project = snabble.getProjects().get(0); project.getShoppingCart().clear(); project.setCheckedInShop(null); @@ -190,7 +203,7 @@ public void error() { } } - public void onApplyConfig(@NonNull Snabble.Config config) { + public void onApplyConfig(@NonNull Config config) { } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 7dcd28361b..25335cfa67 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip diff --git a/utils/src/main/java/io/snabble/sdk/utils/Dispatch.java b/utils/src/main/java/io/snabble/sdk/utils/Dispatch.java index e84771b04a..d436e2dcb3 100644 --- a/utils/src/main/java/io/snabble/sdk/utils/Dispatch.java +++ b/utils/src/main/java/io/snabble/sdk/utils/Dispatch.java @@ -13,6 +13,16 @@ public class Dispatch { private static final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(0); private static final ScheduledExecutorService ioScheduler = Executors.newSingleThreadScheduledExecutor(); + private static MainThreadHandler mainThreadHandler; + + public interface MainThreadHandler { + void handle(Runnable runnable); + } + + public static void setMainThreadHandler(MainThreadHandler runnable) { + Dispatch.mainThreadHandler = runnable; + } + public static Future background(Runnable runnable) { return executorService.submit(runnable); } @@ -29,6 +39,11 @@ public static void mainThread(Runnable runnable) { if (Looper.myLooper() == Looper.getMainLooper()) { runnable.run(); } else { + if (mainThreadHandler != null) { + mainThreadHandler.handle(runnable); + return; + } + handler.post(runnable); } } diff --git a/utils/src/main/java/io/snabble/sdk/utils/StringDownloader.java b/utils/src/main/java/io/snabble/sdk/utils/StringDownloader.java index c50310518e..9f9bd037df 100644 --- a/utils/src/main/java/io/snabble/sdk/utils/StringDownloader.java +++ b/utils/src/main/java/io/snabble/sdk/utils/StringDownloader.java @@ -1,5 +1,6 @@ package io.snabble.sdk.utils; +import android.app.Application; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; @@ -21,7 +22,7 @@ public abstract class StringDownloader extends Downloader { private File storageFile = null; private String assetPath; - private Context context; + private Application context; public StringDownloader(OkHttpClient okHttpClient) { super(okHttpClient); @@ -33,7 +34,7 @@ public StringDownloader(OkHttpClient okHttpClient) { * Copies the bundled data from the asset folder into the app internal files folder and * uses the app files data unless the app gets updated. */ - public void setBundledData(Context context, String assetPath, File storageFile) { + public void setBundledData(Application context, String assetPath, File storageFile) { this.context = context; this.storageFile = storageFile; this.assetPath = assetPath; From be1c4b160d7fdd606d8e2d93e88285b06812d72a Mon Sep 17 00:00:00 2001 From: Alexander Junggeburth Date: Mon, 14 Feb 2022 17:36:25 +0100 Subject: [PATCH 15/30] more refactoring and cleanup --- .../java/io/snabble/sdk/InitializationState.kt | 1 - core/src/main/java/io/snabble/sdk/Snabble.kt | 2 +- .../src/main/java/io/snabble/testapp/App.java | 2 +- .../java/io/snabble/testapp/HomeFragment.java | 4 +++- .../main/java/io/snabble/sdk/ui/BaseFragment.kt | 16 ++++------------ .../snabble/sdk/ui/cart/ShoppingCartFragment.kt | 2 +- .../ui/checkout/CheckoutCustomerCardFragment.kt | 2 +- .../sdk/ui/checkout/CheckoutOfflineFragment.kt | 2 +- .../sdk/ui/checkout/CheckoutPOSFragment.kt | 2 +- .../sdk/ui/checkout/PaymentStatusFragment.kt | 2 +- .../RoutingTargetGatekeeperFragment.kt | 2 +- .../RoutingTargetSupervisorFragment.kt | 2 +- .../ui/payment/AgeVerificationInputFragment.kt | 2 +- .../sdk/ui/payment/CreditCardInputFragment.kt | 2 +- .../sdk/ui/payment/PaydirektInputFragment.kt | 2 +- .../ui/payment/PaymentCredentialsListFragment.kt | 2 +- .../sdk/ui/payment/PaymentOptionsFragment.kt | 2 +- .../sdk/ui/payment/PayoneInputFragment.kt | 2 +- .../ui/payment/ProjectPaymentOptionsFragment.kt | 2 +- .../sdk/ui/payment/SEPACardInputFragment.kt | 2 +- .../sdk/ui/scanner/SelfScanningFragment.kt | 2 +- .../sdk/ui/search/ProductSearchFragment.kt | 2 +- ui/src/main/res/layout/snabble_fragment_base.xml | 7 +------ 23 files changed, 27 insertions(+), 39 deletions(-) diff --git a/core/src/main/java/io/snabble/sdk/InitializationState.kt b/core/src/main/java/io/snabble/sdk/InitializationState.kt index 6e0fb89072..e2d4df267b 100644 --- a/core/src/main/java/io/snabble/sdk/InitializationState.kt +++ b/core/src/main/java/io/snabble/sdk/InitializationState.kt @@ -1,7 +1,6 @@ package io.snabble.sdk enum class InitializationState { - NONE, INITIALIZING, INITIALIZED, ERROR, diff --git a/core/src/main/java/io/snabble/sdk/Snabble.kt b/core/src/main/java/io/snabble/sdk/Snabble.kt index c4450ea9ee..7cac6d677b 100644 --- a/core/src/main/java/io/snabble/sdk/Snabble.kt +++ b/core/src/main/java/io/snabble/sdk/Snabble.kt @@ -126,7 +126,7 @@ object Snabble { var createAppUserUrl: String? = null private set - var initializationState = MutableLiveData(InitializationState.NONE) + var initializationState = MutableLiveData() private set var currentActivity: WeakReference? = null diff --git a/java-sample/src/main/java/io/snabble/testapp/App.java b/java-sample/src/main/java/io/snabble/testapp/App.java index 9ba827b32f..c1b63fb817 100644 --- a/java-sample/src/main/java/io/snabble/testapp/App.java +++ b/java-sample/src/main/java/io/snabble/testapp/App.java @@ -47,7 +47,7 @@ public void onCreate() { snabble.setup(this, config, new Snabble.SetupCompletionListener() { @Override public void onReady() { - + SnabbleUI.setProject(snabble.getProjects().get(0)); } @Override diff --git a/java-sample/src/main/java/io/snabble/testapp/HomeFragment.java b/java-sample/src/main/java/io/snabble/testapp/HomeFragment.java index de18950cfa..b03727b63c 100644 --- a/java-sample/src/main/java/io/snabble/testapp/HomeFragment.java +++ b/java-sample/src/main/java/io/snabble/testapp/HomeFragment.java @@ -30,7 +30,9 @@ public class HomeFragment extends BaseFragment { @Nullable @Override - public View onCreateViewInternal(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + public View onCreateActualView(@NonNull LayoutInflater inflater, + @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { View v = inflater.inflate(R.layout.fragment_home, container, false); v.findViewById(R.id.scanner).setOnClickListener(btn -> ((BaseActivity)getActivity()).showScanner()); diff --git a/ui/src/main/java/io/snabble/sdk/ui/BaseFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/BaseFragment.kt index dee38a066d..3b1dc65efc 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/BaseFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/BaseFragment.kt @@ -4,7 +4,6 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.ProgressBar import android.widget.TextView import androidx.core.view.isVisible import androidx.fragment.app.Fragment @@ -13,7 +12,6 @@ import io.snabble.sdk.Snabble abstract class BaseFragment : Fragment() { private lateinit var sdkNotInitialized: TextView - private lateinit var progress: ProgressBar private lateinit var fragmentContainer: ViewGroup var isReady = false @@ -28,14 +26,10 @@ abstract class BaseFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { fragmentContainer = view.findViewById(R.id.fragment_container) - progress = view.findViewById(R.id.progress) sdkNotInitialized = view.findViewById(R.id.sdk_not_initialized) - Snabble.getInstance().initializationState.observe(viewLifecycleOwner) { + Snabble.initializationState.observe(viewLifecycleOwner) { when(it) { - InitializationState.NONE -> { - waitForProjectAndAdd(savedInstanceState) - } InitializationState.INITIALIZED -> { waitForProjectAndAdd(savedInstanceState) } @@ -43,7 +37,6 @@ abstract class BaseFragment : Fragment() { waitForProjectAndAdd(savedInstanceState) } InitializationState.ERROR -> { - progress.isVisible = false sdkNotInitialized.isVisible = true } } @@ -54,13 +47,12 @@ abstract class BaseFragment : Fragment() { sdkNotInitialized.isVisible = false SnabbleUI.projectAsLiveData.observe(viewLifecycleOwner) { - progress.isVisible = it == null - if (it != null) { if (fragmentContainer.childCount == 0) { val fragmentView = - onCreateViewInternal(layoutInflater, fragmentContainer, savedInstanceState) + onCreateActualView(layoutInflater, fragmentContainer, savedInstanceState) if (fragmentView != null) { + sdkNotInitialized.isVisible = false fragmentContainer.addView(fragmentView) isReady = true } @@ -73,7 +65,7 @@ abstract class BaseFragment : Fragment() { } } - abstract fun onCreateViewInternal( + abstract fun onCreateActualView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?) diff --git a/ui/src/main/java/io/snabble/sdk/ui/cart/ShoppingCartFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/cart/ShoppingCartFragment.kt index d1887630df..c783e74516 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/cart/ShoppingCartFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/cart/ShoppingCartFragment.kt @@ -11,7 +11,7 @@ open class ShoppingCartFragment : BaseFragment() { var shoppingCartView: ShoppingCartView? = null private set - override fun onCreateViewInternal( + override fun onCreateActualView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? diff --git a/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutCustomerCardFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutCustomerCardFragment.kt index aa6b169165..bbc06c5e9e 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutCustomerCardFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutCustomerCardFragment.kt @@ -9,7 +9,7 @@ import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R open class CheckoutCustomerCardFragment : BaseFragment() { - override fun onCreateViewInternal( + override fun onCreateActualView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? diff --git a/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutOfflineFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutOfflineFragment.kt index a100e2036f..3ba7a1e425 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutOfflineFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutOfflineFragment.kt @@ -9,7 +9,7 @@ import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R open class CheckoutOfflineFragment : BaseFragment() { - override fun onCreateViewInternal( + override fun onCreateActualView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? diff --git a/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutPOSFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutPOSFragment.kt index 405989b6da..2a6784942b 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutPOSFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutPOSFragment.kt @@ -9,7 +9,7 @@ import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R open class CheckoutPOSFragment : BaseFragment() { - override fun onCreateViewInternal( + override fun onCreateActualView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? diff --git a/ui/src/main/java/io/snabble/sdk/ui/checkout/PaymentStatusFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/checkout/PaymentStatusFragment.kt index b3a2052dc1..1616f0f106 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/checkout/PaymentStatusFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/checkout/PaymentStatusFragment.kt @@ -9,7 +9,7 @@ import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R open class PaymentStatusFragment : BaseFragment() { - override fun onCreateViewInternal( + override fun onCreateActualView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? diff --git a/ui/src/main/java/io/snabble/sdk/ui/checkout/routingtargets/RoutingTargetGatekeeperFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/checkout/routingtargets/RoutingTargetGatekeeperFragment.kt index 226fac80ea..bb994bbece 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/checkout/routingtargets/RoutingTargetGatekeeperFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/checkout/routingtargets/RoutingTargetGatekeeperFragment.kt @@ -9,7 +9,7 @@ import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R open class RoutingTargetGatekeeperFragment : BaseFragment() { - override fun onCreateViewInternal( + override fun onCreateActualView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? diff --git a/ui/src/main/java/io/snabble/sdk/ui/checkout/routingtargets/RoutingTargetSupervisorFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/checkout/routingtargets/RoutingTargetSupervisorFragment.kt index 729aefa048..a09a18f904 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/checkout/routingtargets/RoutingTargetSupervisorFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/checkout/routingtargets/RoutingTargetSupervisorFragment.kt @@ -9,7 +9,7 @@ import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R open class RoutingTargetSupervisorFragment : BaseFragment() { - override fun onCreateViewInternal( + override fun onCreateActualView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/AgeVerificationInputFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/AgeVerificationInputFragment.kt index 7b999ff994..b76164be2d 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/AgeVerificationInputFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/AgeVerificationInputFragment.kt @@ -9,7 +9,7 @@ import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R open class AgeVerificationInputFragment : BaseFragment() { - override fun onCreateViewInternal( + override fun onCreateActualView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/CreditCardInputFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/CreditCardInputFragment.kt index 4993adbead..1b52fe3ceb 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/CreditCardInputFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/CreditCardInputFragment.kt @@ -25,7 +25,7 @@ open class CreditCardInputFragment : BaseFragment() { paymentMethod = arguments?.getSerializable(ARG_PAYMENT_TYPE) as PaymentMethod? } - override fun onCreateViewInternal(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + override fun onCreateActualView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { val v = inflater.inflate(R.layout.snabble_fragment_cardinput_creditcard, container, false) as CreditCardInputView v.load(projectId, paymentMethod) return v diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/PaydirektInputFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/PaydirektInputFragment.kt index 6b4e9f4577..f234edc24b 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/PaydirektInputFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/PaydirektInputFragment.kt @@ -9,7 +9,7 @@ import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R open class PaydirektInputFragment : BaseFragment() { - override fun onCreateViewInternal( + override fun onCreateActualView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentCredentialsListFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentCredentialsListFragment.kt index 072c6d0ed4..3ed98e186e 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentCredentialsListFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentCredentialsListFragment.kt @@ -28,7 +28,7 @@ open class PaymentCredentialsListFragment : BaseFragment() { project = Snabble.getInstance().projects.firstOrNull { it.id == projectId } } - override fun onCreateViewInternal(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + override fun onCreateActualView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { val v = inflater.inflate(R.layout.snabble_fragment_payment_credentials_list, container, false) as PaymentCredentialsListView type?.let { v.show(it, project) } return v diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentOptionsFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentOptionsFragment.kt index 7b418367f4..d7e738969f 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentOptionsFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentOptionsFragment.kt @@ -9,7 +9,7 @@ import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R open class PaymentOptionsFragment : BaseFragment() { - override fun onCreateViewInternal( + override fun onCreateActualView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/PayoneInputFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/PayoneInputFragment.kt index ca04f1747a..9c52742f59 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/PayoneInputFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/PayoneInputFragment.kt @@ -28,7 +28,7 @@ open class PayoneInputFragment : BaseFragment() { tokenizationData = requireNotNull(arguments?.getParcelable(ARG_TOKEN_DATA)) } - override fun onCreateViewInternal(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View = + override fun onCreateActualView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View = inflater.inflate(R.layout.snabble_fragment_cardinput_payone, container, false).apply { findViewById(R.id.user_payment_method_view).load(projectId, paymentMethod, tokenizationData) } diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/ProjectPaymentOptionsFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/ProjectPaymentOptionsFragment.kt index 2ef02ee328..ad19db1e0f 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/ProjectPaymentOptionsFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/ProjectPaymentOptionsFragment.kt @@ -25,7 +25,7 @@ open class ProjectPaymentOptionsFragment : BaseFragment() { } } - override fun onCreateViewInternal(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + override fun onCreateActualView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { val v = inflater.inflate( R.layout.snabble_fragment_select_payment_project, container, diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/SEPACardInputFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/SEPACardInputFragment.kt index feacd3656f..cc0b53e63d 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/SEPACardInputFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/SEPACardInputFragment.kt @@ -24,7 +24,7 @@ open class SEPACardInputFragment : BaseFragment() { as? PaymentOriginCandidateHelper.PaymentOriginCandidate } - override fun onCreateViewInternal( + override fun onCreateActualView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? diff --git a/ui/src/main/java/io/snabble/sdk/ui/scanner/SelfScanningFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/scanner/SelfScanningFragment.kt index 3c84766d27..565f49c8f0 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/scanner/SelfScanningFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/scanner/SelfScanningFragment.kt @@ -36,7 +36,7 @@ open class SelfScanningFragment : BaseFragment() { val hasSelfScanningView get() = selfScanningView != null - override fun onCreateViewInternal( + override fun onCreateActualView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? diff --git a/ui/src/main/java/io/snabble/sdk/ui/search/ProductSearchFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/search/ProductSearchFragment.kt index 797f147009..462fe1c45f 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/search/ProductSearchFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/search/ProductSearchFragment.kt @@ -9,7 +9,7 @@ import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R open class ProductSearchFragment : BaseFragment() { - override fun onCreateViewInternal( + override fun onCreateActualView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? diff --git a/ui/src/main/res/layout/snabble_fragment_base.xml b/ui/src/main/res/layout/snabble_fragment_base.xml index 1af08e6fb5..de2d576f3d 100644 --- a/ui/src/main/res/layout/snabble_fragment_base.xml +++ b/ui/src/main/res/layout/snabble_fragment_base.xml @@ -2,17 +2,12 @@ - - Date: Tue, 15 Feb 2022 12:06:51 +0100 Subject: [PATCH 16/30] do not inherit from Sample HomeFragment from BaseFragment, syntax improvements --- core/src/main/java/io/snabble/sdk/Snabble.kt | 27 +-- .../src/main/java/io/snabble/testapp/App.java | 2 +- .../java/io/snabble/testapp/HomeFragment.java | 186 ++++++++++-------- .../java/io/snabble/sdk/ui/BaseFragment.kt | 1 - .../main/java/io/snabble/sdk/ui/SnabbleUI.kt | 5 - 5 files changed, 113 insertions(+), 108 deletions(-) diff --git a/core/src/main/java/io/snabble/sdk/Snabble.kt b/core/src/main/java/io/snabble/sdk/Snabble.kt index 7cac6d677b..ec3a439594 100644 --- a/core/src/main/java/io/snabble/sdk/Snabble.kt +++ b/core/src/main/java/io/snabble/sdk/Snabble.kt @@ -97,14 +97,10 @@ object Snabble { private set var receiptsUrl: String? = null - get() { - val url = field - val appUser = userPreferences.appUser - return if (appUser != null && url != null) { + get() = field?.let { url -> + userPreferences.appUser?.let { appUser -> url.replace("{appUserID}", appUser.id) - } else { - null - } + } ?: url } private set @@ -126,8 +122,9 @@ object Snabble { var createAppUserUrl: String? = null private set - var initializationState = MutableLiveData() - private set + private val mutableInitializationState = MutableLiveData() + + val initializationState: LiveData = mutableInitializationState var currentActivity: WeakReference? = null @@ -149,7 +146,7 @@ object Snabble { } isInitializing.set(true) - initializationState.value = InitializationState.INITIALIZING + mutableInitializationState.value = InitializationState.INITIALIZING application = app this.config = config @@ -229,7 +226,7 @@ object Snabble { val token = tokenRegistry.getToken(projects[0]) if (token == null) { isInitializing.set(false) - initializationState.postValue(InitializationState.ERROR) + mutableInitializationState.postValue(InitializationState.ERROR) Dispatch.mainThread { setupCompletionListener.onError(Error.CONNECTION_TIMEOUT) @@ -239,7 +236,7 @@ object Snabble { } isInitializing.set(false) - initializationState.postValue(InitializationState.INITIALIZED) + mutableInitializationState.postValue(InitializationState.INITIALIZED) Dispatch.mainThread { setupCompletionListener.onReady() } @@ -251,7 +248,7 @@ object Snabble { private fun dispatchError(setupCompletionListener: SetupCompletionListener) { isInitializing.set(false) - initializationState.postValue(InitializationState.ERROR) + mutableInitializationState.postValue(InitializationState.ERROR) Dispatch.mainThread { setupCompletionListener.onError(Error.CONNECTION_TIMEOUT) @@ -301,10 +298,6 @@ object Snabble { networkCallback) } - fun getInitializationState(): LiveData { - return initializationState - } - /** * Returns true when the SDK is not compatible with the backend anymore and the app should * notify the user that it will not function anymore. diff --git a/java-sample/src/main/java/io/snabble/testapp/App.java b/java-sample/src/main/java/io/snabble/testapp/App.java index c1b63fb817..9ba827b32f 100644 --- a/java-sample/src/main/java/io/snabble/testapp/App.java +++ b/java-sample/src/main/java/io/snabble/testapp/App.java @@ -47,7 +47,7 @@ public void onCreate() { snabble.setup(this, config, new Snabble.SetupCompletionListener() { @Override public void onReady() { - SnabbleUI.setProject(snabble.getProjects().get(0)); + } @Override diff --git a/java-sample/src/main/java/io/snabble/testapp/HomeFragment.java b/java-sample/src/main/java/io/snabble/testapp/HomeFragment.java index b03727b63c..a2735a4207 100644 --- a/java-sample/src/main/java/io/snabble/testapp/HomeFragment.java +++ b/java-sample/src/main/java/io/snabble/testapp/HomeFragment.java @@ -4,7 +4,6 @@ import android.content.Context; import android.os.Bundle; import android.util.Log; -import android.util.TimingLogger; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -15,22 +14,26 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.lifecycle.Observer; import org.apache.commons.io.FileUtils; import java.io.IOException; import java.util.List; +import io.snabble.sdk.InitializationState; import io.snabble.sdk.Project; import io.snabble.sdk.Shop; import io.snabble.sdk.Snabble; -import io.snabble.sdk.ui.BaseFragment; import io.snabble.sdk.ui.SnabbleUI; -public class HomeFragment extends BaseFragment { +public class HomeFragment extends Fragment { + private Project currentProject; + @Nullable @Override - public View onCreateActualView(@NonNull LayoutInflater inflater, + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View v = inflater.inflate(R.layout.fragment_home, container, false); @@ -61,100 +64,115 @@ public View onCreateActualView(@NonNull LayoutInflater inflater, activityManager.clearApplicationUserData(); }); - // convenience project switching for debugging - use geofencing or a single project in real apps - final List projectList = Snabble.getInstance().getProjects(); - Spinner projects = v.findViewById(R.id.projects); - projects.setAdapter(new ArrayAdapter(requireContext(), R.layout.item_dropdown, projectList) { - @NonNull - @Override - public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { - TextView v = (TextView) super.getView(position, convertView, parent); - v.setText(projectList.get(position).getId()); - return v; - } - - @Override - public View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { - TextView v = (TextView) super.getDropDownView(position, convertView, parent); - v.setText(projectList.get(position).getId()); - return v; - } - }); - - for (int i=0; i() { @Override - public void onItemSelected(AdapterView parent, View view, int position, long id) { - Project project = projectList.get(position); - - SnabbleUI.setProject(project); - - updateShops(v); - - if (project.getShops().size() > 0) { - project.setCheckedInShop(project.getShops().get(0)); + public void onChanged(InitializationState initializationState) { + if (initializationState == InitializationState.INITIALIZED) { + // convenience project switching for debugging - use geofencing or a single project in real apps + final List projectList = Snabble.getInstance().getProjects(); + Spinner projects = v.findViewById(R.id.projects); + + SnabbleUI.getProjectAsLiveData().observe(getViewLifecycleOwner(), project -> { + currentProject = project; + + for (int i = 0; i < projectList.size(); i++) { + if (project == projectList.get(i)) { + projects.setSelection(i); + break; + } + } + + updateShops(v); + }); + + projects.setAdapter(new ArrayAdapter(requireContext(), R.layout.item_dropdown, projectList) { + @NonNull + @Override + public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { + TextView v = (TextView) super.getView(position, convertView, parent); + v.setText(projectList.get(position).getId()); + return v; + } + + @Override + public View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { + TextView v = (TextView) super.getDropDownView(position, convertView, parent); + v.setText(projectList.get(position).getId()); + return v; + } + }); + + projects.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + Project project = projectList.get(position); + + SnabbleUI.setProject(project); + + updateShops(v); + + if (project.getShops().size() > 0) { + project.setCheckedInShop(project.getShops().get(0)); + } + } + + @Override + public void onNothingSelected(AdapterView parent) { + + } + }); + + updateShops(v); } } - - @Override - public void onNothingSelected(AdapterView parent) { - - } }); - updateShops(v); - return v; } private void updateShops(View v) { - Project project = SnabbleUI.getProject(); - final List shopList = project.getShops(); - Spinner shops = v.findViewById(R.id.shops); - shops.setAdapter(new ArrayAdapter(requireContext(), R.layout.item_dropdown, shopList) { - @NonNull - @Override - public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { - TextView v = (TextView) super.getView(position, convertView, parent); - Shop shop = shopList.get(position); - v.setText(shop.getName() + " (" + shop.getId() + ")"); - return v; - } + if (currentProject != null) { + final List shopList = currentProject.getShops(); + Spinner shops = v.findViewById(R.id.shops); + shops.setAdapter(new ArrayAdapter(requireContext(), R.layout.item_dropdown, shopList) { + @NonNull + @Override + public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { + TextView v = (TextView) super.getView(position, convertView, parent); + Shop shop = shopList.get(position); + v.setText(shop.getName() + " (" + shop.getId() + ")"); + return v; + } - @Override - public View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { - TextView v = (TextView) super.getDropDownView(position, convertView, parent); - Shop shop = shopList.get(position); - v.setText(shop.getName() + " (" + shop.getId() + ")"); - return v; - } - }); + @Override + public View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { + TextView v = (TextView) super.getDropDownView(position, convertView, parent); + Shop shop = shopList.get(position); + v.setText(shop.getName() + " (" + shop.getId() + ")"); + return v; + } + }); - for (int i=0; i { args.putString(CreditCardInputView.ARG_PROJECT_ID, projectId) - args.putSerializable(CreditCardInputView.ARG_PAYMENT_TYPE, - PaymentMethod.VISA) - SnabbleUI.executeAction(context, - SnabbleUI.Event.SHOW_CREDIT_CARD_INPUT, - args) + args.putSerializable(CreditCardInputView.ARG_PAYMENT_TYPE, PaymentMethod.VISA) + SnabbleUI.executeAction(context, SnabbleUI.Event.SHOW_CREDIT_CARD_INPUT, args) } PaymentMethod.AMEX -> { args.putString(CreditCardInputView.ARG_PROJECT_ID, projectId) - args.putSerializable(CreditCardInputView.ARG_PAYMENT_TYPE, - PaymentMethod.AMEX) - SnabbleUI.executeAction(context, - SnabbleUI.Event.SHOW_CREDIT_CARD_INPUT, - args) + args.putSerializable(CreditCardInputView.ARG_PAYMENT_TYPE, PaymentMethod.AMEX) + SnabbleUI.executeAction(context, SnabbleUI.Event.SHOW_CREDIT_CARD_INPUT, args) } PaymentMethod.MASTERCARD -> { args.putString(CreditCardInputView.ARG_PROJECT_ID, projectId) - args.putSerializable(CreditCardInputView.ARG_PAYMENT_TYPE, - PaymentMethod.MASTERCARD) - SnabbleUI.executeAction(context, - SnabbleUI.Event.SHOW_CREDIT_CARD_INPUT, - args) + args.putSerializable(CreditCardInputView.ARG_PAYMENT_TYPE, PaymentMethod.MASTERCARD) + SnabbleUI.executeAction(context, SnabbleUI.Event.SHOW_CREDIT_CARD_INPUT, args) } PaymentMethod.PAYDIREKT -> { SnabbleUI.executeAction(context, SnabbleUI.Event.SHOW_PAYDIREKT_INPUT) diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentOptionsFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentOptionsFragment.kt index d7e738969f..34cc2e8529 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentOptionsFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentOptionsFragment.kt @@ -8,12 +8,8 @@ import androidx.fragment.app.Fragment import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R -open class PaymentOptionsFragment : BaseFragment() { - override fun onCreateActualView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - return inflater.inflate(R.layout.snabble_fragment_payment_options, container, false) - } -} \ No newline at end of file +open class PaymentOptionsFragment : BaseFragment( + layoutResId = R.layout.snabble_fragment_payment_options, + waitForProject = false +) + diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/PayoneInputFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/PayoneInputFragment.kt index 9c52742f59..62c59d828f 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/PayoneInputFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/PayoneInputFragment.kt @@ -9,7 +9,10 @@ import io.snabble.sdk.PaymentMethod import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R -open class PayoneInputFragment : BaseFragment() { +open class PayoneInputFragment : BaseFragment( + layoutResId = R.layout.snabble_fragment_cardinput_payone, + waitForProject = false +) { companion object { const val ARG_PROJECT_ID = PayoneInputView.ARG_PROJECT_ID const val ARG_PAYMENT_TYPE = PayoneInputView.ARG_PAYMENT_TYPE @@ -28,8 +31,8 @@ open class PayoneInputFragment : BaseFragment() { tokenizationData = requireNotNull(arguments?.getParcelable(ARG_TOKEN_DATA)) } - override fun onCreateActualView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View = - inflater.inflate(R.layout.snabble_fragment_cardinput_payone, container, false).apply { - findViewById(R.id.user_payment_method_view).load(projectId, paymentMethod, tokenizationData) - } + override fun onActualViewCreated(view: View, savedInstanceState: Bundle?) { + view.findViewById(R.id.user_payment_method_view) + .load(projectId, paymentMethod, tokenizationData) + } } \ No newline at end of file diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/ProjectPaymentOptionsFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/ProjectPaymentOptionsFragment.kt index ad19db1e0f..1884454060 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/ProjectPaymentOptionsFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/ProjectPaymentOptionsFragment.kt @@ -10,7 +10,10 @@ import io.snabble.sdk.Snabble import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R -open class ProjectPaymentOptionsFragment : BaseFragment() { +open class ProjectPaymentOptionsFragment : BaseFragment( + layoutResId = R.layout.snabble_fragment_select_payment_project, + waitForProject = false +) { companion object { const val ARG_BRAND = ProjectPaymentOptionsView.ARG_BRAND } @@ -25,13 +28,8 @@ open class ProjectPaymentOptionsFragment : BaseFragment() { } } - override fun onCreateActualView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { - val v = inflater.inflate( - R.layout.snabble_fragment_select_payment_project, - container, - false - ) as ProjectPaymentOptionsView - + override fun onActualViewCreated(view: View, savedInstanceState: Bundle?) { + val v = view as ProjectPaymentOptionsView brand?.let { brand -> val projects = ArrayList() Snabble.getInstance().projects.forEach { project -> @@ -41,7 +39,5 @@ open class ProjectPaymentOptionsFragment : BaseFragment() { } v.projects = projects } - - return v } } \ No newline at end of file diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/SEPACardInputFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/SEPACardInputFragment.kt index cc0b53e63d..968d24077a 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/SEPACardInputFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/SEPACardInputFragment.kt @@ -10,7 +10,10 @@ import io.snabble.sdk.PaymentOriginCandidateHelper import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R -open class SEPACardInputFragment : BaseFragment() { +open class SEPACardInputFragment : BaseFragment( + layoutResId = R.layout.snabble_fragment_cardinput_sepa, + waitForProject = false +) { companion object { const val ARG_PAYMENT_ORIGIN_CANDIDATE = "paymentOriginCandidate" } @@ -24,15 +27,10 @@ open class SEPACardInputFragment : BaseFragment() { as? PaymentOriginCandidateHelper.PaymentOriginCandidate } - override fun onCreateActualView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - val v = inflater.inflate(R.layout.snabble_fragment_cardinput_sepa, container, false) as SEPACardInputView + override fun onActualViewCreated(view: View, savedInstanceState: Bundle?) { + val v = view as SEPACardInputView paymentOriginCandidate?.let { v.setPrefilledPaymentOriginCandidate(paymentOriginCandidate) } - return v } } \ No newline at end of file diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/SelectPaymentMethodFragment.java b/ui/src/main/java/io/snabble/sdk/ui/payment/SelectPaymentMethodFragment.java index 21a8823fcc..c671cbeec7 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/SelectPaymentMethodFragment.java +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/SelectPaymentMethodFragment.java @@ -66,7 +66,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa "SEPA", getUsableAtText(PaymentMethod.DE_DIRECT_DEBIT), new OneShotClickListener() { @Override public void click() { - PaymentInputViewHelper.openPaymentInputView(requireContext(), PaymentMethod.DE_DIRECT_DEBIT, null); + PaymentInputViewHelper.openPaymentInputView(requireContext(), PaymentMethod.DE_DIRECT_DEBIT, projectId); dismissAllowingStateLoss(); } })); diff --git a/ui/src/main/java/io/snabble/sdk/ui/search/ProductSearchFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/search/ProductSearchFragment.kt index 462fe1c45f..ccdda46675 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/search/ProductSearchFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/search/ProductSearchFragment.kt @@ -8,14 +8,9 @@ import androidx.fragment.app.Fragment import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R -open class ProductSearchFragment : BaseFragment() { - override fun onCreateActualView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View { - val v = inflater.inflate(R.layout.snabble_fragment_productsearch, container, false) as ProductSearchView +open class ProductSearchFragment : BaseFragment(R.layout.snabble_fragment_productsearch) { + override fun onActualViewCreated(view: View, savedInstanceState: Bundle?) { + val v = view as ProductSearchView v.allowAnyCode = true - return v } } \ No newline at end of file From fc960b8c90b46193f0faece1d954bbb0afb948bc Mon Sep 17 00:00:00 2001 From: Alexander Junggeburth Date: Tue, 15 Feb 2022 12:47:46 +0100 Subject: [PATCH 19/30] prevent overriding of baseclass methods --- ui/src/main/java/io/snabble/sdk/ui/BaseFragment.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/src/main/java/io/snabble/sdk/ui/BaseFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/BaseFragment.kt index 12a2d1e722..ece89fe5c9 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/BaseFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/BaseFragment.kt @@ -17,7 +17,7 @@ abstract class BaseFragment(@LayoutRes val layoutResId: Int = 0, val waitForProj var isReady = false - override fun onCreateView( + final override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? @@ -25,7 +25,7 @@ abstract class BaseFragment(@LayoutRes val layoutResId: Int = 0, val waitForProj return inflater.inflate(R.layout.snabble_fragment_base, container, false) } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + final override fun onViewCreated(view: View, savedInstanceState: Bundle?) { fragmentContainer = view.findViewById(R.id.fragment_container) sdkNotInitialized = view.findViewById(R.id.sdk_not_initialized) From 4c50c191dace36745f9f58fbc8610d41d732ade8 Mon Sep 17 00:00:00 2001 From: Alexander Junggeburth Date: Tue, 15 Feb 2022 12:51:39 +0100 Subject: [PATCH 20/30] cleanup --- core/src/main/java/io/snabble/sdk/Snabble.kt | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/core/src/main/java/io/snabble/sdk/Snabble.kt b/core/src/main/java/io/snabble/sdk/Snabble.kt index ec3a439594..c3bda74fcc 100644 --- a/core/src/main/java/io/snabble/sdk/Snabble.kt +++ b/core/src/main/java/io/snabble/sdk/Snabble.kt @@ -48,13 +48,13 @@ object Snabble { lateinit var tokenRegistry: TokenRegistry private set - lateinit var projects: List + var projects: List = emptyList() private set - var brands: Map? = null + var brands: Map = emptyMap() private set - lateinit var receipts: Receipts + var receipts: Receipts = Receipts() private set lateinit var users: Users @@ -66,7 +66,7 @@ object Snabble { lateinit var userPreferences: UserPreferences private set - lateinit var paymentCredentialsStore: PaymentCredentialsStore + var paymentCredentialsStore: PaymentCredentialsStore = PaymentCredentialsStore() private set lateinit var checkInLocationManager: CheckInLocationManager @@ -171,20 +171,16 @@ object Snabble { } versionName = version - internalStorageDirectory = File(application.filesDir, "snabble/" + config.appId + "/") + internalStorageDirectory = File(application.filesDir, "snabble/${config.appId}/") internalStorageDirectory.mkdirs() okHttpClient = OkHttpClientFactory.createOkHttpClient(app) userPreferences = UserPreferences(app) tokenRegistry = TokenRegistry(okHttpClient, userPreferences, config.appId, config.secret) - receipts = Receipts() users = Users(userPreferences) - brands = Collections.unmodifiableMap(HashMap()) - projects = Collections.unmodifiableList(ArrayList()) environment = Environment.getEnvironmentByUrl(config.endpointBaseUrl) metadataUrl = absoluteUrl("/metadata/app/" + config.appId + "/android/" + version) - paymentCredentialsStore = PaymentCredentialsStore() checkInLocationManager = CheckInLocationManager(application) checkInManager = CheckInManager(this, From 86d952e5f8ae0a6cd0d2b8ef5aae120e35bd703c Mon Sep 17 00:00:00 2001 From: Alexander Junggeburth Date: Tue, 15 Feb 2022 13:21:53 +0100 Subject: [PATCH 21/30] small fixes and clean up --- core/src/main/java/io/snabble/sdk/Snabble.kt | 58 ++++++++----------- .../java/io/snabble/sdk/UserPreferences.kt | 14 ++--- .../src/main/java/io/snabble/testapp/App.java | 12 +--- .../java/io/snabble/testapp/HomeFragment.java | 15 +++-- ui/build.gradle | 2 +- 5 files changed, 39 insertions(+), 62 deletions(-) diff --git a/core/src/main/java/io/snabble/sdk/Snabble.kt b/core/src/main/java/io/snabble/sdk/Snabble.kt index c3bda74fcc..2a10220ae8 100644 --- a/core/src/main/java/io/snabble/sdk/Snabble.kt +++ b/core/src/main/java/io/snabble/sdk/Snabble.kt @@ -140,7 +140,8 @@ object Snabble { private val isInitializing = AtomicBoolean(false) - fun setup(app: Application, config: Config, setupCompletionListener: SetupCompletionListener) { + @JvmOverloads + fun setup(app: Application, config: Config, setupCompletionListener: SetupCompletionListener? = null) { if (isInitializing.get()) { return } @@ -156,7 +157,7 @@ object Snabble { if (!config.endpointBaseUrl.startsWith("http://") && !config.endpointBaseUrl.startsWith("https://")) { - setupCompletionListener.onError(Error.CONFIG_ERROR) + setupCompletionListener?.onError(Error.CONFIG_ERROR) return } @@ -214,7 +215,7 @@ object Snabble { registerNetworkCallback(app) } - private fun dispatchOnReady(setupCompletionListener: SetupCompletionListener) { + private fun dispatchOnReady(setupCompletionListener: SetupCompletionListener?) { Dispatch.background { readMetadata() val appUser = userPreferences.appUser @@ -225,7 +226,7 @@ object Snabble { mutableInitializationState.postValue(InitializationState.ERROR) Dispatch.mainThread { - setupCompletionListener.onError(Error.CONNECTION_TIMEOUT) + setupCompletionListener?.onError(Error.CONNECTION_TIMEOUT) } return@background } @@ -234,7 +235,7 @@ object Snabble { isInitializing.set(false) mutableInitializationState.postValue(InitializationState.INITIALIZED) Dispatch.mainThread { - setupCompletionListener.onReady() + setupCompletionListener?.onReady() } if (config.loadActiveShops) { loadActiveShops() @@ -242,12 +243,12 @@ object Snabble { } } - private fun dispatchError(setupCompletionListener: SetupCompletionListener) { + private fun dispatchError(setupCompletionListener: SetupCompletionListener?) { isInitializing.set(false) mutableInitializationState.postValue(InitializationState.ERROR) Dispatch.mainThread { - setupCompletionListener.onError(Error.CONNECTION_TIMEOUT) + setupCompletionListener?.onError(Error.CONNECTION_TIMEOUT) } } @@ -299,12 +300,9 @@ object Snabble { * notify the user that it will not function anymore. */ val isOutdatedSDK: Boolean - get() { - val jsonObject = additionalMetadata - return if (jsonObject != null) { - JsonUtils.getBooleanOpt(jsonObject, "kill", false) - } else false - } + get() = additionalMetadata?.let { json -> + JsonUtils.getBooleanOpt(json, "kill", false) + } ?: false /** Returns additional metadata that may be provided for apps unrelated to the SDK */ val additionalMetadata: JsonObject? @@ -316,8 +314,7 @@ object Snabble { @Synchronized private fun readMetadata() { - val jsonObject = metadataDownloader.jsonObject - if (jsonObject != null) { + metadataDownloader.jsonObject?.let { jsonObject -> createAppUserUrl = getUrl(jsonObject, "createAppUser") telecashSecretUrl = getUrl(jsonObject, "telecashSecret") telecashPreAuthUrl = getUrl(jsonObject, "telecashPreauth") @@ -339,6 +336,7 @@ object Snabble { GsonHolder.get().fromJson(jsonObject["terms"], TermsOfService::class.java) } } + restoreCheckedInShop() paymentCredentialsStore.init(application, environment) users.postPendingConsents() @@ -371,11 +369,7 @@ object Snabble { private fun parseBrands(jsonObject: JsonObject) { val jsonBrands = GsonHolder.get().fromJson(jsonObject["brands"], Array::class.java) - val map = HashMap() - for (brand in jsonBrands) { - map[brand.id] = brand - } - brands = Collections.unmodifiableMap(map) + brands = jsonBrands.map { it.id to it }.toMap() } private fun parseProjects(jsonObject: JsonObject) { @@ -418,17 +412,16 @@ object Snabble { private fun parsePaymentCertificates(jsonObject: JsonObject) { val certificates: MutableList = ArrayList() val certs = jsonObject["gatewayCertificates"].asJsonArray - for (i in 0 until certs.size()) { - val jsonElement = certs[i] + certs.forEach { jsonElement -> if (jsonElement.isJsonObject) { val cert = jsonElement.asJsonObject val value = cert["value"] if (value != null) { val bytes = Base64.decode(value.asString, Base64.DEFAULT) - val `is`: InputStream = ByteArrayInputStream(bytes) + val inputStream: InputStream = ByteArrayInputStream(bytes) try { val certificateFactory = CertificateFactory.getInstance("X.509") - val certificate = certificateFactory.generateCertificate(`is`) as X509Certificate + val certificate = certificateFactory.generateCertificate(inputStream) as X509Certificate certificates.add(certificate) } catch (e: CertificateException) { e.printStackTrace() @@ -448,16 +441,11 @@ object Snabble { } } - val endpointBaseUrl: String? + val endpointBaseUrl: String get() = config.endpointBaseUrl fun getProjectById(projectId: String?): Project? { - for (project in projects) { - if (project.id == projectId) { - return project - } - } - return null + return projects.firstOrNull { it.id == projectId } } private fun updateMetadata() { @@ -476,25 +464,25 @@ object Snabble { } private fun loadActiveShops() { - for (project in projects) { + projects.forEach { project -> project.loadActiveShops { notifyMetadataUpdated() } } } private fun checkCartTimeouts() { - for (project in projects) { + projects.forEach { project -> project.shoppingCart.checkForTimeout() } } private fun processPendingCheckouts() { - for (project in projects) { + projects.forEach { project -> project.checkout.processPendingCheckouts() } } private fun notifyMetadataUpdated() { - for (listener in onMetaDataUpdateListeners) { + onMetaDataUpdateListeners.forEach { listener -> listener.onMetaDataUpdated() } } diff --git a/core/src/main/java/io/snabble/sdk/UserPreferences.kt b/core/src/main/java/io/snabble/sdk/UserPreferences.kt index dc1386d6f8..b10e3cb25b 100644 --- a/core/src/main/java/io/snabble/sdk/UserPreferences.kt +++ b/core/src/main/java/io/snabble/sdk/UserPreferences.kt @@ -58,14 +58,14 @@ class UserPreferences internal constructor(context: Context) { private val appUserIdKey: String get() { - val (_, appId) = Snabble.config - return SHARED_PREFERENCES_APPUSER_ID + "_" + environmentKey + appId + val appId = Snabble.config.appId + return "${SHARED_PREFERENCES_APPUSER_ID}_$environmentKey$appId" } private val appUserIdSecret: String get() { - val (_, appId) = Snabble.config - return SHARED_PREFERENCES_APPUSER_SECRET + "_" + environmentKey + appId + val appId = Snabble.config.appId + return "${SHARED_PREFERENCES_APPUSER_SECRET}_$environmentKey$appId" } var appUser: AppUser? @@ -118,7 +118,7 @@ class UserPreferences internal constructor(context: Context) { return } var appUserString = String(Base64.decode(appUserBase64, Base64.DEFAULT)) - val split = appUserString.split(":").toTypedArray() + val split = appUserString.split(":") if (split.size == 2) { val appUserId = split[0] val appUserSecret = split[1] @@ -158,7 +158,7 @@ class UserPreferences internal constructor(context: Context) { } set(date) { sharedPreferences.edit() - .putString(SHARED_PREFERENCES_BIRTHDAY, BIRTHDAY_FORMAT.format(date)) + .putString(SHARED_PREFERENCES_BIRTHDAY, date?.let { BIRTHDAY_FORMAT.format(date) }) .apply() } @@ -201,7 +201,7 @@ class UserPreferences internal constructor(context: Context) { } } - interface OnNewAppUserListener { + fun interface OnNewAppUserListener { fun onNewAppUser(appUser: AppUser?) } } \ No newline at end of file diff --git a/java-sample/src/main/java/io/snabble/testapp/App.java b/java-sample/src/main/java/io/snabble/testapp/App.java index 9ba827b32f..a75dbc1721 100644 --- a/java-sample/src/main/java/io/snabble/testapp/App.java +++ b/java-sample/src/main/java/io/snabble/testapp/App.java @@ -44,17 +44,7 @@ public void onCreate() { // } final Snabble snabble = Snabble.getInstance(); - snabble.setup(this, config, new Snabble.SetupCompletionListener() { - @Override - public void onReady() { - - } - - @Override - public void onError(Snabble.Error error) { - - } - }); + snabble.setup(this, config); // sets a ui event listener for telemetry events, which can you redirect to any // telemetry provider diff --git a/java-sample/src/main/java/io/snabble/testapp/HomeFragment.java b/java-sample/src/main/java/io/snabble/testapp/HomeFragment.java index a2735a4207..2b58b50d42 100644 --- a/java-sample/src/main/java/io/snabble/testapp/HomeFragment.java +++ b/java-sample/src/main/java/io/snabble/testapp/HomeFragment.java @@ -26,17 +26,18 @@ import io.snabble.sdk.Project; import io.snabble.sdk.Shop; import io.snabble.sdk.Snabble; +import io.snabble.sdk.ui.BaseFragment; import io.snabble.sdk.ui.SnabbleUI; -public class HomeFragment extends Fragment { +public class HomeFragment extends BaseFragment { private Project currentProject; - @Nullable + public HomeFragment() { + super(R.layout.fragment_home, false); + } + @Override - public View onCreateView(@NonNull LayoutInflater inflater, - @Nullable ViewGroup container, - @Nullable Bundle savedInstanceState) { - View v = inflater.inflate(R.layout.fragment_home, container, false); + public void onActualViewCreated(@NonNull View v, @Nullable Bundle savedInstanceState) { v.findViewById(R.id.scanner).setOnClickListener(btn -> ((BaseActivity)getActivity()).showScanner()); @@ -126,8 +127,6 @@ public void onNothingSelected(AdapterView parent) { } } }); - - return v; } private void updateShops(View v) { diff --git a/ui/build.gradle b/ui/build.gradle index f704132bb3..1890d2d39e 100644 --- a/ui/build.gradle +++ b/ui/build.gradle @@ -41,7 +41,7 @@ android { jvmTarget = '1.8' } lint { - disable 'LabelFor', 'ContentDescription', 'MissingTranslation' + disable 'LabelFor', 'MissingTranslation' } } From 18aec787f423ffabaf5e0b9fa0eb8bcbf4b0a2e2 Mon Sep 17 00:00:00 2001 From: Alexander Junggeburth Date: Tue, 15 Feb 2022 15:37:36 +0100 Subject: [PATCH 22/30] fix lint --- ui/src/main/java/io/snabble/sdk/ui/views/MessageBox.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ui/src/main/java/io/snabble/sdk/ui/views/MessageBox.kt b/ui/src/main/java/io/snabble/sdk/ui/views/MessageBox.kt index ba6d05bfd8..0759f10d98 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/views/MessageBox.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/views/MessageBox.kt @@ -1,6 +1,7 @@ package io.snabble.sdk.ui.views import android.animation.* +import android.annotation.SuppressLint import android.content.Context import android.graphics.Color import android.util.AttributeSet @@ -10,6 +11,7 @@ import android.widget.LinearLayout import android.widget.TextView import androidx.cardview.widget.CardView import androidx.core.view.isVisible +import com.google.android.material.animation.AnimationUtils import com.google.android.material.animation.AnimationUtils.LINEAR_INTERPOLATOR import io.snabble.sdk.ui.R import io.snabble.sdk.utils.Dispatch @@ -60,16 +62,18 @@ class MessageBox @JvmOverloads constructor( animator.start() } + @SuppressLint("RestrictedApi") private fun getAlphaAnimator(vararg alphaValues: Float): ValueAnimator { val animator = ValueAnimator.ofFloat(*alphaValues) - animator.interpolator = LINEAR_INTERPOLATOR + animator.interpolator = AnimationUtils.LINEAR_INTERPOLATOR animator.addUpdateListener { valueAnimator -> alpha = valueAnimator.animatedValue as Float } return animator } + @SuppressLint("RestrictedApi") private fun getScaleAnimator(vararg scaleValues: Float): ValueAnimator { val animator = ValueAnimator.ofFloat(*scaleValues) - animator.interpolator = com.google.android.material.animation.AnimationUtils.LINEAR_OUT_SLOW_IN_INTERPOLATOR + animator.interpolator = AnimationUtils.LINEAR_OUT_SLOW_IN_INTERPOLATOR animator.addUpdateListener { valueAnimator -> val scale = valueAnimator.animatedValue as Float scaleX = scale From 4eb386cbec54e0206779fd43cb9f8650f055e321 Mon Sep 17 00:00:00 2001 From: Alexander Junggeburth Date: Tue, 15 Feb 2022 17:02:47 +0100 Subject: [PATCH 23/30] compatibility fixes --- core/src/main/java/io/snabble/sdk/Snabble.kt | 2 +- .../io/snabble/sdk/ui/scanner/SelfScanningFragment.kt | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/io/snabble/sdk/Snabble.kt b/core/src/main/java/io/snabble/sdk/Snabble.kt index 2a10220ae8..e27673823f 100644 --- a/core/src/main/java/io/snabble/sdk/Snabble.kt +++ b/core/src/main/java/io/snabble/sdk/Snabble.kt @@ -147,7 +147,7 @@ object Snabble { } isInitializing.set(true) - mutableInitializationState.value = InitializationState.INITIALIZING + mutableInitializationState.postValue(InitializationState.INITIALIZING) application = app this.config = config diff --git a/ui/src/main/java/io/snabble/sdk/ui/scanner/SelfScanningFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/scanner/SelfScanningFragment.kt index 565f49c8f0..67a0885193 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/scanner/SelfScanningFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/scanner/SelfScanningFragment.kt @@ -42,9 +42,13 @@ open class SelfScanningFragment : BaseFragment() { savedInstanceState: Bundle? ): View? { setHasOptionsMenu(false) + return inflater.inflate(R.layout.snabble_fragment_selfscanning, container, false) as ViewGroup + } - rootView = inflater.inflate(R.layout.snabble_fragment_selfscanning, container, false) as ViewGroup + override fun onActualViewCreated(view: View, savedInstanceState: Bundle?) { + super.onActualViewCreated(view, savedInstanceState) + rootView = view as ViewGroup selfScanningView = null permissionContainer = rootView.findViewById(R.id.permission_denied_container) askForPermission = rootView.findViewById(R.id.open_settings) @@ -52,8 +56,6 @@ open class SelfScanningFragment : BaseFragment() { if (isPermissionGranted) { createSelfScanningView() } - - return rootView } override fun onStart() { @@ -78,8 +80,6 @@ open class SelfScanningFragment : BaseFragment() { } private fun createSelfScanningView() { - if (!isReady) return - if (selfScanningView == null) { selfScanningView = SelfScanningView(context).apply { setAllowShowingHints(allowShowingHints) From fb69fde4a8e9d95504e008a54403d19a527580b4 Mon Sep 17 00:00:00 2001 From: Alexander Junggeburth Date: Wed, 16 Feb 2022 10:47:35 +0100 Subject: [PATCH 24/30] fix repeated setup calls cleaning up properly --- core/src/main/java/io/snabble/sdk/Snabble.kt | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/io/snabble/sdk/Snabble.kt b/core/src/main/java/io/snabble/sdk/Snabble.kt index e27673823f..943892561c 100644 --- a/core/src/main/java/io/snabble/sdk/Snabble.kt +++ b/core/src/main/java/io/snabble/sdk/Snabble.kt @@ -47,14 +47,14 @@ object Snabble { lateinit var tokenRegistry: TokenRegistry private set - - var projects: List = emptyList() + + lateinit var projects: List private set - var brands: Map = emptyMap() + lateinit var brands: Map private set - var receipts: Receipts = Receipts() + lateinit var receipts: Receipts private set lateinit var users: Users @@ -66,7 +66,7 @@ object Snabble { lateinit var userPreferences: UserPreferences private set - var paymentCredentialsStore: PaymentCredentialsStore = PaymentCredentialsStore() + lateinit var paymentCredentialsStore: PaymentCredentialsStore private set lateinit var checkInLocationManager: CheckInLocationManager @@ -178,10 +178,13 @@ object Snabble { okHttpClient = OkHttpClientFactory.createOkHttpClient(app) userPreferences = UserPreferences(app) tokenRegistry = TokenRegistry(okHttpClient, userPreferences, config.appId, config.secret) + receipts = Receipts() users = Users(userPreferences) - + brands = Collections.unmodifiableMap(emptyMap()) + projects = Collections.unmodifiableList(emptyList()) environment = Environment.getEnvironmentByUrl(config.endpointBaseUrl) metadataUrl = absoluteUrl("/metadata/app/" + config.appId + "/android/" + version) + paymentCredentialsStore = PaymentCredentialsStore() checkInLocationManager = CheckInLocationManager(application) checkInManager = CheckInManager(this, From 214e3981832e8dbb51bb8ac3ea639c5a9d1ce6bb Mon Sep 17 00:00:00 2001 From: Alexander Junggeburth Date: Wed, 16 Feb 2022 11:14:22 +0100 Subject: [PATCH 25/30] improve null safety --- ui/src/main/java/io/snabble/sdk/ui/payment/Payone.kt | 2 +- ui/src/main/java/io/snabble/sdk/ui/payment/PayoneInputView.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/Payone.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/Payone.kt index 055c535846..d3316ba7b1 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/Payone.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/Payone.kt @@ -36,7 +36,7 @@ object Payone { @Parcelize data class Link( - val href: String + val href: String? ) : Parcelable data class PreAuthRequest( diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/PayoneInputView.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/PayoneInputView.kt index cf9ff99412..14b404d922 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/PayoneInputView.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/PayoneInputView.kt @@ -243,7 +243,7 @@ class PayoneInputView @JvmOverloads constructor(context: Context, attrs: Attribu private fun authenticate(creditCardInfo: CreditCardInfo) { val req = Payone.PreAuthRequest(creditCardInfo.pseudocardpan, creditCardInfo.lastname) val link = tokenizationData.links["preAuth"] - if (link != null) { + if (link != null && link.href != null) { val request = Request.Builder() .url(Snabble.getInstance().absoluteUrl(Snabble.getInstance().absoluteUrl(link.href))) .post(req.toJsonRequest()) From 4fd25648cf47e31464aafe77e6313ee5a506e9e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Kilczan?= Date: Thu, 17 Feb 2022 09:45:11 +0100 Subject: [PATCH 26/30] Fix imports and rarely formatting --- .../payment/AgeVerificationInputFragment.kt | 5 --- .../sdk/ui/payment/CreditCardInputFragment.kt | 3 -- .../sdk/ui/payment/PaydirektInputFragment.kt | 5 --- .../sdk/ui/payment/PaydirektInputView.java | 34 ++++++++-------- .../payment/PaymentCredentialsListFragment.kt | 4 -- .../sdk/ui/payment/PaymentInputViewHelper.kt | 10 ++--- .../sdk/ui/payment/PaymentMethodIcons.kt | 4 +- .../sdk/ui/payment/PaymentOptionsFragment.kt | 8 +--- .../sdk/ui/payment/PaymentOptionsView.kt | 11 +++-- .../java/io/snabble/sdk/ui/payment/Payone.kt | 3 +- .../sdk/ui/payment/PayoneInputFragment.kt | 3 -- .../snabble/sdk/ui/payment/PayoneInputView.kt | 40 ++++++++++--------- .../payment/ProjectPaymentOptionsFragment.kt | 3 -- .../ui/payment/ProjectPaymentOptionsView.kt | 15 +++---- .../sdk/ui/payment/SEPACardInputActivity.kt | 3 -- .../sdk/ui/payment/SEPACardInputFragment.kt | 4 -- .../sdk/ui/payment/SEPACardInputView.java | 4 +- .../payment/SelectPaymentMethodFragment.java | 4 +- 18 files changed, 66 insertions(+), 97 deletions(-) diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/AgeVerificationInputFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/AgeVerificationInputFragment.kt index e5423fe8c1..8fe8f3983b 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/AgeVerificationInputFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/AgeVerificationInputFragment.kt @@ -1,10 +1,5 @@ package io.snabble.sdk.ui.payment -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.Fragment import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/CreditCardInputFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/CreditCardInputFragment.kt index 3bf9f7f41e..e9f475eb91 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/CreditCardInputFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/CreditCardInputFragment.kt @@ -1,10 +1,7 @@ package io.snabble.sdk.ui.payment import android.os.Bundle -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.Fragment import io.snabble.sdk.PaymentMethod import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/PaydirektInputFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/PaydirektInputFragment.kt index 23d6ce0d7b..cad901931c 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/PaydirektInputFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/PaydirektInputFragment.kt @@ -1,10 +1,5 @@ package io.snabble.sdk.ui.payment -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.Fragment import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/PaydirektInputView.java b/ui/src/main/java/io/snabble/sdk/ui/payment/PaydirektInputView.java index 57f77b190d..fb0ecd2b1e 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/PaydirektInputView.java +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/PaydirektInputView.java @@ -194,26 +194,26 @@ private void load() { okHttpClient.newCall(request).enqueue( new SimpleJsonCallback(AuthorizationResult.class) { @Override - public void success(AuthorizationResult result) { - Dispatch.mainThread(() -> { - authorizationResult = result; - String webLink = result.getWebLink(); - if (webLink == null) { - finishWithError(); - return; + public void success(AuthorizationResult result) { + Dispatch.mainThread(() -> { + authorizationResult = result; + String webLink = result.getWebLink(); + if (webLink == null) { + finishWithError(); + return; + } + + webView.loadUrl(webLink); + }); } - webView.loadUrl(webLink); - }); - } - - @Override - public void error(Throwable t) { - Dispatch.mainThread(() -> { - finishWithError(); + @Override + public void error(Throwable t) { + Dispatch.mainThread(() -> { + finishWithError(); + }); + } }); - } - }); } private void authenticateAndSave() { diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentCredentialsListFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentCredentialsListFragment.kt index 782d774f61..b71295cff2 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentCredentialsListFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentCredentialsListFragment.kt @@ -1,16 +1,12 @@ package io.snabble.sdk.ui.payment import android.os.Bundle -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.Fragment import io.snabble.sdk.Project import io.snabble.sdk.Snabble import io.snabble.sdk.payment.PaymentCredentials import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R -import java.util.ArrayList open class PaymentCredentialsListFragment : BaseFragment( layoutResId = R.layout.snabble_fragment_payment_credentials_list, diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentInputViewHelper.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentInputViewHelper.kt index 587799193d..a04bf2b118 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentInputViewHelper.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentInputViewHelper.kt @@ -1,17 +1,17 @@ package io.snabble.sdk.ui.payment import android.content.Context -import io.snabble.sdk.PaymentMethod -import io.snabble.sdk.ui.SnabbleUI -import io.snabble.sdk.ui.utils.KeyguardUtils -import io.snabble.sdk.Snabble -import io.snabble.sdk.ui.utils.UIUtils import android.os.Bundle import androidx.appcompat.app.AlertDialog import androidx.fragment.app.FragmentActivity +import io.snabble.sdk.PaymentMethod import io.snabble.sdk.Project +import io.snabble.sdk.Snabble import io.snabble.sdk.payment.PaymentCredentials import io.snabble.sdk.ui.R +import io.snabble.sdk.ui.SnabbleUI +import io.snabble.sdk.ui.utils.KeyguardUtils +import io.snabble.sdk.ui.utils.UIUtils import io.snabble.sdk.utils.Logger object PaymentInputViewHelper { diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentMethodIcons.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentMethodIcons.kt index eb146bd4b8..205229924b 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentMethodIcons.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentMethodIcons.kt @@ -5,7 +5,7 @@ import io.snabble.sdk.PaymentMethodDescriptor import io.snabble.sdk.ui.R val PaymentMethodDescriptor.icon: Int - get() = when(id) { + get() = when (id) { PaymentMethod.QRCODE_POS.id -> R.drawable.snabble_ic_payment_select_pos PaymentMethod.QRCODE_OFFLINE.id -> R.drawable.snabble_ic_payment_select_pos PaymentMethod.DE_DIRECT_DEBIT.id -> R.drawable.snabble_ic_payment_select_sepa @@ -18,7 +18,7 @@ val PaymentMethodDescriptor.icon: Int PaymentMethod.GATEKEEPER_TERMINAL.id -> R.drawable.snabble_ic_payment_select_sco PaymentMethod.PAYDIREKT.id -> R.drawable.snabble_ic_payment_select_paydirekt PaymentMethod.GOOGLE_PAY.id -> R.drawable.snabble_ic_payment_select_gpay - "externalBilling" -> when(acceptedOriginTypes?.first()) { + "externalBilling" -> when (acceptedOriginTypes?.first()) { "tegutEmployeeID" -> R.drawable.snabble_ic_payment_select_tegut "leinweberCustomerID" -> R.drawable.snabble_ic_payment_select_leinweber else -> 0 diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentOptionsFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentOptionsFragment.kt index 34cc2e8529..2ef01470c5 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentOptionsFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentOptionsFragment.kt @@ -1,15 +1,9 @@ package io.snabble.sdk.ui.payment -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.Fragment import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R open class PaymentOptionsFragment : BaseFragment( layoutResId = R.layout.snabble_fragment_payment_options, waitForProject = false -) - +) \ No newline at end of file diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentOptionsView.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentOptionsView.kt index 56491d1cfd..b23a4eedbf 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentOptionsView.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentOptionsView.kt @@ -12,16 +12,19 @@ import android.widget.TextView import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleObserver import androidx.lifecycle.OnLifecycleEvent -import androidx.recyclerview.widget.* +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.ListAdapter +import androidx.recyclerview.widget.RecyclerView import io.snabble.sdk.Brand import io.snabble.sdk.Project import io.snabble.sdk.Snabble import io.snabble.sdk.payment.PaymentCredentialsStore import io.snabble.sdk.ui.R import io.snabble.sdk.ui.SnabbleUI -import io.snabble.sdk.ui.utils.* -import kotlin.collections.ArrayList -import kotlin.collections.HashMap +import io.snabble.sdk.ui.utils.executeUiAction +import io.snabble.sdk.ui.utils.getFragmentActivity +import io.snabble.sdk.ui.utils.loadAsset open class PaymentOptionsView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/Payone.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/Payone.kt index d3316ba7b1..fad83e8c1d 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/Payone.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/Payone.kt @@ -13,7 +13,8 @@ import io.snabble.sdk.utils.Dispatch import io.snabble.sdk.utils.Logger import io.snabble.sdk.utils.SimpleJsonCallback import kotlinx.parcelize.Parcelize -import okhttp3.* +import okhttp3.Callback +import okhttp3.Request object Payone { diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/PayoneInputFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/PayoneInputFragment.kt index 62c59d828f..f00523583d 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/PayoneInputFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/PayoneInputFragment.kt @@ -1,10 +1,7 @@ package io.snabble.sdk.ui.payment import android.os.Bundle -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.Fragment import io.snabble.sdk.PaymentMethod import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/PayoneInputView.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/PayoneInputView.kt index 14b404d922..209a553594 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/PayoneInputView.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/PayoneInputView.kt @@ -1,41 +1,45 @@ package io.snabble.sdk.ui.payment -import android.widget.FrameLayout -import android.widget.ProgressBar -import io.snabble.sdk.Project -import android.widget.TextView import android.annotation.SuppressLint -import io.snabble.sdk.ui.R -import io.snabble.sdk.ui.payment.Payone.PayoneTokenizationData -import androidx.lifecycle.Lifecycle -import io.snabble.sdk.Snabble -import io.snabble.sdk.payment.PaymentCredentials -import io.snabble.sdk.ui.telemetry.Telemetry -import io.snabble.sdk.ui.SnabbleUI import android.content.Context import android.content.pm.ApplicationInfo import android.content.res.Configuration import android.util.AttributeSet import android.webkit.* +import android.widget.FrameLayout +import android.widget.ProgressBar +import android.widget.TextView import android.widget.Toast import androidx.annotation.Keep import androidx.core.view.ViewCompat import androidx.core.view.isVisible +import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleObserver import androidx.lifecycle.OnLifecycleEvent import androidx.webkit.WebSettingsCompat import androidx.webkit.WebViewFeature import eu.rekisoft.android.util.LazyWorker import io.snabble.sdk.PaymentMethod +import io.snabble.sdk.Project +import io.snabble.sdk.Snabble +import io.snabble.sdk.payment.PaymentCredentials import io.snabble.sdk.ui.Keyguard +import io.snabble.sdk.ui.R +import io.snabble.sdk.ui.SnabbleUI +import io.snabble.sdk.ui.payment.Payone.PayoneTokenizationData +import io.snabble.sdk.ui.telemetry.Telemetry import io.snabble.sdk.ui.utils.UIUtils -import io.snabble.sdk.utils.* -import okhttp3.* +import io.snabble.sdk.utils.Dispatch +import io.snabble.sdk.utils.GsonHolder +import io.snabble.sdk.utils.Logger +import io.snabble.sdk.utils.SimpleJsonCallback +import okhttp3.Callback import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.Request +import okhttp3.RequestBody import okhttp3.RequestBody.Companion.toRequestBody import org.apache.commons.io.IOUtils import java.io.IOException -import java.lang.IllegalStateException import java.math.BigDecimal import java.nio.charset.Charset import java.text.NumberFormat @@ -135,7 +139,7 @@ class PayoneInputView @JvmOverloads constructor(context: Context, attrs: Attribu val url = uri.toString() Logger.d("shouldOverrideUrlLoading $url") lastPreAuthResponse?.links?.let { links -> - when(url) { + when (url) { links["redirectBack"]?.href -> finish() links["redirectError"]?.href -> finishWithError() links["redirectSuccess"]?.href -> polling.doNow() @@ -160,7 +164,7 @@ class PayoneInputView @JvmOverloads constructor(context: Context, attrs: Attribu val nightModeFlags = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK if (nightModeFlags == Configuration.UI_MODE_NIGHT_YES && WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) { // Force dark mode when in dark mode - WebSettingsCompat.setForceDark(webView.settings, WebSettingsCompat.FORCE_DARK_ON); + WebSettingsCompat.setForceDark(webView.settings, WebSettingsCompat.FORCE_DARK_ON) } if (context.applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE != 0) { WebView.setWebContentsDebuggingEnabled(true) @@ -183,7 +187,7 @@ class PayoneInputView @JvmOverloads constructor(context: Context, attrs: Attribu private fun loadForm() { try { - val ccType = when(paymentType) { + val ccType = when (paymentType) { PaymentMethod.AMEX -> "A" PaymentMethod.MASTERCARD -> "M" PaymentMethod.VISA -> "V" @@ -237,7 +241,7 @@ class PayoneInputView @JvmOverloads constructor(context: Context, attrs: Attribu } } - fun Any.toJsonRequest() : RequestBody = + fun Any.toJsonRequest(): RequestBody = GsonHolder.get().toJson(this).toRequestBody("application/json".toMediaTypeOrNull()) private fun authenticate(creditCardInfo: CreditCardInfo) { diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/ProjectPaymentOptionsFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/ProjectPaymentOptionsFragment.kt index 1884454060..ab43448823 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/ProjectPaymentOptionsFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/ProjectPaymentOptionsFragment.kt @@ -1,10 +1,7 @@ package io.snabble.sdk.ui.payment import android.os.Bundle -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.Fragment import io.snabble.sdk.Project import io.snabble.sdk.Snabble import io.snabble.sdk.ui.BaseFragment diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/ProjectPaymentOptionsView.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/ProjectPaymentOptionsView.kt index ce3bdd2fd5..4a40d65674 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/ProjectPaymentOptionsView.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/ProjectPaymentOptionsView.kt @@ -1,7 +1,6 @@ package io.snabble.sdk.ui.payment import android.content.Context -import android.os.Bundle import android.util.AttributeSet import android.view.LayoutInflater import android.view.View @@ -9,21 +8,19 @@ import android.view.ViewGroup import android.widget.FrameLayout import android.widget.ImageView import android.widget.TextView -import androidx.appcompat.app.AlertDialog -import androidx.fragment.app.FragmentActivity import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleObserver import androidx.lifecycle.OnLifecycleEvent -import androidx.recyclerview.widget.* -import io.snabble.sdk.PaymentMethod +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.ListAdapter +import androidx.recyclerview.widget.RecyclerView import io.snabble.sdk.Project import io.snabble.sdk.Snabble -import io.snabble.sdk.payment.PaymentCredentials import io.snabble.sdk.payment.PaymentCredentialsStore import io.snabble.sdk.ui.R -import io.snabble.sdk.ui.SnabbleUI -import io.snabble.sdk.ui.utils.* -import java.util.* +import io.snabble.sdk.ui.utils.getFragmentActivity +import io.snabble.sdk.ui.utils.loadAsset open class ProjectPaymentOptionsView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/SEPACardInputActivity.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/SEPACardInputActivity.kt index d89dadecab..e0d975c914 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/SEPACardInputActivity.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/SEPACardInputActivity.kt @@ -1,9 +1,6 @@ package io.snabble.sdk.ui.payment -import android.os.Bundle -import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.Fragment -import io.snabble.sdk.PaymentOriginCandidateHelper import io.snabble.sdk.ui.BaseFragmentActivity class SEPACardInputActivity : BaseFragmentActivity() { diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/SEPACardInputFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/SEPACardInputFragment.kt index 968d24077a..ec1cb2f127 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/SEPACardInputFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/SEPACardInputFragment.kt @@ -1,11 +1,7 @@ package io.snabble.sdk.ui.payment import android.os.Bundle -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.Fragment -import io.snabble.sdk.PaymentMethod import io.snabble.sdk.PaymentOriginCandidateHelper import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/SEPACardInputView.java b/ui/src/main/java/io/snabble/sdk/ui/payment/SEPACardInputView.java index cc1eff841d..3dd209078e 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/SEPACardInputView.java +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/SEPACardInputView.java @@ -228,7 +228,7 @@ private void saveCard() { final String name = nameInput.getText().toString(); final String iban = ibanCountryCode.getText().toString() + ibanInput.getText().toString().replace(" ", ""); - if(name.length() > 0) { + if (name.length() > 0) { nameTextInputLayout.setErrorEnabled(false); } else { nameTextInputLayout.setErrorEnabled(true); @@ -236,7 +236,7 @@ private void saveCard() { ok = false; } - if(IBAN.validate(iban)) { + if (IBAN.validate(iban)) { ibanTextInputLayout.setErrorEnabled(false); } else { ibanTextInputLayout.setErrorEnabled(true); diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/SelectPaymentMethodFragment.java b/ui/src/main/java/io/snabble/sdk/ui/payment/SelectPaymentMethodFragment.java index c671cbeec7..7e784ef536 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/SelectPaymentMethodFragment.java +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/SelectPaymentMethodFragment.java @@ -154,7 +154,7 @@ public void click() { return v; } - private String getUsableAtText(PaymentMethod...paymentMethods) { + private String getUsableAtText(PaymentMethod... paymentMethods) { List projects = Snabble.getInstance().getProjects(); if (projects.size() == 1) { return null; @@ -167,7 +167,7 @@ private String getUsableAtText(PaymentMethod...paymentMethods) { List availablePaymentMethods = project.getAvailablePaymentMethods(); for (PaymentMethod pm : paymentMethods) { if (availablePaymentMethods.contains(pm)) { - if (count > 0 ) { + if (count > 0) { sb.append(", "); } From 257cceadaab4e8ac36cc317451e008afd5654123 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Kilczan?= Date: Thu, 17 Feb 2022 11:56:02 +0100 Subject: [PATCH 27/30] Eliminate usage of Snabble.getInstance() in Kotlin code --- .../sdk/AcceptedLanguageInterceptor.kt | 4 ++-- core/src/main/java/io/snabble/sdk/Coupons.kt | 2 +- core/src/main/java/io/snabble/sdk/Snabble.kt | 5 ++-- .../sdk/checkin/CheckInLocationManager.kt | 2 +- .../io/snabble/sdk/checkin/CheckInManager.kt | 6 ++--- .../snabble/sdk/googlepay/GooglePayHelper.kt | 2 +- .../sdk/googlepay/GooglePayHelperActivity.kt | 2 +- .../java/io/snabble/sdk/CheckInManagerTest.kt | 24 +++++++++---------- .../io/snabble/sdk/sample/LoadingActivity.kt | 5 ++-- .../io/snabble/sdk/sample/MainActivity.kt | 2 +- .../io/snabble/sdk/ui/ProjectPersistence.kt | 16 ++++--------- .../io/snabble/sdk/ui/cart/CheckoutBar.kt | 2 +- .../sdk/ui/checkout/CheckoutActivity.kt | 4 ++-- .../sdk/ui/checkout/PaymentStatusView.kt | 2 +- .../io/snabble/sdk/ui/payment/Datatrans.kt | 4 ++-- .../payment/PaymentCredentialsListFragment.kt | 2 +- .../sdk/ui/payment/PaymentOptionsView.kt | 10 ++++---- .../java/io/snabble/sdk/ui/payment/Payone.kt | 2 +- .../snabble/sdk/ui/payment/PayoneInputView.kt | 13 +++++----- .../payment/ProjectPaymentOptionsFragment.kt | 2 +- .../ui/payment/ProjectPaymentOptionsView.kt | 6 ++--- .../snabble/sdk/ui/scanner/ProductResolver.kt | 4 ++-- 22 files changed, 55 insertions(+), 66 deletions(-) diff --git a/core/src/main/java/io/snabble/sdk/AcceptedLanguageInterceptor.kt b/core/src/main/java/io/snabble/sdk/AcceptedLanguageInterceptor.kt index 5e95ecc9c7..4537114529 100644 --- a/core/src/main/java/io/snabble/sdk/AcceptedLanguageInterceptor.kt +++ b/core/src/main/java/io/snabble/sdk/AcceptedLanguageInterceptor.kt @@ -28,8 +28,8 @@ class AcceptedLanguageInterceptor : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { var request: Request = chain.request() val url = request.url.toString() - val baseUrl = Snabble.getInstance().endpointBaseUrl - if (baseUrl != null && url.startsWith(baseUrl)) { + val baseUrl = Snabble.endpointBaseUrl + if (url.startsWith(baseUrl)) { request = request.newBuilder() .addHeader("Accept-Language", acceptedLanguagesHeader) .build() diff --git a/core/src/main/java/io/snabble/sdk/Coupons.kt b/core/src/main/java/io/snabble/sdk/Coupons.kt index 776f2626bf..8fc027f0ac 100644 --- a/core/src/main/java/io/snabble/sdk/Coupons.kt +++ b/core/src/main/java/io/snabble/sdk/Coupons.kt @@ -97,7 +97,7 @@ class Coupons ( } } project.urls["coupons"]?.let { path -> - val couponsUrl = Snabble.getInstance().absoluteUrl(path) ?: return + val couponsUrl = Snabble.absoluteUrl(path) isLoading.setAsap(true) val request = Request.Builder() diff --git a/core/src/main/java/io/snabble/sdk/Snabble.kt b/core/src/main/java/io/snabble/sdk/Snabble.kt index 943892561c..e682a6ac5f 100644 --- a/core/src/main/java/io/snabble/sdk/Snabble.kt +++ b/core/src/main/java/io/snabble/sdk/Snabble.kt @@ -34,9 +34,8 @@ import java.util.concurrent.atomic.AtomicBoolean object Snabble { @JvmStatic - fun getInstance() : Snabble { - return this - } + val instance: Snabble + get() = this @JvmStatic val version: String diff --git a/core/src/main/java/io/snabble/sdk/checkin/CheckInLocationManager.kt b/core/src/main/java/io/snabble/sdk/checkin/CheckInLocationManager.kt index 3d327d00cf..dcf4bb6d75 100644 --- a/core/src/main/java/io/snabble/sdk/checkin/CheckInLocationManager.kt +++ b/core/src/main/java/io/snabble/sdk/checkin/CheckInLocationManager.kt @@ -81,7 +81,7 @@ class CheckInLocationManager(val application: Application) { fun isLocationAvailable(): Boolean { return if (!checkLocationPermission()) { false - } else isEnabled(Snabble.getInstance().application) + } else isEnabled(Snabble.application) } /** diff --git a/core/src/main/java/io/snabble/sdk/checkin/CheckInManager.kt b/core/src/main/java/io/snabble/sdk/checkin/CheckInManager.kt index 4b9e7ef182..702210bca7 100644 --- a/core/src/main/java/io/snabble/sdk/checkin/CheckInManager.kt +++ b/core/src/main/java/io/snabble/sdk/checkin/CheckInManager.kt @@ -195,7 +195,7 @@ class CheckInManager(val snabble: Snabble, Dispatch.mainThread { locationManager.startTrackingLocation() locationManager.location.observeForever(locationObserver) - Snabble.getInstance().addOnMetadataUpdateListener(metadataListener) + Snabble.addOnMetadataUpdateListener(metadataListener) } } @@ -203,7 +203,7 @@ class CheckInManager(val snabble: Snabble, Dispatch.mainThread { locationManager.stopTrackingLocation() locationManager.location.removeObserver(locationObserver) - Snabble.getInstance().removeOnMetadataUpdateListener(metadataListener) + Snabble.removeOnMetadataUpdateListener(metadataListener) } } @@ -250,7 +250,7 @@ class CheckInManager(val snabble: Snabble, private fun updateShopProjectsMap() { - val projects = Snabble.getInstance().projects + val projects = Snabble.projects projectByShopId = projects.flatMap { project -> project.shops.map { it.id to project } }.toMap() } diff --git a/core/src/main/java/io/snabble/sdk/googlepay/GooglePayHelper.kt b/core/src/main/java/io/snabble/sdk/googlepay/GooglePayHelper.kt index dc676d0fc5..83549c6341 100644 --- a/core/src/main/java/io/snabble/sdk/googlepay/GooglePayHelper.kt +++ b/core/src/main/java/io/snabble/sdk/googlepay/GooglePayHelper.kt @@ -36,7 +36,7 @@ class GooglePayHelper( .setEnvironment(env) .build() - return Wallet.getPaymentsClient(Snabble.getInstance().application, walletOptions) + return Wallet.getPaymentsClient(Snabble.application, walletOptions) } fun setUseTestEnvironment(boolean: Boolean) { diff --git a/core/src/main/java/io/snabble/sdk/googlepay/GooglePayHelperActivity.kt b/core/src/main/java/io/snabble/sdk/googlepay/GooglePayHelperActivity.kt index e03f8b4da7..970371fff9 100644 --- a/core/src/main/java/io/snabble/sdk/googlepay/GooglePayHelperActivity.kt +++ b/core/src/main/java/io/snabble/sdk/googlepay/GooglePayHelperActivity.kt @@ -39,7 +39,7 @@ class GooglePayHelperActivity : AppCompatActivity() { private val googlePayHelper: GooglePayHelper? get() { val projectId = intent.getStringExtra(INTENT_EXTRA_PROJECT_ID) - val project = Snabble.getInstance().projects.firstOrNull { it.id == projectId } + val project = Snabble.projects.firstOrNull { it.id == projectId } if (project != null) { return project.googlePayHelper } diff --git a/core/src/test/java/io/snabble/sdk/CheckInManagerTest.kt b/core/src/test/java/io/snabble/sdk/CheckInManagerTest.kt index b687b928c1..4d02634560 100644 --- a/core/src/test/java/io/snabble/sdk/CheckInManagerTest.kt +++ b/core/src/test/java/io/snabble/sdk/CheckInManagerTest.kt @@ -43,14 +43,14 @@ class CheckInManagerTest : SnabbleSdkTest() { @Test fun testCheckIn() { - val checkInManager = Snabble.getInstance().checkInManager + val checkInManager = Snabble.checkInManager checkInManager.startUpdating() val listener = CheckInListener(checkInManager, onMultipleCandidatesAvailable = { countDown() }) - val locationManager = Snabble.getInstance().checkInLocationManager + val locationManager = Snabble.checkInLocationManager locationManager.mockLocation = locationSnabble listener.await() @@ -59,14 +59,14 @@ class CheckInManagerTest : SnabbleSdkTest() { @Test fun testCheckOutByDistanceAndTime() { - val checkInManager = Snabble.getInstance().checkInManager + val checkInManager = Snabble.checkInManager checkInManager.startUpdating() val listener = CheckInListener(checkInManager, onMultipleCandidatesAvailable = { countDown() }) - val locationManager = Snabble.getInstance().checkInLocationManager + val locationManager = Snabble.checkInLocationManager locationManager.mockLocation = locationSnabble listener.await() @@ -86,14 +86,14 @@ class CheckInManagerTest : SnabbleSdkTest() { @Test fun testStillCheckedInWhileInTimeWindow() { - val checkInManager = Snabble.getInstance().checkInManager + val checkInManager = Snabble.checkInManager checkInManager.startUpdating() val listener = CheckInListener(checkInManager, onMultipleCandidatesAvailable = { countDown() }) - val locationManager = Snabble.getInstance().checkInLocationManager + val locationManager = Snabble.checkInLocationManager locationManager.mockLocation = locationSnabble listener.await() @@ -115,14 +115,14 @@ class CheckInManagerTest : SnabbleSdkTest() { @Test fun testStillCheckedInWhileInCheckOutRadiusButNotInTimeWindow() { - val checkInManager = Snabble.getInstance().checkInManager + val checkInManager = Snabble.checkInManager checkInManager.startUpdating() val listener = CheckInListener(checkInManager, onMultipleCandidatesAvailable = { countDown() }) - val locationManager = Snabble.getInstance().checkInLocationManager + val locationManager = Snabble.checkInLocationManager locationManager.mockLocation = locationSnabble listener.await() @@ -146,14 +146,14 @@ class CheckInManagerTest : SnabbleSdkTest() { @Test fun testMultipleShopsAvailable() { - val checkInManager = Snabble.getInstance().checkInManager + val checkInManager = Snabble.checkInManager checkInManager.startUpdating() val listener = CheckInListener(checkInManager, onMultipleCandidatesAvailable = { countDown() }) - val locationManager = Snabble.getInstance().checkInLocationManager + val locationManager = Snabble.checkInLocationManager locationManager.mockLocation = locationSnabble listener.await() @@ -162,14 +162,14 @@ class CheckInManagerTest : SnabbleSdkTest() { @Test fun testMultipleShopsCheckIn() { - val checkInManager = Snabble.getInstance().checkInManager + val checkInManager = Snabble.checkInManager checkInManager.startUpdating() val listener = CheckInListener(checkInManager, onCheckIn = { countDown() }) - val locationManager = Snabble.getInstance().checkInLocationManager + val locationManager = Snabble.checkInLocationManager locationManager.mockLocation = locationSnabble listener.await() diff --git a/kotlin-sample/src/main/java/io/snabble/sdk/sample/LoadingActivity.kt b/kotlin-sample/src/main/java/io/snabble/sdk/sample/LoadingActivity.kt index ea71d15316..ee4fcb1157 100644 --- a/kotlin-sample/src/main/java/io/snabble/sdk/sample/LoadingActivity.kt +++ b/kotlin-sample/src/main/java/io/snabble/sdk/sample/LoadingActivity.kt @@ -26,11 +26,10 @@ class LoadingActivity : AppCompatActivity() { Snabble.setDebugLoggingEnabled(BuildConfig.DEBUG) - val snabble = Snabble.getInstance() - snabble.setup(application, config, object : Snabble.SetupCompletionListener { + Snabble.setup(application, config, object : Snabble.SetupCompletionListener { override fun onReady() { // an application can have multiple projects - val project = snabble.projects.first() + val project = Snabble.projects.first() SnabbleUI.project = project project.checkedInShop = project.shops.first() diff --git a/kotlin-sample/src/main/java/io/snabble/sdk/sample/MainActivity.kt b/kotlin-sample/src/main/java/io/snabble/sdk/sample/MainActivity.kt index d7bdea7869..7101d45a53 100644 --- a/kotlin-sample/src/main/java/io/snabble/sdk/sample/MainActivity.kt +++ b/kotlin-sample/src/main/java/io/snabble/sdk/sample/MainActivity.kt @@ -23,7 +23,7 @@ class MainActivity : AppCompatActivity() { super.onCreate(savedInstanceState) // for simplicity sake we are reloading the whole application on state loss - if (Snabble.getInstance().application == null) { + if (Snabble.application == null) { startActivity(Intent(this, LoadingActivity::class.java)) finish() } else { diff --git a/ui/src/main/java/io/snabble/sdk/ui/ProjectPersistence.kt b/ui/src/main/java/io/snabble/sdk/ui/ProjectPersistence.kt index 6c120be2a6..665fa69bc8 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/ProjectPersistence.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/ProjectPersistence.kt @@ -11,8 +11,7 @@ import io.snabble.sdk.utils.Dispatch import java.util.concurrent.atomic.AtomicBoolean internal object ProjectPersistence { - private val snabble = Snabble.getInstance() - private var application = snabble.application + private var application = Snabble.application private val sharedPreferences: SharedPreferences = application.getSharedPreferences("snabble_ui_persistence", Context.MODE_PRIVATE) val projectAsLiveData = MutableLiveData() @@ -20,15 +19,8 @@ internal object ProjectPersistence { init { Dispatch.mainThread { - snabble.initializationState.observeForever { - update() - } - - snabble.addOnMetadataUpdateListener(object : Snabble.OnMetadataUpdateListener { - override fun onMetaDataUpdated() { - update() - } - }) + Snabble.initializationState.observeForever { update() } + Snabble.addOnMetadataUpdateListener { update() } } } @@ -39,7 +31,7 @@ internal object ProjectPersistence { } private fun update() { - val p = snabble.projects.find { + val p = Snabble.projects.find { it.id == sharedPreferences.getString("id", null) } project = p diff --git a/ui/src/main/java/io/snabble/sdk/ui/cart/CheckoutBar.kt b/ui/src/main/java/io/snabble/sdk/ui/cart/CheckoutBar.kt index 61178f8a81..a38939cf79 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/cart/CheckoutBar.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/cart/CheckoutBar.kt @@ -150,7 +150,7 @@ open class CheckoutBar @JvmOverloads constructor( if (entry == null) { binding.paymentSelector.visibility = GONE } else { - val pcs = Snabble.getInstance().paymentCredentialsStore + val pcs = Snabble.paymentCredentialsStore val hasNoPaymentMethods = pcs.usablePaymentCredentialsCount == 0 val isHidden = project.paymentMethodDescriptors.size == 1 && hasNoPaymentMethods binding.paymentSelector.isVisible = !isHidden diff --git a/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutActivity.kt b/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutActivity.kt index 91ce333319..18d0743424 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutActivity.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutActivity.kt @@ -50,7 +50,7 @@ class CheckoutActivity : FragmentActivity() { navGraph = graphInflater.inflate(R.navigation.snabble_nav_checkout) navController = navHostFragment.navController - Snabble.getInstance().initializationState.observe(this) { + Snabble.initializationState.observe(this) { when(it) { InitializationState.INITIALIZED -> { val projectId = intent.getStringExtra(ARG_PROJECT_ID) @@ -59,7 +59,7 @@ class CheckoutActivity : FragmentActivity() { return@observe } - val project = Snabble.getInstance().getProjectById(projectId) + val project = Snabble.getProjectById(projectId) if (project == null) { finishWithError("Project with id $projectId not found") return@observe diff --git a/ui/src/main/java/io/snabble/sdk/ui/checkout/PaymentStatusView.kt b/ui/src/main/java/io/snabble/sdk/ui/checkout/PaymentStatusView.kt index d1d4797f59..58aaaea560 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/checkout/PaymentStatusView.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/checkout/PaymentStatusView.kt @@ -306,7 +306,7 @@ class PaymentStatusView @JvmOverloads constructor( return } - val receipts = Snabble.getInstance().receipts + val receipts = Snabble.receipts receipts.getReceiptInfos(object : Receipts.ReceiptInfoCallback { override fun success(receiptInfos: Array?) { val receipt = receiptInfos?.filter { it.id == orderId }?.firstOrNull() diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/Datatrans.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/Datatrans.kt index 999d4637aa..09bc905033 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/Datatrans.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/Datatrans.kt @@ -63,7 +63,7 @@ object Datatrans { } val request: Request = Request.Builder() - .url(Snabble.getInstance().absoluteUrl(url.href)) + .url(Snabble.absoluteUrl(url.href)) .post(GsonHolder.get().toJson( DatatransTokenizationRequest(paymentMethod) ).toRequestBody("application/json".toMediaType())) @@ -133,7 +133,7 @@ object Datatrans { if (token != null) { Keyguard.unlock(activity, object : Keyguard.Callback { override fun success() { - val store = Snabble.getInstance().paymentCredentialsStore + val store = Snabble.paymentCredentialsStore val credentials = PaymentCredentials.fromDatatrans( token.alias, PaymentCredentials.Brand.fromPaymentMethod(paymentMethod), diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentCredentialsListFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentCredentialsListFragment.kt index b71295cff2..ed3950dc90 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentCredentialsListFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentCredentialsListFragment.kt @@ -24,7 +24,7 @@ open class PaymentCredentialsListFragment : BaseFragment( super.onCreate(savedInstanceState) type = arguments?.getSerializable(ARG_PAYMENT_TYPE) as ArrayList? val projectId = arguments?.getString(ARG_PROJECT_ID) - project = Snabble.getInstance().projects.firstOrNull { it.id == projectId } + project = Snabble.projects.firstOrNull { it.id == projectId } } override fun onActualViewCreated(view: View, savedInstanceState: Bundle?) { diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentOptionsView.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentOptionsView.kt index b23a4eedbf..d08fceeac7 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentOptionsView.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentOptionsView.kt @@ -44,7 +44,7 @@ open class PaymentOptionsView @JvmOverloads constructor( adapter.submitList(getEntries()) } - Snabble.getInstance().paymentCredentialsStore.addCallback(listener) + Snabble.paymentCredentialsStore.addCallback(listener) getFragmentActivity()?.lifecycle?.addObserver(object : LifecycleObserver { @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) @@ -55,21 +55,21 @@ open class PaymentOptionsView @JvmOverloads constructor( @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) fun onDestroy() { getFragmentActivity()?.lifecycle?.removeObserver(this) - Snabble.getInstance().paymentCredentialsStore.removeCallback(listener) + Snabble.paymentCredentialsStore.removeCallback(listener) } }) } private fun getEntries(): List { - val projects = Snabble.getInstance().projects.filter { project -> + val projects = Snabble.projects.filter { project -> project.availablePaymentMethods.count { it.isRequiringCredentials } > 0 } val projectList = ArrayList() - val store = Snabble.getInstance().paymentCredentialsStore + val store = Snabble.paymentCredentialsStore projects.filter { it.brand == null } - .forEachIndexed { i, project -> + .forEach { project -> val count = store.getCountForProject(project) projectList.add( diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/Payone.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/Payone.kt index fad83e8c1d..8ccb4cbe59 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/Payone.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/Payone.kt @@ -84,7 +84,7 @@ object Payone { } val request: Request = Request.Builder() - .url(Snabble.getInstance().absoluteUrl(url.href)) + .url(Snabble.absoluteUrl(url.href)) .build() project.okHttpClient.newCall(request).enqueue(object : SimpleJsonCallback(PayoneTokenizationData::class.java), Callback { diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/PayoneInputView.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/PayoneInputView.kt index 209a553594..f594fc6e39 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/PayoneInputView.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/PayoneInputView.kt @@ -59,7 +59,7 @@ class PayoneInputView @JvmOverloads constructor(context: Context, attrs: Attribu private var polling = LazyWorker.createLifeCycleAwareJob(context) { lastPreAuthResponse?.links?.get("preAuthStatus")?.href?.let { statusUrl -> val request = Request.Builder() - .url(Snabble.getInstance().absoluteUrl(Snabble.getInstance().absoluteUrl(statusUrl))) + .url(Snabble.absoluteUrl(Snabble.absoluteUrl(statusUrl))) .build() project.okHttpClient.newCall(request).enqueue(object : SimpleJsonCallback(Payone.PreAuthResponse::class.java), @@ -176,7 +176,7 @@ class PayoneInputView @JvmOverloads constructor(context: Context, attrs: Attribu paymentType: PaymentMethod, tokenizationData: PayoneTokenizationData ) { - this.project = Snabble.getInstance().projects.first { it.id == projectId } + this.project = Snabble.projects.first { it.id == projectId } this.paymentType = paymentType this.tokenizationData = tokenizationData inflateView() @@ -247,10 +247,10 @@ class PayoneInputView @JvmOverloads constructor(context: Context, attrs: Attribu private fun authenticate(creditCardInfo: CreditCardInfo) { val req = Payone.PreAuthRequest(creditCardInfo.pseudocardpan, creditCardInfo.lastname) val link = tokenizationData.links["preAuth"] - if (link != null && link.href != null) { + if (link?.href != null) { val request = Request.Builder() - .url(Snabble.getInstance().absoluteUrl(Snabble.getInstance().absoluteUrl(link.href))) - .post(req.toJsonRequest()) + .url(Snabble.absoluteUrl(Snabble.absoluteUrl(link.href))) + .post(req.toJsonRequest()) .build() project.okHttpClient.newCall(request).enqueue(object : @@ -278,7 +278,6 @@ class PayoneInputView @JvmOverloads constructor(context: Context, attrs: Attribu } } - private fun authenticateAndSave(creditCardInfo: CreditCardInfo) { Keyguard.unlock(UIUtils.getHostFragmentActivity(context), object : Keyguard.Callback { override fun success() { @@ -313,7 +312,7 @@ class PayoneInputView @JvmOverloads constructor(context: Context, attrs: Attribu Toast.makeText(context, "Could not verify payment credentials", Toast.LENGTH_LONG) .show() } else { - Snabble.getInstance().paymentCredentialsStore.add(pc) + Snabble.paymentCredentialsStore.add(pc) Telemetry.event(Telemetry.Event.PaymentMethodAdded, pc.type.name) } finish() diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/ProjectPaymentOptionsFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/ProjectPaymentOptionsFragment.kt index ab43448823..9de17bd108 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/ProjectPaymentOptionsFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/ProjectPaymentOptionsFragment.kt @@ -29,7 +29,7 @@ open class ProjectPaymentOptionsFragment : BaseFragment( val v = view as ProjectPaymentOptionsView brand?.let { brand -> val projects = ArrayList() - Snabble.getInstance().projects.forEach { project -> + Snabble.projects.forEach { project -> if (project.brand?.id == brand) { projects.add(project) } diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/ProjectPaymentOptionsView.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/ProjectPaymentOptionsView.kt index 4a40d65674..293fcc621c 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/ProjectPaymentOptionsView.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/ProjectPaymentOptionsView.kt @@ -50,7 +50,7 @@ open class ProjectPaymentOptionsView @JvmOverloads constructor( adapter.notifyDataSetChanged() } - Snabble.getInstance().paymentCredentialsStore.addCallback(listener) + Snabble.paymentCredentialsStore.addCallback(listener) getFragmentActivity()?.lifecycle?.addObserver(object : LifecycleObserver { @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) @@ -61,7 +61,7 @@ open class ProjectPaymentOptionsView @JvmOverloads constructor( @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) fun onDestroy() { getFragmentActivity()?.lifecycle?.removeObserver(this) - Snabble.getInstance().paymentCredentialsStore.removeCallback(listener) + Snabble.paymentCredentialsStore.removeCallback(listener) } }) } @@ -83,7 +83,7 @@ open class ProjectPaymentOptionsView @JvmOverloads constructor( holder.text.text = project.name holder.image.loadAsset(project.assets, "icon") - val store = Snabble.getInstance().paymentCredentialsStore + val store = Snabble.paymentCredentialsStore val count = store.getCountForProject(project) if (count > 0) { diff --git a/ui/src/main/java/io/snabble/sdk/ui/scanner/ProductResolver.kt b/ui/src/main/java/io/snabble/sdk/ui/scanner/ProductResolver.kt index 476d8f382f..66b790f805 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/scanner/ProductResolver.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/scanner/ProductResolver.kt @@ -43,10 +43,10 @@ class ProductResolver private constructor(private val context: Context, private private fun checkMinAge(product: Product) { if (product.saleRestriction.isAgeRestriction) { val minAge = product.saleRestriction.value - val birthday = Snabble.getInstance().userPreferences.birthday + val birthday = Snabble.userPreferences.birthday var isOldEnough = false if (birthday != null) { - val age = Age.calculateAge(Snabble.getInstance().userPreferences.birthday) + val age = Age.calculateAge(Snabble.userPreferences.birthday) if (age.years >= minAge) { isOldEnough = true } From d99d0e19081a40eb681df028d1759acc0f954364 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Kilczan?= Date: Thu, 17 Feb 2022 12:32:28 +0100 Subject: [PATCH 28/30] Optimize imports and small formatting issues --- .../java/io/snabble/sdk/ui/BaseFragment.kt | 2 +- .../java/io/snabble/sdk/ui/GestureHandler.kt | 25 +++++--- .../io/snabble/sdk/ui/ProjectPersistence.kt | 3 - .../main/java/io/snabble/sdk/ui/SnabbleUI.kt | 24 +++++--- .../io/snabble/sdk/ui/cart/CheckoutBar.kt | 21 ++++--- .../sdk/ui/cart/PaymentSelectionHelper.java | 10 ++- .../sdk/ui/cart/ShoppingCartFragment.kt | 7 ++- .../snabble/sdk/ui/cart/ShoppingCartView.java | 8 +-- .../sdk/ui/checkout/CheckoutActivity.kt | 5 +- .../checkout/CheckoutCustomerCardFragment.kt | 5 -- .../snabble/sdk/ui/checkout/CheckoutHelper.kt | 2 +- .../ui/checkout/CheckoutOfflineFragment.kt | 5 -- .../sdk/ui/checkout/CheckoutOfflineView.java | 4 +- .../sdk/ui/checkout/CheckoutPOSFragment.kt | 5 -- .../sdk/ui/checkout/PaymentStatusFragment.kt | 5 -- .../sdk/ui/checkout/PaymentStatusItemView.kt | 12 ---- .../sdk/ui/checkout/PaymentStatusView.kt | 41 +++++++------ .../RoutingTargetGatekeeperFragment.kt | 5 -- .../RoutingTargetGatekeeperView.kt | 29 +++++---- .../RoutingTargetSupervisorFragment.kt | 5 -- .../RoutingTargetSupervisorView.kt | 29 +++++---- .../sdk/ui/payment/CreditCardInputView.java | 2 +- .../io/snabble/sdk/ui/payment/Datatrans.kt | 5 +- .../sdk/ui/payment/PaymentOptionsView.kt | 56 +++++++++-------- .../sdk/ui/payment/SEPACardInputView.java | 4 +- .../sdk/ui/scanner/BarcodeScannerView.kt | 6 +- .../snabble/sdk/ui/scanner/BarcodeView.java | 2 +- .../sdk/ui/scanner/FalsePositiveFilter.java | 1 + .../ui/scanner/ProductConfirmationDialog.java | 4 +- .../snabble/sdk/ui/scanner/ProductResolver.kt | 61 ++++++++++--------- .../SelectReducedPriceDialogFragment.kt | 3 +- .../sdk/ui/scanner/SelfScanningFragment.kt | 6 +- .../sdk/ui/scanner/SelfScanningView.java | 6 +- .../snabble/sdk/ui/scanner/ZXingHelper.java | 2 +- .../sdk/ui/search/ProductSearchFragment.kt | 3 - .../sdk/ui/search/SearchableProductAdapter.kt | 3 +- .../snabble/sdk/ui/utils/KotlinExtensions.kt | 2 +- .../java/io/snabble/sdk/ui/utils/UIUtils.java | 14 +++-- .../io/snabble/sdk/ui/views/MessageBox.kt | 6 +- 39 files changed, 217 insertions(+), 221 deletions(-) diff --git a/ui/src/main/java/io/snabble/sdk/ui/BaseFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/BaseFragment.kt index ece89fe5c9..cca0e95921 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/BaseFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/BaseFragment.kt @@ -30,7 +30,7 @@ abstract class BaseFragment(@LayoutRes val layoutResId: Int = 0, val waitForProj sdkNotInitialized = view.findViewById(R.id.sdk_not_initialized) Snabble.initializationState.observe(viewLifecycleOwner) { - when(it) { + when (it) { InitializationState.INITIALIZED -> { waitForProjectAndAdd(savedInstanceState) } diff --git a/ui/src/main/java/io/snabble/sdk/ui/GestureHandler.kt b/ui/src/main/java/io/snabble/sdk/ui/GestureHandler.kt index 08d3b7ed34..83b5bbe844 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/GestureHandler.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/GestureHandler.kt @@ -46,14 +46,15 @@ abstract class GestureHandler(resources: Resources) : ItemTouchHelper.SimpleC get() = (adapter as? SortableAdapter)?.sortMode ?: false override fun getDragDirs(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) = - if (recyclerView.isInSortMode) ItemTouchHelper.UP + ItemTouchHelper.DOWN else 0 + if (recyclerView.isInSortMode) ItemTouchHelper.UP + ItemTouchHelper.DOWN else 0 override fun getSwipeDirs(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) = - if (recyclerView.isInSortMode) 0 else ItemTouchHelper.LEFT + ItemTouchHelper.RIGHT + if (recyclerView.isInSortMode) 0 else ItemTouchHelper.LEFT + ItemTouchHelper.RIGHT - override fun onMove(recyclerView: RecyclerView, - viewHolder: RecyclerView.ViewHolder, - target: RecyclerView.ViewHolder + override fun onMove( + recyclerView: RecyclerView, + viewHolder: RecyclerView.ViewHolder, + target: RecyclerView.ViewHolder ): Boolean { val adapter = recyclerView.adapter as SortableAdapter val from = viewHolder.bindingAdapterPosition @@ -63,7 +64,15 @@ abstract class GestureHandler(resources: Resources) : ItemTouchHelper.SimpleC } // based on https://stackoverflow.com/a/45565493/995926 - override fun onChildDraw(c: Canvas, recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, dX: Float, dY: Float, actionState: Int, isCurrentlyActive: Boolean) { + override fun onChildDraw( + c: Canvas, + recyclerView: RecyclerView, + viewHolder: RecyclerView.ViewHolder, + dX: Float, + dY: Float, + actionState: Int, + isCurrentlyActive: Boolean + ) { if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) { val itemView = viewHolder.itemView val height = itemView.bottom.toFloat() - itemView.top.toFloat() @@ -83,7 +92,7 @@ abstract class GestureHandler(resources: Resources) : ItemTouchHelper.SimpleC itemView.bottom - width ) c.drawBitmap(icon, null, iconDest, paint) - } else if(dX > 0) { + } else if (dX > 0) { val background = Rect( itemView.left, itemView.top, itemView.left + dX.toInt(), itemView.bottom @@ -112,7 +121,7 @@ abstract class GestureHandler(resources: Resources) : ItemTouchHelper.SimpleC viewHolder: RecyclerView.ViewHolder ): Int { val adapter = recyclerView.adapter as? DismissibleAdapter - return if(viewHolder.bindingAdapterPosition >= 0 && adapter?.isDismissible(viewHolder.bindingAdapterPosition) == false) { + return if (viewHolder.bindingAdapterPosition >= 0 && adapter?.isDismissible(viewHolder.bindingAdapterPosition) == false) { 0 } else { super.getMovementFlags(recyclerView, viewHolder) diff --git a/ui/src/main/java/io/snabble/sdk/ui/ProjectPersistence.kt b/ui/src/main/java/io/snabble/sdk/ui/ProjectPersistence.kt index 665fa69bc8..b10c360910 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/ProjectPersistence.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/ProjectPersistence.kt @@ -1,14 +1,11 @@ package io.snabble.sdk.ui -import android.annotation.SuppressLint -import android.app.Application import android.content.Context import android.content.SharedPreferences import androidx.lifecycle.MutableLiveData import io.snabble.sdk.Project import io.snabble.sdk.Snabble import io.snabble.sdk.utils.Dispatch -import java.util.concurrent.atomic.AtomicBoolean internal object ProjectPersistence { private var application = Snabble.application diff --git a/ui/src/main/java/io/snabble/sdk/ui/SnabbleUI.kt b/ui/src/main/java/io/snabble/sdk/ui/SnabbleUI.kt index 430e3f52b0..40caf293ac 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/SnabbleUI.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/SnabbleUI.kt @@ -2,11 +2,13 @@ package io.snabble.sdk.ui import android.content.Context import android.content.Intent -import io.snabble.sdk.Project -import kotlin.jvm.JvmOverloads import android.os.Bundle import androidx.appcompat.app.AppCompatActivity -import androidx.lifecycle.* +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleObserver +import androidx.lifecycle.LiveData +import androidx.lifecycle.OnLifecycleEvent +import io.snabble.sdk.Project import io.snabble.sdk.ui.SnabbleUI.Event.* import io.snabble.sdk.ui.cart.ShoppingCartActivity import io.snabble.sdk.ui.checkout.CheckoutActivity @@ -15,6 +17,10 @@ import io.snabble.sdk.ui.scanner.SelfScanningActivity import io.snabble.sdk.ui.search.ProductSearchActivity import io.snabble.sdk.ui.utils.UIUtils import java.lang.ref.WeakReference +import kotlin.collections.get +import kotlin.collections.mutableMapOf +import kotlin.collections.remove +import kotlin.collections.set /*** * The heart of the snabble UI components where everything connects. @@ -114,7 +120,7 @@ object SnabbleUI { actions.remove(event) } } else { - when(event) { + when (event) { SHOW_CHECKOUT -> CheckoutActivity.startCheckoutFlow(context, args) SHOW_SCANNER -> startActivity(context, SelfScanningActivity::class.java, args, canGoBack = true, @@ -145,10 +151,12 @@ object SnabbleUI { } } - internal fun startActivity(context: Context, - clazz: Class, args: Bundle?, - canGoBack: Boolean = true, - unique: Boolean = false) { + internal fun startActivity( + context: Context, + clazz: Class, args: Bundle?, + canGoBack: Boolean = true, + unique: Boolean = false + ) { val intent = Intent(context, clazz) if (args != null) { diff --git a/ui/src/main/java/io/snabble/sdk/ui/cart/CheckoutBar.kt b/ui/src/main/java/io/snabble/sdk/ui/cart/CheckoutBar.kt index a38939cf79..e8d8161ee8 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/cart/CheckoutBar.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/cart/CheckoutBar.kt @@ -11,7 +11,9 @@ import android.os.Bundle import android.util.AttributeSet import android.view.KeyEvent import android.view.LayoutInflater -import android.widget.* +import android.widget.ArrayAdapter +import android.widget.LinearLayout +import android.widget.Toast import androidx.appcompat.app.AlertDialog import androidx.core.view.isVisible import androidx.core.view.marginTop @@ -19,7 +21,10 @@ import androidx.fragment.app.FragmentActivity import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleObserver import androidx.lifecycle.OnLifecycleEvent -import io.snabble.sdk.* +import io.snabble.sdk.Checkout +import io.snabble.sdk.PaymentMethod +import io.snabble.sdk.ShoppingCart +import io.snabble.sdk.Snabble import io.snabble.sdk.ui.Keyguard import io.snabble.sdk.ui.R import io.snabble.sdk.ui.SnabbleUI @@ -37,9 +42,9 @@ open class CheckoutBar @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : LinearLayout(context, attrs, defStyleAttr), Checkout.OnCheckoutStateChangedListener { private lateinit var progressDialog: DelayedProgressDialog - + private val binding: SnabbleViewCheckoutBarBinding - + private val paymentSelectionHelper by lazy { PaymentSelectionHelper.getInstance() } private val project by lazy { SnabbleUI.project } private val cart: ShoppingCart by lazy { project.shoppingCart } @@ -53,7 +58,7 @@ open class CheckoutBar @JvmOverloads constructor( init { LayoutInflater.from(context).inflate(R.layout.snabble_view_checkout_bar, this, true) binding = SnabbleViewCheckoutBarBinding.bind(this) - + orientation = VERTICAL if (!isInEditMode) { @@ -62,9 +67,9 @@ open class CheckoutBar @JvmOverloads constructor( } private fun initBusinessLogic() { - paymentSelectionHelper.selectedEntry.observe(UIUtils.getHostActivity(context) as FragmentActivity, { + paymentSelectionHelper.selectedEntry.observe(UIUtils.getHostActivity(context) as FragmentActivity) { update() - }) + } binding.paymentSelectorButton.setOnClickListener { paymentSelectionHelper.showDialog(UIUtils.getHostFragmentActivity(context)) @@ -268,7 +273,7 @@ open class CheckoutBar @JvmOverloads constructor( } override fun onStateChanged(state: Checkout.State) { - when(state) { + when (state) { Checkout.State.HANDSHAKING -> { progressDialog.showAfterDelay(300) } diff --git a/ui/src/main/java/io/snabble/sdk/ui/cart/PaymentSelectionHelper.java b/ui/src/main/java/io/snabble/sdk/ui/cart/PaymentSelectionHelper.java index 5b0150bede..c78188f113 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/cart/PaymentSelectionHelper.java +++ b/ui/src/main/java/io/snabble/sdk/ui/cart/PaymentSelectionHelper.java @@ -21,7 +21,11 @@ import java.util.Map; import java.util.Set; -import io.snabble.sdk.*; +import io.snabble.sdk.CheckoutApi; +import io.snabble.sdk.PaymentMethod; +import io.snabble.sdk.Project; +import io.snabble.sdk.ShoppingCart; +import io.snabble.sdk.Snabble; import io.snabble.sdk.googlepay.GooglePayHelper; import io.snabble.sdk.payment.PaymentCredentials; import io.snabble.sdk.payment.PaymentCredentialsStore; @@ -302,7 +306,7 @@ private void updateEntries() { List availablePaymentMethodsList = new ArrayList<>(); for (final CheckoutApi.PaymentMethodInfo paymentMethodInfo : availablePaymentMethods) { String[] origins = paymentMethodInfo.acceptedOriginTypes; - if(origins == null) origins = new String[0]; + if (origins == null) origins = new String[0]; PaymentMethod paymentMethod = PaymentMethod.fromIdAndOrigin(paymentMethodInfo.id, Arrays.asList(origins)); if (paymentMethod == PaymentMethod.GOOGLE_PAY && googlePayIsReady) { availablePaymentMethodsList.add(paymentMethod); @@ -334,7 +338,7 @@ private void updateEntries() { if (availablePaymentMethodsList.contains(e.paymentMethod)) { e.isAvailable = true; e.hint = pc.getObfuscatedId(); - } else if (projectPaymentMethods.contains(e.paymentMethod)){ + } else if (projectPaymentMethods.contains(e.paymentMethod)) { e.hint = application.getString(R.string.Snabble_Shoppingcart_notForThisPurchase); e.isAvailable = false; } else { diff --git a/ui/src/main/java/io/snabble/sdk/ui/cart/ShoppingCartFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/cart/ShoppingCartFragment.kt index 80c4c01465..c51367afe4 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/cart/ShoppingCartFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/cart/ShoppingCartFragment.kt @@ -1,10 +1,13 @@ package io.snabble.sdk.ui.cart import android.os.Bundle -import io.snabble.sdk.ui.R -import android.view.* +import android.view.Menu +import android.view.MenuInflater +import android.view.MenuItem +import android.view.View import androidx.appcompat.app.AlertDialog import io.snabble.sdk.ui.BaseFragment +import io.snabble.sdk.ui.R import io.snabble.sdk.ui.SnabbleUI open class ShoppingCartFragment : BaseFragment(R.layout.snabble_fragment_shoppingcart) { diff --git a/ui/src/main/java/io/snabble/sdk/ui/cart/ShoppingCartView.java b/ui/src/main/java/io/snabble/sdk/ui/cart/ShoppingCartView.java index ae67f55df1..11ad636fd4 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/cart/ShoppingCartView.java +++ b/ui/src/main/java/io/snabble/sdk/ui/cart/ShoppingCartView.java @@ -134,7 +134,7 @@ public ShoppingCartView(Context context, AttributeSet attrs, int defStyleAttr) { private void inflateView(Context context, AttributeSet attrs) { inflate(getContext(), R.layout.snabble_view_shopping_cart, this); - if(isInEditMode()) return; + if (isInEditMode()) return; final Project project = SnabbleUI.getProject(); if (cart != null) { @@ -175,7 +175,7 @@ private void inflateView(Context context, AttributeSet attrs) { PaymentSelectionHelper .getInstance() .getSelectedEntry() - .observe((FragmentActivity)UIUtils.getHostActivity(getContext()), entry -> update()); + .observe((FragmentActivity) UIUtils.getHostActivity(getContext()), entry -> update()); createItemTouchHelper(context.getResources()); submitList(); @@ -240,7 +240,7 @@ private void checkSaleStop() { sb.append("\n\n"); - for(Product product : invalidProducts) { + for (Product product : invalidProducts) { if (product.getSubtitle() != null) { sb.append(product.getSubtitle()); sb.append(" "); @@ -310,7 +310,7 @@ private void unregisterListeners() { public void onAttachedToWindow() { super.onAttachedToWindow(); - if(!isInEditMode()) { + if (!isInEditMode()) { Application application = (Application) getContext().getApplicationContext(); application.registerActivityLifecycleCallbacks(activityLifecycleCallbacks); diff --git a/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutActivity.kt b/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutActivity.kt index 18d0743424..8bbe0a5445 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutActivity.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutActivity.kt @@ -10,7 +10,6 @@ import androidx.navigation.NavOptions import androidx.navigation.fragment.NavHostFragment import io.snabble.sdk.* import io.snabble.sdk.ui.R -import io.snabble.sdk.ui.SnabbleUI import io.snabble.sdk.utils.Logger class CheckoutActivity : FragmentActivity() { @@ -51,7 +50,7 @@ class CheckoutActivity : FragmentActivity() { navController = navHostFragment.navController Snabble.initializationState.observe(this) { - when(it) { + when (it) { InitializationState.INITIALIZED -> { val projectId = intent.getStringExtra(ARG_PROJECT_ID) if (projectId == null) { @@ -100,7 +99,7 @@ class CheckoutActivity : FragmentActivity() { private fun getNavigationId(): Int? { val checkout = checkout ?: return null - return when(checkout.state) { + return when (checkout.state) { Checkout.State.WAIT_FOR_GATEKEEPER -> { R.id.snabble_nav_routing_gatekeeper } diff --git a/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutCustomerCardFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutCustomerCardFragment.kt index 47d69ef7c4..d70d0fbd4d 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutCustomerCardFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutCustomerCardFragment.kt @@ -1,10 +1,5 @@ package io.snabble.sdk.ui.checkout -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.Fragment import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R diff --git a/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutHelper.kt b/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutHelper.kt index 1b0e004ad1..43ab61b90a 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutHelper.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutHelper.kt @@ -3,7 +3,7 @@ package io.snabble.sdk.ui.checkout import io.snabble.sdk.Checkout val Checkout.State.isCheckoutState: Boolean - get() = when(this) { + get() = when (this) { Checkout.State.NONE, Checkout.State.HANDSHAKING, Checkout.State.REQUEST_PAYMENT_METHOD, diff --git a/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutOfflineFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutOfflineFragment.kt index dc0e835f64..3745ccc8f2 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutOfflineFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutOfflineFragment.kt @@ -1,10 +1,5 @@ package io.snabble.sdk.ui.checkout -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.Fragment import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R diff --git a/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutOfflineView.java b/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutOfflineView.java index fa656f1b95..1884c38d64 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutOfflineView.java +++ b/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutOfflineView.java @@ -33,8 +33,6 @@ import io.snabble.sdk.ui.utils.I18nUtils; import io.snabble.sdk.ui.utils.OneShotClickListener; import io.snabble.sdk.utils.Dispatch; -import io.snabble.sdk.utils.Logger; -import io.snabble.sdk.utils.Utils; import me.relex.circleindicator.CircleIndicator3; public class CheckoutOfflineView extends FrameLayout { @@ -210,7 +208,7 @@ private class CodeListViewAdapter extends RecyclerView.Adapter { @NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - LayoutInflater layoutInflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + LayoutInflater layoutInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); return new ViewHolder(layoutInflater.inflate(R.layout.snabble_item_checkout_offline_qrcode, parent, false)); } diff --git a/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutPOSFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutPOSFragment.kt index f576d68711..4d1dfa3cc5 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutPOSFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/checkout/CheckoutPOSFragment.kt @@ -1,10 +1,5 @@ package io.snabble.sdk.ui.checkout -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.Fragment import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R diff --git a/ui/src/main/java/io/snabble/sdk/ui/checkout/PaymentStatusFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/checkout/PaymentStatusFragment.kt index b819d71dba..c9d00d9055 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/checkout/PaymentStatusFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/checkout/PaymentStatusFragment.kt @@ -1,10 +1,5 @@ package io.snabble.sdk.ui.checkout -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.Fragment import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R diff --git a/ui/src/main/java/io/snabble/sdk/ui/checkout/PaymentStatusItemView.kt b/ui/src/main/java/io/snabble/sdk/ui/checkout/PaymentStatusItemView.kt index 60882e3d54..8dc3c1f651 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/checkout/PaymentStatusItemView.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/checkout/PaymentStatusItemView.kt @@ -5,20 +5,8 @@ import android.util.AttributeSet import android.view.View import android.widget.* import androidx.core.view.isVisible -import androidx.core.widget.TextViewCompat -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.LifecycleObserver -import androidx.lifecycle.OnLifecycleEvent -import com.google.android.material.progressindicator.CircularProgressIndicator -import io.snabble.sdk.BarcodeFormat -import io.snabble.sdk.Checkout -import io.snabble.sdk.Project import io.snabble.sdk.ui.R -import io.snabble.sdk.ui.SnabbleUI -import io.snabble.sdk.ui.scanner.BarcodeView -import io.snabble.sdk.ui.utils.getFragmentActivity import io.snabble.sdk.ui.utils.setOrHide -import io.snabble.sdk.utils.Utils.dp2px @Suppress("LeakingThis") open class PaymentStatusItemView @JvmOverloads constructor( diff --git a/ui/src/main/java/io/snabble/sdk/ui/checkout/PaymentStatusView.kt b/ui/src/main/java/io/snabble/sdk/ui/checkout/PaymentStatusView.kt index 58aaaea560..1ce80742f2 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/checkout/PaymentStatusView.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/checkout/PaymentStatusView.kt @@ -4,30 +4,31 @@ import android.animation.LayoutTransition import android.content.Context import android.content.Intent import android.os.Bundle +import android.text.Editable +import android.text.TextWatcher import android.util.AttributeSet import android.view.View +import android.view.ViewGroup +import android.widget.ScrollView +import androidx.activity.OnBackPressedCallback +import androidx.core.view.isInvisible import androidx.core.view.isVisible -import androidx.lifecycle.* +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleObserver +import androidx.lifecycle.OnLifecycleEvent import io.snabble.sdk.* +import io.snabble.sdk.PaymentOriginCandidateHelper.PaymentOriginCandidate +import io.snabble.sdk.PaymentOriginCandidateHelper.PaymentOriginCandidateAvailableListener import io.snabble.sdk.ui.R import io.snabble.sdk.ui.SnabbleUI -import io.snabble.sdk.ui.utils.getFragmentActivity -import io.snabble.sdk.ui.utils.observeView -import io.snabble.sdk.utils.Dispatch -import android.widget.ScrollView -import androidx.activity.OnBackPressedCallback -import androidx.core.view.isInvisible import io.snabble.sdk.ui.databinding.SnabbleViewPaymentStatusBinding +import io.snabble.sdk.ui.payment.SEPACardInputActivity import io.snabble.sdk.ui.telemetry.Telemetry import io.snabble.sdk.ui.utils.executeUiAction -import android.text.Editable - -import android.text.TextWatcher -import android.view.ViewGroup -import io.snabble.sdk.PaymentOriginCandidateHelper.PaymentOriginCandidate -import io.snabble.sdk.PaymentOriginCandidateHelper.PaymentOriginCandidateAvailableListener -import io.snabble.sdk.ui.payment.SEPACardInputActivity +import io.snabble.sdk.ui.utils.getFragmentActivity +import io.snabble.sdk.ui.utils.observeView import io.snabble.sdk.ui.utils.requireFragmentActivity +import io.snabble.sdk.utils.Dispatch class PaymentStatusView @JvmOverloads constructor( @@ -204,7 +205,9 @@ class PaymentStatusView @JvmOverloads constructor( if (it.value != null && it.format != null) { val format = BarcodeFormat.parse(it.format) if (format != null) { - SnabbleUI.executeAction(requireFragmentActivity(), SnabbleUI.Event.EXIT_TOKEN_AVAILABLE, + SnabbleUI.executeAction( + requireFragmentActivity(), + SnabbleUI.Event.EXIT_TOKEN_AVAILABLE, Bundle().apply { putString("token", it.value) putString("format", it.format) @@ -253,7 +256,7 @@ class PaymentStatusView @JvmOverloads constructor( } } - private fun stopPollingForPaymentOriginCandidate(){ + private fun stopPollingForPaymentOriginCandidate() { paymentOriginCandidateHelper.removePaymentOriginCandidateAvailableListener(this) paymentOriginCandidateHelper.stopPolling() } @@ -335,9 +338,11 @@ class PaymentStatusView @JvmOverloads constructor( if (itemView == null) { itemView = PaymentStatusItemView(context) itemView.tag = it.type - binding.fulfillmentContainer.addView(itemView, + binding.fulfillmentContainer.addView( + itemView, ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT) + ViewGroup.LayoutParams.WRAP_CONTENT + ) } if (it.type == "tobaccolandEWA") { diff --git a/ui/src/main/java/io/snabble/sdk/ui/checkout/routingtargets/RoutingTargetGatekeeperFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/checkout/routingtargets/RoutingTargetGatekeeperFragment.kt index 9bac58171d..f112c5e5c9 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/checkout/routingtargets/RoutingTargetGatekeeperFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/checkout/routingtargets/RoutingTargetGatekeeperFragment.kt @@ -1,10 +1,5 @@ package io.snabble.sdk.ui.checkout.routingtargets -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.Fragment import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R diff --git a/ui/src/main/java/io/snabble/sdk/ui/checkout/routingtargets/RoutingTargetGatekeeperView.kt b/ui/src/main/java/io/snabble/sdk/ui/checkout/routingtargets/RoutingTargetGatekeeperView.kt index 5009420dd3..cfe94e0af7 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/checkout/routingtargets/RoutingTargetGatekeeperView.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/checkout/routingtargets/RoutingTargetGatekeeperView.kt @@ -1,27 +1,26 @@ package io.snabble.sdk.ui.checkout.routingtargets -import android.widget.FrameLayout -import io.snabble.sdk.Checkout.OnCheckoutStateChangedListener -import io.snabble.sdk.Checkout -import io.snabble.sdk.ui.scanner.BarcodeView -import android.widget.TextView -import io.snabble.sdk.ui.R -import io.snabble.sdk.ui.utils.I18nUtils -import android.graphics.Bitmap import android.annotation.SuppressLint import android.content.Context -import android.view.ViewGroup -import android.widget.LinearLayout -import io.snabble.sdk.ui.utils.UIUtils -import android.content.DialogInterface +import android.graphics.Bitmap import android.util.AttributeSet import android.view.View +import android.view.ViewGroup +import android.widget.FrameLayout import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.TextView import androidx.appcompat.app.AlertDialog import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleObserver import androidx.lifecycle.OnLifecycleEvent +import io.snabble.sdk.Checkout +import io.snabble.sdk.Checkout.OnCheckoutStateChangedListener +import io.snabble.sdk.ui.R import io.snabble.sdk.ui.SnabbleUI +import io.snabble.sdk.ui.scanner.BarcodeView +import io.snabble.sdk.ui.utils.I18nUtils +import io.snabble.sdk.ui.utils.UIUtils import io.snabble.sdk.ui.utils.setOrHide import io.snabble.sdk.utils.Logger import kotlin.math.roundToInt @@ -54,7 +53,7 @@ class RoutingTargetGatekeeperView @JvmOverloads constructor( helperTextNoImage = findViewById(R.id.helper_text_no_image) helperImage = findViewById(R.id.helper_image) - upArrow = findViewById(R.id.arrow) + upArrow = findViewById(R.id.arrow) cancel.setOnClickListener { abort() @@ -86,8 +85,8 @@ class RoutingTargetGatekeeperView @JvmOverloads constructor( Logger.d("QRCode content: $content") checkoutIdCode.setText(content) - project.assets.get("checkout-online") { - bitmap: Bitmap? -> setHelperImage(bitmap) + project.assets.get("checkout-online") { bitmap: Bitmap? -> + setHelperImage(bitmap) } onStateChanged(checkout.state) } diff --git a/ui/src/main/java/io/snabble/sdk/ui/checkout/routingtargets/RoutingTargetSupervisorFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/checkout/routingtargets/RoutingTargetSupervisorFragment.kt index d3099b9f89..78e3507547 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/checkout/routingtargets/RoutingTargetSupervisorFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/checkout/routingtargets/RoutingTargetSupervisorFragment.kt @@ -1,10 +1,5 @@ package io.snabble.sdk.ui.checkout.routingtargets -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.Fragment import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R diff --git a/ui/src/main/java/io/snabble/sdk/ui/checkout/routingtargets/RoutingTargetSupervisorView.kt b/ui/src/main/java/io/snabble/sdk/ui/checkout/routingtargets/RoutingTargetSupervisorView.kt index fe8ba244a9..4d0dc300d6 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/checkout/routingtargets/RoutingTargetSupervisorView.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/checkout/routingtargets/RoutingTargetSupervisorView.kt @@ -1,27 +1,26 @@ package io.snabble.sdk.ui.checkout.routingtargets -import android.widget.FrameLayout -import io.snabble.sdk.Checkout.OnCheckoutStateChangedListener -import io.snabble.sdk.Checkout -import io.snabble.sdk.ui.scanner.BarcodeView -import android.widget.TextView -import io.snabble.sdk.ui.R -import io.snabble.sdk.ui.utils.I18nUtils -import android.graphics.Bitmap import android.annotation.SuppressLint import android.content.Context -import android.view.ViewGroup -import android.widget.LinearLayout -import io.snabble.sdk.ui.utils.UIUtils -import android.content.DialogInterface +import android.graphics.Bitmap import android.util.AttributeSet import android.view.View +import android.view.ViewGroup +import android.widget.FrameLayout import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.TextView import androidx.appcompat.app.AlertDialog import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleObserver import androidx.lifecycle.OnLifecycleEvent +import io.snabble.sdk.Checkout +import io.snabble.sdk.Checkout.OnCheckoutStateChangedListener +import io.snabble.sdk.ui.R import io.snabble.sdk.ui.SnabbleUI +import io.snabble.sdk.ui.scanner.BarcodeView +import io.snabble.sdk.ui.utils.I18nUtils +import io.snabble.sdk.ui.utils.UIUtils import io.snabble.sdk.ui.utils.setOrHide import io.snabble.sdk.utils.Logger import kotlin.math.roundToInt @@ -81,10 +80,10 @@ class RoutingTargetSupervisorView @JvmOverloads constructor( Logger.d("QRCode content: $content") checkoutIdCode.setText(content) - project.assets.get("checkout-online") { - bitmap: Bitmap? -> setHelperImage(bitmap) + project.assets.get("checkout-online") { bitmap: Bitmap? -> + setHelperImage(bitmap) } - + onStateChanged(checkout.state) } diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/CreditCardInputView.java b/ui/src/main/java/io/snabble/sdk/ui/payment/CreditCardInputView.java index fb7795292b..421be86d9d 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/CreditCardInputView.java +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/CreditCardInputView.java @@ -209,7 +209,7 @@ private void loadForm(HashResponse hashResponse) { data = data.replace("{{hash}}", hashResponse.hash); // hides credit card selection, V = VISA, but in reality we can enter any credit card that is supported - switch(paymentType) { + switch (paymentType) { case MASTERCARD: data = data.replace("{{paymentMethod}}", "M"); break; diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/Datatrans.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/Datatrans.kt index 09bc905033..f1cc2297eb 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/Datatrans.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/Datatrans.kt @@ -22,8 +22,9 @@ import io.snabble.sdk.utils.Dispatch import io.snabble.sdk.utils.GsonHolder import io.snabble.sdk.utils.Logger import io.snabble.sdk.utils.SimpleJsonCallback -import okhttp3.* +import okhttp3.Callback import okhttp3.MediaType.Companion.toMediaType +import okhttp3.Request import okhttp3.RequestBody.Companion.toRequestBody import java.util.* @@ -131,7 +132,7 @@ object Datatrans { } if (token != null) { - Keyguard.unlock(activity, object : Keyguard.Callback { + Keyguard.unlock(activity, object : Keyguard.Callback { override fun success() { val store = Snabble.paymentCredentialsStore val credentials = PaymentCredentials.fromDatatrans( diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentOptionsView.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentOptionsView.kt index d08fceeac7..560a5ba667 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentOptionsView.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentOptionsView.kt @@ -68,42 +68,44 @@ open class PaymentOptionsView @JvmOverloads constructor( val projectList = ArrayList() val store = Snabble.paymentCredentialsStore - projects.filter { it.brand == null } - .forEach { project -> - val count = store.getCountForProject(project) - - projectList.add( - Entry( - text = project.name, - project = project, - count = count, - click = { - if (count > 0) { - PaymentInputViewHelper.showPaymentList(context, project) - } else { - PaymentInputViewHelper.showPaymentSelectionForAdding(context, project) - } + projects + .filter { it.brand == null } + .forEach { project -> + val count = store.getCountForProject(project) + + projectList.add( + Entry( + text = project.name, + project = project, + count = count, + click = { + if (count > 0) { + PaymentInputViewHelper.showPaymentList(context, project) + } else { + PaymentInputViewHelper.showPaymentSelectionForAdding(context, project) } - ) + } ) - } + ) + } val brands = ArrayList() val counts = HashMap() val projectCount = HashMap() - projects.filter { it.brand != null } - .forEach { project -> - val count = store.getCountForProject(project) + projects + .filter { it.brand != null } + .forEach { project -> + val count = store.getCountForProject(project) - if (!brands.contains(project.brand)) { - brands.add(project.brand) - } + if (!brands.contains(project.brand)) { + brands.add(project.brand) + } - val currentCount = counts.getOrPut(project.brand) { 0 } - counts[project.brand] = currentCount + count - projectCount[project.brand] = projectCount.getOrPut(project.brand) { 0 } + 1 - } + val currentCount = counts.getOrPut(project.brand) { 0 } + counts[project.brand] = currentCount + count + projectCount[project.brand] = projectCount.getOrPut(project.brand) { 0 } + 1 + } brands.forEach { brand -> val project = projects.firstOrNull { it.brand?.id == brand.id } diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/SEPACardInputView.java b/ui/src/main/java/io/snabble/sdk/ui/payment/SEPACardInputView.java index 3dd209078e..4711b05937 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/SEPACardInputView.java +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/SEPACardInputView.java @@ -93,7 +93,7 @@ public void click() { } }); - ibanInput.setFilters(new InputFilter[] { + ibanInput.setFilters(new InputFilter[]{ new InputFilter.AllCaps() }); @@ -329,7 +329,7 @@ public void setOnCloseListener(OnCloseListener onCloseListener) { } private void hideSoftKeyboard(View view) { - InputMethodManager imm = (InputMethodManager)getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); } diff --git a/ui/src/main/java/io/snabble/sdk/ui/scanner/BarcodeScannerView.kt b/ui/src/main/java/io/snabble/sdk/ui/scanner/BarcodeScannerView.kt index 13b28b1169..9b6bfc5eba 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/scanner/BarcodeScannerView.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/scanner/BarcodeScannerView.kt @@ -8,7 +8,10 @@ import android.graphics.ImageFormat import android.graphics.Rect import android.util.AttributeSet import android.util.Size -import android.view.* +import android.view.Gravity +import android.view.View +import android.view.ViewGroup +import android.view.ViewTreeObserver import android.widget.FrameLayout import android.widget.ImageView import android.widget.TextView @@ -24,7 +27,6 @@ import io.snabble.sdk.ui.utils.UIUtils import io.snabble.sdk.utils.Dispatch import io.snabble.sdk.utils.Logger import java.nio.ByteBuffer -import java.util.* import java.util.concurrent.ExecutorService import java.util.concurrent.Executors import java.util.concurrent.TimeUnit diff --git a/ui/src/main/java/io/snabble/sdk/ui/scanner/BarcodeView.java b/ui/src/main/java/io/snabble/sdk/ui/scanner/BarcodeView.java index a4cf022be4..b7d8756323 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/scanner/BarcodeView.java +++ b/ui/src/main/java/io/snabble/sdk/ui/scanner/BarcodeView.java @@ -191,7 +191,7 @@ private void generate() { BitMatrix bm = writer.encode(text, ZXingHelper.toZXingFormat(format), tw, th, hints); int[] pixels = new int[w * h]; - + int[] rect = bm.getEnclosingRectangle(); int left = rect[0]; int top = rect[1]; diff --git a/ui/src/main/java/io/snabble/sdk/ui/scanner/FalsePositiveFilter.java b/ui/src/main/java/io/snabble/sdk/ui/scanner/FalsePositiveFilter.java index 2921e386ee..82988a1c5f 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/scanner/FalsePositiveFilter.java +++ b/ui/src/main/java/io/snabble/sdk/ui/scanner/FalsePositiveFilter.java @@ -10,6 +10,7 @@ public class FalsePositiveFilter { public FalsePositiveFilter() { this.repeatsNeeded = 2; } + public FalsePositiveFilter(int repeatsNeeded) { this.repeatsNeeded = repeatsNeeded; } diff --git a/ui/src/main/java/io/snabble/sdk/ui/scanner/ProductConfirmationDialog.java b/ui/src/main/java/io/snabble/sdk/ui/scanner/ProductConfirmationDialog.java index 23a5639ed4..3e25e72835 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/scanner/ProductConfirmationDialog.java +++ b/ui/src/main/java/io/snabble/sdk/ui/scanner/ProductConfirmationDialog.java @@ -235,7 +235,7 @@ public void afterTextChanged(Editable s) { inputMethodManager.showSoftInput(quantity, 0); }); } - + SnabbleUI.executeAction(context, SnabbleUI.Event.PRODUCT_CONFIRMATION_SHOWN); } @@ -334,7 +334,7 @@ public void addToCart() { if (imageUrl != null && imageUrl.length() > 0) { Picasso.get().load(cartItem.getProduct().getImageUrl()).fetch(); } - + Bundle args = new Bundle(); args.putString("cartItem", GsonHolder.get().toJson(cartItem)); SnabbleUI.executeAction(context, SnabbleUI.Event.PRODUCT_CONFIRMATION_HIDDEN, args); diff --git a/ui/src/main/java/io/snabble/sdk/ui/scanner/ProductResolver.kt b/ui/src/main/java/io/snabble/sdk/ui/scanner/ProductResolver.kt index 66b790f805..e8d6e9d1d5 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/scanner/ProductResolver.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/scanner/ProductResolver.kt @@ -6,18 +6,16 @@ import android.content.DialogInterface import android.view.KeyEvent import io.snabble.sdk.* import io.snabble.sdk.Unit -import java.math.BigDecimal -import java.util.concurrent.CountDownLatch - import io.snabble.sdk.codes.ScannedCode import io.snabble.sdk.codes.gs1.GS1Code import io.snabble.sdk.ui.R - import io.snabble.sdk.ui.SnabbleUI import io.snabble.sdk.ui.telemetry.Telemetry import io.snabble.sdk.ui.utils.DelayedProgressDialog import io.snabble.sdk.utils.Age import io.snabble.sdk.utils.Dispatch +import java.math.BigDecimal +import java.util.concurrent.CountDownLatch class ProductResolver private constructor(private val context: Context, private val project: Project) { private var resolveBundles = true @@ -59,11 +57,11 @@ class ProductResolver private constructor(private val context: Context, private } private data class Result( - var product: Product? = null, - var wasOnlineProduct: Boolean = false, - var code: ScannedCode? = null, - var error: Boolean = false, - var matchCount: Int = 0 + var product: Product? = null, + var wasOnlineProduct: Boolean = false, + var code: ScannedCode? = null, + var error: Boolean = false, + var matchCount: Int = 0 ) private fun lookupProductData(scannedCodes: List, gs1Code: GS1Code?) { @@ -131,12 +129,14 @@ class ProductResolver private constructor(private val context: Context, private for (scannedCode in scannedCodes) { newGs1Code = GS1Code(scannedCode.code) val code = project.getCodeTemplate("default") - .match(newGs1Code.gtin) - .buildCode() + .match(newGs1Code.gtin) + .buildCode() if (code != null) { - gs1GtinScannedCodes.add(code.newBuilder() + gs1GtinScannedCodes.add( + code.newBuilder() .setScannedCode(newGs1Code.code) - .create()) + .create() + ) break } } @@ -170,9 +170,11 @@ class ProductResolver private constructor(private val context: Context, private var gs1EmbeddedData: BigDecimal? = null if (gs1Code != null) { - gs1EmbeddedData = gs1Code.getEmbeddedData(unit, - project.currency.defaultFractionDigits, - project.roundingMode) + gs1EmbeddedData = gs1Code.getEmbeddedData( + unit, + project.currency.defaultFractionDigits, + project.roundingMode + ) } if (scannedCode.hasEmbeddedDecimalData() || gs1EmbeddedData != null) { @@ -335,7 +337,10 @@ class ProductResolver private constructor(private val context: Context, private fun onAlreadyScanned() } - class Builder @JvmOverloads constructor(context: Context, private val project: Project = SnabbleUI.project) { + class Builder @JvmOverloads constructor( + context: Context, + private val project: Project = SnabbleUI.project + ) { private val productResolver: ProductResolver = ProductResolver(context, project) fun setCodes(codes: List) = apply { @@ -371,29 +376,29 @@ class ProductResolver private constructor(private val context: Context, private } fun setOnProductNotFoundListener(listener: () -> kotlin.Unit) = - setOnProductNotFoundListener(object : OnProductNotFoundListener { - override fun onProductNotFound() = listener.invoke() - }) + setOnProductNotFoundListener(object : OnProductNotFoundListener { + override fun onProductNotFound() = listener.invoke() + }) fun setOnProductFoundListener(listener: OnProductFoundListener) = apply { productResolver.onProductFoundListener = listener } fun setOnProductFoundListener(listener: (product: Product, scannedCode: ScannedCode) -> kotlin.Unit) = - setOnProductFoundListener(object : OnProductFoundListener { - override fun onProductFound(product: Product, scannedCode: ScannedCode) { - listener.invoke(product, scannedCode) - } - }) + setOnProductFoundListener(object : OnProductFoundListener { + override fun onProductFound(product: Product, scannedCode: ScannedCode) { + listener.invoke(product, scannedCode) + } + }) fun setOnNetworkErrorListener(listener: OnNetworkErrorListener) = apply { productResolver.onNetworkErrorListener = listener } fun setOnNetworkErrorListener(listener: () -> kotlin.Unit) = - setOnNetworkErrorListener(object : OnNetworkErrorListener { - override fun onNetworkError() = listener.invoke() - }) + setOnNetworkErrorListener(object : OnNetworkErrorListener { + override fun onNetworkError() = listener.invoke() + }) fun setOnSaleStopListener(listener: OnSaleStopListener) = apply { productResolver.onSaleStopListener = listener diff --git a/ui/src/main/java/io/snabble/sdk/ui/scanner/SelectReducedPriceDialogFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/scanner/SelectReducedPriceDialogFragment.kt index 59172f53de..627a24e751 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/scanner/SelectReducedPriceDialogFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/scanner/SelectReducedPriceDialogFragment.kt @@ -27,7 +27,8 @@ class SelectReducedPriceDialogFragment( val item = cartItem val cart = shoppingCart - val adapter = ArrayAdapter(requireContext(), + val adapter = ArrayAdapter( + requireContext(), R.layout.snabble_item_pricereduction_select, R.id.label, listOf(getString(R.string.Snabble_noDiscount)) + (discounts.map { it.name }) diff --git a/ui/src/main/java/io/snabble/sdk/ui/scanner/SelfScanningFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/scanner/SelfScanningFragment.kt index 67a0885193..787af710b6 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/scanner/SelfScanningFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/scanner/SelfScanningFragment.kt @@ -11,12 +11,10 @@ import android.widget.Button import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat import androidx.core.content.res.ResourcesCompat -import androidx.fragment.app.Fragment import io.snabble.sdk.codes.ScannedCode import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R import io.snabble.sdk.ui.SnabbleUI -import io.snabble.sdk.ui.payment.PayoneInputView import io.snabble.sdk.ui.search.SearchHelper import io.snabble.sdk.ui.utils.setOneShotClickListener @@ -150,7 +148,7 @@ open class SelfScanningFragment : BaseFragment() { } override fun onOptionsItemSelected(item: MenuItem): Boolean { - when(item.itemId) { + when (item.itemId) { R.id.snabble_action_search -> { selfScanningView?.searchWithBarcode() } @@ -165,7 +163,7 @@ open class SelfScanningFragment : BaseFragment() { private fun updateTorchIcon() { val menuItem = optionsMenu?.findItem(R.id.snabble_action_torch) - if (selfScanningView?.isTorchEnabled ?: false) { + if (selfScanningView?.isTorchEnabled == true) { menuItem?.icon = ResourcesCompat.getDrawable(resources, R.drawable.snabble_ic_flashlight_on, null) } else { menuItem?.icon = ResourcesCompat.getDrawable(resources, R.drawable.snabble_ic_flashlight_off, null) diff --git a/ui/src/main/java/io/snabble/sdk/ui/scanner/SelfScanningView.java b/ui/src/main/java/io/snabble/sdk/ui/scanner/SelfScanningView.java index ee84b61e21..3eab142905 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/scanner/SelfScanningView.java +++ b/ui/src/main/java/io/snabble/sdk/ui/scanner/SelfScanningView.java @@ -217,11 +217,11 @@ private void handleCoupon(List scannedCodes, String failureMessage) private Pair lookupCoupon(List scannedCodes) { Project project = SnabbleUI.getProject(); - for (Coupon coupon : project.getCoupons().filter(CouponType.PRINTED)){ + for (Coupon coupon : project.getCoupons().filter(CouponType.PRINTED)) { for (CouponCode code : coupon.getCodes()) { for (ScannedCode scannedCode : scannedCodes) { if (scannedCode.getCode().equals(code.getCode()) - && scannedCode.getTemplateName().equals(code.getTemplate())) { + && scannedCode.getTemplateName().equals(code.getTemplate())) { return new Pair<>(coupon, scannedCode); } } @@ -258,7 +258,7 @@ private void showInfo(final String text) { UIUtils.getDurationByLength(text), ResourcesCompat.getColor(getResources(), R.color.snabble_infoColor, null), ResourcesCompat.getColor(getResources(), R.color.snabble_infoTextColor, null) - )); + )); } private void showWarning(final String text) { diff --git a/ui/src/main/java/io/snabble/sdk/ui/scanner/ZXingHelper.java b/ui/src/main/java/io/snabble/sdk/ui/scanner/ZXingHelper.java index 0c4f0ae1bd..0c7ef68fd8 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/scanner/ZXingHelper.java +++ b/ui/src/main/java/io/snabble/sdk/ui/scanner/ZXingHelper.java @@ -4,7 +4,7 @@ class ZXingHelper { public static com.google.zxing.BarcodeFormat toZXingFormat(BarcodeFormat barcodeFormat) { - switch(barcodeFormat) { + switch (barcodeFormat) { case EAN_8: return com.google.zxing.BarcodeFormat.EAN_8; case EAN_13: diff --git a/ui/src/main/java/io/snabble/sdk/ui/search/ProductSearchFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/search/ProductSearchFragment.kt index ccdda46675..37a71ffb73 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/search/ProductSearchFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/search/ProductSearchFragment.kt @@ -1,10 +1,7 @@ package io.snabble.sdk.ui.search -import android.view.LayoutInflater -import android.view.ViewGroup import android.os.Bundle import android.view.View -import androidx.fragment.app.Fragment import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R diff --git a/ui/src/main/java/io/snabble/sdk/ui/search/SearchableProductAdapter.kt b/ui/src/main/java/io/snabble/sdk/ui/search/SearchableProductAdapter.kt index e1359ea233..7c2459446f 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/search/SearchableProductAdapter.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/search/SearchableProductAdapter.kt @@ -16,7 +16,8 @@ import io.snabble.sdk.ui.utils.setOrHide import io.snabble.sdk.utils.Dispatch import io.snabble.sdk.utils.StringNormalizer -class SearchableProductAdapter : RecyclerView.Adapter() { +class SearchableProductAdapter : + RecyclerView.Adapter() { enum class SearchType { BARCODE, FOLDED_NAME } diff --git a/ui/src/main/java/io/snabble/sdk/ui/utils/KotlinExtensions.kt b/ui/src/main/java/io/snabble/sdk/ui/utils/KotlinExtensions.kt index eea8412e1f..58064c923e 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/utils/KotlinExtensions.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/utils/KotlinExtensions.kt @@ -76,7 +76,7 @@ fun Snackbar.setGravity(gravity: Int) = apply { // if the view is rendered at the location y == 0 then this snackbar could be hidden behind a toolbar. Checking this and move it below. if (gravity == Gravity.TOP && view.y.absoluteValue < 0.0001) { (view.requireFragmentActivity() as AppCompatActivity).supportActionBar?.let { actionBar -> - val y = if(actionBar.customView != null) { + val y = if (actionBar.customView != null) { max( actionBar.customView.y, actionBar.customView.y + actionBar.customView.translationY + (actionBar.customView.parent as View).translationY + actionBar.height diff --git a/ui/src/main/java/io/snabble/sdk/ui/utils/UIUtils.java b/ui/src/main/java/io/snabble/sdk/ui/utils/UIUtils.java index 8990cdc603..cd233ef904 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/utils/UIUtils.java +++ b/ui/src/main/java/io/snabble/sdk/ui/utils/UIUtils.java @@ -1,5 +1,7 @@ package io.snabble.sdk.ui.utils; +import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.app.Activity; @@ -29,8 +31,8 @@ import eu.rekisoft.android.util.LazyWorker; import io.snabble.sdk.ui.R; - -import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP; +import kotlin.Unit; +import kotlin.jvm.functions.Function0; public class UIUtils { @RestrictTo(LIBRARY_GROUP) @@ -42,7 +44,7 @@ public class UIUtils { public static final int INFO_NEUTRAL = 0; public static final int INFO_WARNING = 1; public static final int INFO_POSITIVE = 2; - + @BaseTransientBottomBar.Duration public static final int SNACKBAR_LENGTH_VERY_LONG = 5000; @@ -92,7 +94,7 @@ public static int getColorByAttribute(Context context, @AttrRes int attrResId) { @Deprecated public static TopDownInfoBoxController showTopDownInfoBox(ViewGroup parent, String text, int duration, int type, int offsetY) { LayoutInflater inflater = LayoutInflater.from(parent.getContext()); - final TextView info = (TextView)inflater.inflate(R.layout.snabble_view_info, parent, false); + final TextView info = (TextView) inflater.inflate(R.layout.snabble_view_info, parent, false); parent.addView(info, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); info.setVisibility(View.INVISIBLE); @@ -128,8 +130,8 @@ public void onLayoutChange(View view, int left, int top, int right, int bottom, Handler infoHandler = new Handler(Looper.getMainLooper()); infoHandler.removeCallbacksAndMessages(null); - LazyWorker.Job hide = LazyWorker.createLifeCycleAwareJob(parent.getContext(), (job) -> { - if(info.isAttachedToWindow()) { + LazyWorker.Job hide = LazyWorker.createLifeCycleAwareJob(parent.getContext(), (job) -> { + if (info.isAttachedToWindow()) { info.animate() .translationY(-offsetY - info.getHeight()) .setListener(new AnimatorListenerAdapter() { diff --git a/ui/src/main/java/io/snabble/sdk/ui/views/MessageBox.kt b/ui/src/main/java/io/snabble/sdk/ui/views/MessageBox.kt index 0759f10d98..7e2321ba88 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/views/MessageBox.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/views/MessageBox.kt @@ -1,6 +1,9 @@ package io.snabble.sdk.ui.views -import android.animation.* +import android.animation.Animator +import android.animation.AnimatorListenerAdapter +import android.animation.AnimatorSet +import android.animation.ValueAnimator import android.annotation.SuppressLint import android.content.Context import android.graphics.Color @@ -12,7 +15,6 @@ import android.widget.TextView import androidx.cardview.widget.CardView import androidx.core.view.isVisible import com.google.android.material.animation.AnimationUtils -import com.google.android.material.animation.AnimationUtils.LINEAR_INTERPOLATOR import io.snabble.sdk.ui.R import io.snabble.sdk.utils.Dispatch import io.snabble.sdk.utils.Utils From e1e52c156ae9837ff1212bcca4244b2490afae49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Kilczan?= Date: Fri, 18 Feb 2022 08:16:54 +0100 Subject: [PATCH 29/30] Fix lint warnings --- ui/src/main/java/io/snabble/sdk/ui/Keyguard.java | 4 +--- .../ui/cart/PaymentSelectionDialogFragment.java | 4 +++- .../sdk/ui/cart/PaymentSelectionHelper.java | 8 +++----- .../io/snabble/sdk/ui/cart/ShoppingCartView.java | 4 +--- .../snabble/sdk/ui/checkout/PaymentStatusView.kt | 16 ++++++++-------- .../sdk/ui/payment/PaydirektInputView.java | 4 +--- .../ui/payment/PaymentCredentialsListView.java | 5 ++--- .../snabble/sdk/ui/payment/PaymentOptionsView.kt | 2 +- .../snabble/sdk/ui/scanner/BarcodeScannerView.kt | 4 ++-- .../snabble/sdk/ui/scanner/SelfScanningView.java | 4 +--- .../sdk/ui/scanner/ZXingBarcodeDetector.java | 2 +- .../sdk/ui/search/SearchableProductAdapter.kt | 3 +-- .../sdk/ui/utils/SnackbarPushUpBehavior.java | 13 +++++++------ .../io/snabble/sdk/ui/utils/SnackbarUtils.kt | 4 ++-- .../java/io/snabble/sdk/ui/utils/UIUtils.java | 6 ++---- 15 files changed, 36 insertions(+), 47 deletions(-) diff --git a/ui/src/main/java/io/snabble/sdk/ui/Keyguard.java b/ui/src/main/java/io/snabble/sdk/ui/Keyguard.java index 459596ac0a..3011cca84e 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/Keyguard.java +++ b/ui/src/main/java/io/snabble/sdk/ui/Keyguard.java @@ -54,9 +54,7 @@ public static void unlock(FragmentActivity activity, Callback callback) { new BiometricPrompt.Builder(activity) .setTitle(activity.getString(R.string.Snabble_Keyguard_title)) .setDescription(activity.getString(R.string.Snabble_Keyguard_message)) - .setNegativeButton(activity.getString(R.string.Snabble_Cancel), Executors.newSingleThreadExecutor(), (dialogInterface, i) -> { - error(callback); - }) + .setNegativeButton(activity.getString(R.string.Snabble_Cancel), Executors.newSingleThreadExecutor(), (dialogInterface, i) -> error(callback)) .build() .authenticate(new CancellationSignal(), Executors.newSingleThreadExecutor(), new BiometricPrompt.AuthenticationCallback() { diff --git a/ui/src/main/java/io/snabble/sdk/ui/cart/PaymentSelectionDialogFragment.java b/ui/src/main/java/io/snabble/sdk/ui/cart/PaymentSelectionDialogFragment.java index a0a691b62e..1f87211fb0 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/cart/PaymentSelectionDialogFragment.java +++ b/ui/src/main/java/io/snabble/sdk/ui/cart/PaymentSelectionDialogFragment.java @@ -10,6 +10,8 @@ import android.widget.LinearLayout; import android.widget.TextView; +import androidx.annotation.NonNull; + import com.google.android.material.bottomsheet.BottomSheetDialogFragment; import java.util.ArrayList; @@ -24,7 +26,7 @@ public class PaymentSelectionDialogFragment extends BottomSheetDialogFragment { public static final String ARG_SELECTED_ENTRY = "selectedEntry"; @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = View.inflate(requireContext(), R.layout.snabble_dialog_payment_selection, null); LinearLayout options = view.findViewById(R.id.options); diff --git a/ui/src/main/java/io/snabble/sdk/ui/cart/PaymentSelectionHelper.java b/ui/src/main/java/io/snabble/sdk/ui/cart/PaymentSelectionHelper.java index c78188f113..3abc1e1c9d 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/cart/PaymentSelectionHelper.java +++ b/ui/src/main/java/io/snabble/sdk/ui/cart/PaymentSelectionHelper.java @@ -54,10 +54,8 @@ public static class Entry implements Serializable { private final Map names = new HashMap<>(); private final List paymentMethodsSortPriority = new ArrayList<>(); - private Application application; - private PaymentCredentialsStore paymentCredentialsStore; - private List paymentCredentials; - private MutableLiveData selectedEntry; + private final Application application; + private final MutableLiveData selectedEntry; private Project project; private ShoppingCart cart; private final SharedPreferences sharedPreferences; @@ -125,7 +123,7 @@ private PaymentSelectionHelper() { selectedEntry = new MutableLiveData<>(); - paymentCredentialsStore = Snabble.getInstance().getPaymentCredentialsStore(); + PaymentCredentialsStore paymentCredentialsStore = Snabble.getInstance().getPaymentCredentialsStore(); paymentCredentialsStore.addCallback(this::update); paymentCredentialsStore.addOnPaymentCredentialsAddedListener(paymentCredentials -> { diff --git a/ui/src/main/java/io/snabble/sdk/ui/cart/ShoppingCartView.java b/ui/src/main/java/io/snabble/sdk/ui/cart/ShoppingCartView.java index 11ad636fd4..5787d12530 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/cart/ShoppingCartView.java +++ b/ui/src/main/java/io/snabble/sdk/ui/cart/ShoppingCartView.java @@ -165,9 +165,7 @@ private void inflateView(Context context, AttributeSet attrs) { paymentContainer = findViewById(R.id.bottom_payment_container); scanProducts = findViewById(R.id.scan_products); - scanProducts.setOnClickListener(view -> { - SnabbleUI.executeAction(context, SnabbleUI.Event.SHOW_SCANNER); - }); + scanProducts.setOnClickListener(view -> SnabbleUI.executeAction(context, SnabbleUI.Event.SHOW_SCANNER)); restore = findViewById(R.id.restore); restore.setOnClickListener(v -> cart.restore()); diff --git a/ui/src/main/java/io/snabble/sdk/ui/checkout/PaymentStatusView.kt b/ui/src/main/java/io/snabble/sdk/ui/checkout/PaymentStatusView.kt index 1ce80742f2..f6e8ba6ea1 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/checkout/PaymentStatusView.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/checkout/PaymentStatusView.kt @@ -167,27 +167,27 @@ class PaymentStatusView @JvmOverloads constructor( paymentOriginCandidateHelper.startPollingIfLinkIsAvailable(checkout.checkoutProcess) } Checkout.State.PAYMENT_PROCESSING_ERROR -> { - Telemetry.event(Telemetry.Event.CheckoutDeniedByPaymentProvider); + Telemetry.event(Telemetry.Event.CheckoutDeniedByPaymentProvider) handlePaymentAborted() } Checkout.State.DENIED_TOO_YOUNG -> { - Telemetry.event(Telemetry.Event.CheckoutDeniedByTooYoung); + Telemetry.event(Telemetry.Event.CheckoutDeniedByTooYoung) handlePaymentAborted() } Checkout.State.DENIED_BY_PAYMENT_PROVIDER -> { - Telemetry.event(Telemetry.Event.CheckoutDeniedByPaymentProvider); + Telemetry.event(Telemetry.Event.CheckoutDeniedByPaymentProvider) handlePaymentAborted() } Checkout.State.DENIED_BY_SUPERVISOR -> { - Telemetry.event(Telemetry.Event.CheckoutDeniedBySupervisor); + Telemetry.event(Telemetry.Event.CheckoutDeniedBySupervisor) handlePaymentAborted() } Checkout.State.PAYMENT_ABORTED -> { - Telemetry.event(Telemetry.Event.CheckoutAbortByUser); + Telemetry.event(Telemetry.Event.CheckoutAbortByUser) handlePaymentAborted() } Checkout.State.REQUEST_PAYMENT_AUTHORIZATION_TOKEN -> { - val price = checkout.verifiedOnlinePrice; + val price = checkout.verifiedOnlinePrice if (price != -1) { val googlePayHelper = project.googlePayHelper if (googlePayHelper != null) { @@ -226,7 +226,7 @@ class PaymentStatusView @JvmOverloads constructor( } } - binding.statusContainer.layoutTransition.enableTransitionType(LayoutTransition.CHANGING); + binding.statusContainer.layoutTransition.enableTransitionType(LayoutTransition.CHANGING) } private fun handlePaymentAborted() { @@ -312,7 +312,7 @@ class PaymentStatusView @JvmOverloads constructor( val receipts = Snabble.receipts receipts.getReceiptInfos(object : Receipts.ReceiptInfoCallback { override fun success(receiptInfos: Array?) { - val receipt = receiptInfos?.filter { it.id == orderId }?.firstOrNull() + val receipt = receiptInfos?.firstOrNull { it.id == orderId } if (receipt != null) { Dispatch.mainThread { binding.receipt.state = PaymentStatusItemView.State.SUCCESS diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/PaydirektInputView.java b/ui/src/main/java/io/snabble/sdk/ui/payment/PaydirektInputView.java index fb0ecd2b1e..098db4f2e2 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/PaydirektInputView.java +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/PaydirektInputView.java @@ -209,9 +209,7 @@ public void success(AuthorizationResult result) { @Override public void error(Throwable t) { - Dispatch.mainThread(() -> { - finishWithError(); - }); + Dispatch.mainThread(() -> finishWithError()); } }); } diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentCredentialsListView.java b/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentCredentialsListView.java index c9d56e126d..12077a0bf1 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentCredentialsListView.java +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentCredentialsListView.java @@ -237,6 +237,7 @@ private int getDrawableForBrand(PaymentCredentials.Brand brand) { } private class Adapter extends RecyclerView.Adapter { + @NonNull @Override public EntryViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View v = LayoutInflater.from(getContext()).inflate(R.layout.snabble_item_payment_credentials_list_entry, parent, false); @@ -270,9 +271,7 @@ public void onBindViewHolder(@NonNull final EntryViewHolder vh, final int positi vh.delete.setOnClickListener(view -> { new AlertDialog.Builder(getContext()) .setMessage(R.string.Snabble_Payment_delete_message) - .setPositiveButton(R.string.Snabble_Yes, (dialog, which) -> { - paymentCredentialsStore.remove(e.paymentCredentials); - }) + .setPositiveButton(R.string.Snabble_Yes, (dialog, which) -> paymentCredentialsStore.remove(e.paymentCredentials)) .setNegativeButton(R.string.Snabble_No, null) .create() .show(); diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentOptionsView.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentOptionsView.kt index 560a5ba667..5c8d9e6b31 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentOptionsView.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/PaymentOptionsView.kt @@ -109,7 +109,7 @@ open class PaymentOptionsView @JvmOverloads constructor( brands.forEach { brand -> val project = projects.firstOrNull { it.brand?.id == brand.id } - val projectBrandCount = projectCount.get(project?.brand) ?: 0 + val projectBrandCount = projectCount[project?.brand] ?: 0 projectList.add( Entry( text = brand.name, diff --git a/ui/src/main/java/io/snabble/sdk/ui/scanner/BarcodeScannerView.kt b/ui/src/main/java/io/snabble/sdk/ui/scanner/BarcodeScannerView.kt index 9b6bfc5eba..eee936dcfd 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/scanner/BarcodeScannerView.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/scanner/BarcodeScannerView.kt @@ -153,9 +153,9 @@ open class BarcodeScannerView @JvmOverloads constructor( .build() .also { cameraExecutor?.let { exec -> - it.setAnalyzer(exec, { image -> + it.setAnalyzer(exec) { image -> processImage(image) - }) + } } } diff --git a/ui/src/main/java/io/snabble/sdk/ui/scanner/SelfScanningView.java b/ui/src/main/java/io/snabble/sdk/ui/scanner/SelfScanningView.java index 3eab142905..c1be2128c7 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/scanner/SelfScanningView.java +++ b/ui/src/main/java/io/snabble/sdk/ui/scanner/SelfScanningView.java @@ -307,9 +307,7 @@ public void searchWithBarcode() { new AlertDialog.Builder(getContext()) .setView(input) .setTitle(R.string.Snabble_Scanner_enterBarcode) - .setPositiveButton(R.string.Snabble_Done, (dialog, which) -> { - lookupAndShowProduct(ScannedCode.parse(SnabbleUI.getProject(), input.getText().toString())); - }) + .setPositiveButton(R.string.Snabble_Done, (dialog, which) -> lookupAndShowProduct(ScannedCode.parse(SnabbleUI.getProject(), input.getText().toString()))) .setNegativeButton(R.string.Snabble_Cancel, null) .setOnDismissListener(dialog -> resumeBarcodeScanner()) .create() diff --git a/ui/src/main/java/io/snabble/sdk/ui/scanner/ZXingBarcodeDetector.java b/ui/src/main/java/io/snabble/sdk/ui/scanner/ZXingBarcodeDetector.java index 6224469a04..2c58ad5361 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/scanner/ZXingBarcodeDetector.java +++ b/ui/src/main/java/io/snabble/sdk/ui/scanner/ZXingBarcodeDetector.java @@ -74,7 +74,7 @@ public Barcode detect(byte[] data, int width, int height, int bitsPerPixel, Rect Barcode filtered = falsePositiveFilter.filter(barcode); if (filtered != null) { - Logger.d("Detected barcode: " + barcode.toString()); + Logger.d("Detected barcode: " + barcode); return filtered; } } diff --git a/ui/src/main/java/io/snabble/sdk/ui/search/SearchableProductAdapter.kt b/ui/src/main/java/io/snabble/sdk/ui/search/SearchableProductAdapter.kt index 7c2459446f..e1359ea233 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/search/SearchableProductAdapter.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/search/SearchableProductAdapter.kt @@ -16,8 +16,7 @@ import io.snabble.sdk.ui.utils.setOrHide import io.snabble.sdk.utils.Dispatch import io.snabble.sdk.utils.StringNormalizer -class SearchableProductAdapter : - RecyclerView.Adapter() { +class SearchableProductAdapter : RecyclerView.Adapter() { enum class SearchType { BARCODE, FOLDED_NAME } diff --git a/ui/src/main/java/io/snabble/sdk/ui/utils/SnackbarPushUpBehavior.java b/ui/src/main/java/io/snabble/sdk/ui/utils/SnackbarPushUpBehavior.java index 00686ddc06..06f70a8c2a 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/utils/SnackbarPushUpBehavior.java +++ b/ui/src/main/java/io/snabble/sdk/ui/utils/SnackbarPushUpBehavior.java @@ -4,6 +4,7 @@ import android.util.AttributeSet; import android.view.View; +import androidx.annotation.NonNull; import androidx.coordinatorlayout.widget.CoordinatorLayout; import com.google.android.material.snackbar.Snackbar; @@ -18,21 +19,21 @@ public SnackbarPushUpBehavior(Context context, AttributeSet attrs) { } @Override - public boolean layoutDependsOn(CoordinatorLayout parent, - View child, - View dependency) { + public boolean layoutDependsOn(@NonNull CoordinatorLayout parent, + @NonNull View child, + @NonNull View dependency) { return dependency instanceof Snackbar.SnackbarLayout; } @Override - public void onDependentViewRemoved(CoordinatorLayout parent, + public void onDependentViewRemoved(@NonNull CoordinatorLayout parent, View child, - View dependency) { + @NonNull View dependency) { child.setTranslationY(0); } @Override - public boolean onDependentViewChanged(CoordinatorLayout parent, + public boolean onDependentViewChanged(@NonNull CoordinatorLayout parent, View child, View dependency) { float translationY = Math.min(0, dependency.getTranslationY() - dependency.getHeight()); diff --git a/ui/src/main/java/io/snabble/sdk/ui/utils/SnackbarUtils.kt b/ui/src/main/java/io/snabble/sdk/ui/utils/SnackbarUtils.kt index 0be6a62121..7e0b5a2a5b 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/utils/SnackbarUtils.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/utils/SnackbarUtils.kt @@ -12,7 +12,7 @@ class SnackbarUtils { val snackbar: Snackbar = Snackbar.make(parentView, string, duration) ViewCompat.setFitsSystemWindows(snackbar.view, false) ViewCompat.setOnApplyWindowInsetsListener(snackbar.view, null) - return snackbar; + return snackbar } @JvmStatic @@ -20,7 +20,7 @@ class SnackbarUtils { val snackbar: Snackbar = Snackbar.make(parentView, resId, duration) ViewCompat.setFitsSystemWindows(snackbar.view, false) ViewCompat.setOnApplyWindowInsetsListener(snackbar.view, null) - return snackbar; + return snackbar } } } \ No newline at end of file diff --git a/ui/src/main/java/io/snabble/sdk/ui/utils/UIUtils.java b/ui/src/main/java/io/snabble/sdk/ui/utils/UIUtils.java index cd233ef904..660f87b8d8 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/utils/UIUtils.java +++ b/ui/src/main/java/io/snabble/sdk/ui/utils/UIUtils.java @@ -31,8 +31,6 @@ import eu.rekisoft.android.util.LazyWorker; import io.snabble.sdk.ui.R; -import kotlin.Unit; -import kotlin.jvm.functions.Function0; public class UIUtils { @RestrictTo(LIBRARY_GROUP) @@ -154,9 +152,9 @@ public void onAnimationCancel(Animator animation) { } public static final class TopDownInfoBoxController { - private final LazyWorker.Job hide; + private final LazyWorker.Job hide; - private TopDownInfoBoxController(LazyWorker.Job hideJob) { + private TopDownInfoBoxController(LazyWorker.Job hideJob) { hide = hideJob; } From 85d112d663695c0273be111c36d33bb553d6efe9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Kilczan?= Date: Fri, 18 Feb 2022 10:45:14 +0100 Subject: [PATCH 30/30] Ignore generated documentation --- docs/.gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/.gitignore diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000000..9e5bfb42d2 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1 @@ +api \ No newline at end of file